├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── TreeViewControl ├── IntegerToIndentationConverter.cpp ├── IntegerToIndentationConverter.h ├── TreeNode.cpp ├── TreeNode.h ├── TreeView.cpp ├── TreeView.h ├── TreeViewControl.vcxproj ├── TreeViewControl.vcxproj.filters ├── TreeViewItem.cpp ├── TreeViewItem.h ├── TreeViewItemAutomationPeer.cpp ├── TreeViewItemAutomationPeer.h ├── ViewModel.cpp ├── ViewModel.h ├── pch.cpp └── pch.h ├── VisualStudioShell.Controls ├── MenuFlyoutImageItem.cs ├── Properties │ ├── AssemblyInfo.cs │ └── VisualStudioShell.Controls.rd.xml ├── Themes │ └── Generic.xaml ├── VisualStudioShell.Controls.csproj └── project.json ├── VisualStudioShell.sln └── VisualStudioShell ├── App.xaml ├── App.xaml.cs ├── Assets ├── LockScreenLogo.scale-200.png ├── SplashScreen.scale-200.png ├── Square150x150Logo.scale-200.png ├── Square44x44Logo.altform-unplated_targetsize-16.png ├── Square44x44Logo.altform-unplated_targetsize-256.png ├── Square44x44Logo.altform-unplated_targetsize-32.png ├── Square44x44Logo.altform-unplated_targetsize-48.png ├── Square44x44Logo.scale-100.png ├── Square44x44Logo.scale-125.png ├── Square44x44Logo.scale-150.png ├── Square44x44Logo.scale-200.png ├── Square44x44Logo.scale-400.png ├── Square44x44Logo.targetsize-16.png ├── Square44x44Logo.targetsize-24.png ├── Square44x44Logo.targetsize-24_altform-unplated.png ├── Square44x44Logo.targetsize-256.png ├── Square44x44Logo.targetsize-32.png ├── Square44x44Logo.targetsize-48.png ├── StoreLogo.png └── Wide310x150Logo.scale-200.png ├── Controls ├── DiagnosticTools.xaml ├── DiagnosticTools.xaml.cs ├── LiveVisualTree.xaml ├── LiveVisualTree.xaml.cs ├── Notifications.xaml ├── Notifications.xaml.cs ├── SolutionExplorer.xaml ├── SolutionExplorer.xaml.cs ├── Toolbox.xaml ├── Toolbox.xaml.cs └── TreeNodeData.cs ├── Converter ├── BooleanToVisibilityConverter.cs └── GlyphConverter.cs ├── Images ├── Menu │ ├── CloseSolution.png │ ├── Debug.png │ ├── NewProject.png │ ├── NewWebsite.png │ ├── Save.png │ └── SaveAll.png ├── SolutionExplorer │ ├── FileCs.png │ ├── FileXaml.png │ ├── FileXamlCs.png │ ├── HeaderPinned.png │ ├── HeaderUnpinned.png │ ├── ProjectCSharp.png │ ├── References.png │ └── Solution.png ├── Titlebar │ ├── Feedback.png │ └── Notifications.png ├── VisualStudioIcon.png └── thomas.png ├── MainPage.xaml ├── MainPage.xaml.cs ├── Package.appxmanifest ├── Properties ├── AssemblyInfo.cs └── Default.rd.xml ├── Resources ├── Brushes.xaml ├── Button.xaml ├── MenuFlyoutSubItem.xaml ├── Pivot.xaml └── PivotHeaderItem.xaml ├── VisualStudioShell.csproj └── project.json /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Thomas Claudius Huber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Uwp-Visual-Studio-Shell 2 | Contains a little UWP-project that tries to immitate the Visual Studio Shell: 3 | 4 | Find more information in this blog-post: 5 | https://www.thomasclaudiushuber.com/2017/02/18/lessons-learned-from-building-a-visual-studio-shell-with-uwp/ 6 | -------------------------------------------------------------------------------- /TreeViewControl/IntegerToIndentationConverter.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "IntegerToIndentationConverter.h" 4 | 5 | using namespace Platform; 6 | using namespace Windows::UI::Xaml; 7 | using namespace Windows::UI::Xaml::Interop; 8 | 9 | namespace TreeViewControl { 10 | 11 | IntegerToIndentationConverter::IntegerToIndentationConverter() 12 | { 13 | //default 14 | indentMultiplier = 20; 15 | } 16 | 17 | Object^ IntegerToIndentationConverter::Convert(Object^ value, TypeName targetType, Object^ parameter, String^ language) 18 | { 19 | Thickness indent(0); 20 | if (value != nullptr) 21 | { 22 | indent.Left = (int)value * indentMultiplier; 23 | return indent; 24 | } 25 | 26 | return indent; 27 | } 28 | 29 | Object^ IntegerToIndentationConverter::ConvertBack(Object^ value, TypeName targetType, Object^ parameter, String^ language) 30 | { 31 | throw ref new NotImplementedException(); 32 | } 33 | } -------------------------------------------------------------------------------- /TreeViewControl/IntegerToIndentationConverter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace TreeViewControl { 4 | [Windows::Foundation::Metadata::WebHostHidden] 5 | public ref class IntegerToIndentationConverter sealed : Windows::UI::Xaml::Data::IValueConverter 6 | { 7 | public: 8 | property int IndentMultiplier 9 | { 10 | int get() { return indentMultiplier; }; 11 | void set(int i) { indentMultiplier = i; }; 12 | } 13 | 14 | IntegerToIndentationConverter(); 15 | 16 | virtual Platform::Object^ Convert(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object^ parameter, Platform::String^ language); 17 | 18 | virtual Platform::Object^ ConvertBack(Object^ value, Windows::UI::Xaml::Interop::TypeName targetType, Platform::Object^ parameter, Platform::String^ language); 19 | private: 20 | int indentMultiplier; 21 | }; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /TreeViewControl/TreeNode.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "TreeNode.h" 4 | 5 | using namespace Platform; 6 | using namespace Platform::Collections; 7 | using namespace Windows::UI::Xaml::Data; 8 | using namespace Windows::UI::Xaml::Interop; 9 | using namespace Windows::Foundation; 10 | using namespace Windows::Foundation::Collections; 11 | 12 | namespace TreeViewControl { 13 | 14 | TreeNode::TreeNode() 15 | { 16 | childrenVector->VectorChanged += ref new VectorChangedEventHandler(this, &TreeNode::ChildrenVectorChanged); 17 | } 18 | 19 | void TreeNode::Append(Object^ value) 20 | { 21 | int count = childrenVector->Size; 22 | TreeNode^ targetNode = (TreeNode^)value; 23 | targetNode->ParentNode = this; 24 | childrenVector->Append(targetNode); 25 | 26 | //If the count was 0 before we appended, then the HasItems property needs to change. 27 | if (count == 0) 28 | { 29 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems")); 30 | } 31 | 32 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size")); 33 | } 34 | 35 | void TreeNode::Clear() 36 | { 37 | int count = childrenVector->Size; 38 | TreeNode^ childNode; 39 | for (int i = 0; i < (int)Size; i++) 40 | { 41 | childNode = (TreeNode^)GetAt(i); 42 | childNode->ParentNode = nullptr; 43 | } 44 | 45 | childrenVector->Clear(); 46 | 47 | //If the count was not 0 before we cleared, then the HasItems property needs to change. 48 | if (count != 0) 49 | { 50 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems")); 51 | } 52 | 53 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size")); 54 | } 55 | 56 | IBindableIterator^ TreeNode::First() 57 | { 58 | return dynamic_cast(childrenVector->First()); 59 | } 60 | 61 | Object^ TreeNode::GetAt(unsigned int index) 62 | { 63 | if ((int)index > -1 && index < childrenVector->Size) 64 | { 65 | return childrenVector->GetAt(index); 66 | } 67 | 68 | return nullptr; 69 | } 70 | 71 | IBindableVectorView^ TreeNode::GetView() 72 | { 73 | return safe_cast(childrenVector->GetView()); 74 | } 75 | 76 | bool TreeNode::IndexOf(Object^ value, unsigned int* index) 77 | { 78 | return childrenVector->IndexOf((TreeNode^)value, index); 79 | } 80 | 81 | void TreeNode::InsertAt(unsigned int index, Object^ value) 82 | { 83 | if ((int)index > -1 && index <= childrenVector->Size) 84 | { 85 | int count = childrenVector->Size; 86 | TreeNode^ targetNode = (TreeNode^)value; 87 | targetNode->ParentNode = this; 88 | return childrenVector->InsertAt(index, (TreeNode^)value); 89 | 90 | //If the count was 0 before we insert, then the HasItems property needs to change. 91 | if (count == 0) 92 | { 93 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems")); 94 | } 95 | 96 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size")); 97 | } 98 | } 99 | 100 | void TreeNode::RemoveAt(unsigned int index) 101 | { 102 | if ((int)index > -1 && index < childrenVector->Size) 103 | { 104 | int count = childrenVector->Size; 105 | TreeNode^ targetNode = childrenVector->GetAt(index); 106 | targetNode->ParentNode = nullptr; 107 | childrenVector->RemoveAt(index); 108 | 109 | //If the count was 1 before we remove, then the HasItems property needs to change. 110 | if (count == 1) 111 | { 112 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems")); 113 | } 114 | 115 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size")); 116 | } 117 | } 118 | 119 | void TreeNode::RemoveAtEnd() 120 | { 121 | int count = childrenVector->Size; 122 | TreeNode^ targetNode = childrenVector->GetAt(childrenVector->Size - 1); 123 | targetNode->ParentNode = nullptr; 124 | childrenVector->RemoveAtEnd(); 125 | 126 | //If the count was 1 before we remove, then the HasItems property needs to change. 127 | if (count == 1) 128 | { 129 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("HasItems")); 130 | } 131 | 132 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Size")); 133 | } 134 | 135 | void TreeNode::SetAt(unsigned int index, Object^ value) 136 | { 137 | if ((int)index > -1 && index <= childrenVector->Size) 138 | { 139 | childrenVector->GetAt(index)->ParentNode = nullptr; 140 | TreeNode^ targetNode = (TreeNode^)value; 141 | targetNode->ParentNode = this; 142 | return childrenVector->SetAt(index, targetNode); 143 | } 144 | } 145 | 146 | void TreeNode::ChildrenVectorChanged(IObservableVector^ sender, IVectorChangedEventArgs^ e) 147 | { 148 | VectorChanged(this, e); 149 | } 150 | 151 | unsigned int TreeNode::Size::get() 152 | { 153 | return childrenVector->Size; 154 | } 155 | 156 | Object^ TreeNode::Data::get() 157 | { 158 | return data; 159 | } 160 | 161 | void TreeNode::Data::set(Object^ value) 162 | { 163 | data = value; 164 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Data")); 165 | } 166 | 167 | TreeNode^ TreeNode::ParentNode::get() 168 | { 169 | return parentNode; 170 | } 171 | 172 | void TreeNode::ParentNode::set(TreeNode^ value) 173 | { 174 | parentNode = value; 175 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("ParentNode")); 176 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("Depth")); 177 | } 178 | 179 | bool TreeNode::IsExpanded::get() 180 | { 181 | return isExpanded; 182 | } 183 | 184 | void TreeNode::IsExpanded::set(bool value) 185 | { 186 | isExpanded = value; 187 | this->PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs("IsExpanded")); 188 | } 189 | 190 | bool TreeNode::HasItems::get() 191 | { 192 | return (Size != 0); 193 | } 194 | 195 | int TreeNode::Depth::get() 196 | { 197 | TreeNode^ ancestorNode = this; 198 | int depth = -1; 199 | while ((ancestorNode->ParentNode) != nullptr) 200 | { 201 | depth++; 202 | ancestorNode = ancestorNode->ParentNode; 203 | } 204 | 205 | return depth; 206 | } 207 | 208 | } -------------------------------------------------------------------------------- /TreeViewControl/TreeNode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace TreeViewControl { 4 | /// 5 | /// The TreeNode class implements the hierarchical layout for the TreeView. 6 | /// It also holds the data that will be bound to in the item template. 7 | /// 8 | [Windows::UI::Xaml::Data::Bindable] 9 | [Windows::Foundation::Metadata::WebHostHidden] 10 | public ref class TreeNode sealed : Windows::UI::Xaml::Interop::IBindableObservableVector, Windows::UI::Xaml::Data::INotifyPropertyChanged 11 | { 12 | public: 13 | TreeNode(); 14 | 15 | virtual void Append(Object^ value); 16 | 17 | virtual void Clear(); 18 | 19 | virtual Windows::UI::Xaml::Interop::IBindableIterator^ First(); 20 | 21 | virtual Object^ GetAt(unsigned int index); 22 | 23 | virtual Windows::UI::Xaml::Interop::IBindableVectorView^ GetView(); 24 | 25 | virtual bool IndexOf(Object^ value, unsigned int* index); 26 | 27 | virtual void InsertAt(unsigned int index, Object^ value); 28 | 29 | virtual void RemoveAt(unsigned int index); 30 | 31 | virtual void RemoveAtEnd(); 32 | 33 | virtual void SetAt(unsigned int index, Object^ value); 34 | 35 | virtual event Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ VectorChanged 36 | { 37 | virtual Windows::Foundation::EventRegistrationToken add(Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ e) 38 | { 39 | return TreeNodeChanged += e; 40 | } 41 | 42 | virtual void remove(Windows::Foundation::EventRegistrationToken t) 43 | { 44 | TreeNodeChanged -= t; 45 | } 46 | 47 | internal: virtual void raise(Windows::UI::Xaml::Interop::IBindableObservableVector^ vector, Platform::Object^ e) 48 | { 49 | TreeNodeChanged(vector, e); 50 | } 51 | } 52 | 53 | virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged; 54 | 55 | virtual property unsigned int Size 56 | { 57 | unsigned int get(); 58 | } 59 | 60 | property Object^ Data 61 | { 62 | Object^ get(); 63 | void set(Object^ value); 64 | } 65 | 66 | property TreeNode^ ParentNode 67 | { 68 | TreeNode^ get(); 69 | void set(TreeNode^ value); 70 | } 71 | 72 | property bool IsExpanded 73 | { 74 | bool get(); 75 | void set(bool value); 76 | } 77 | 78 | property bool HasItems 79 | { 80 | bool get(); 81 | } 82 | 83 | //A lone TreeNode will have a depth of -1, this is to show that it is not appended 84 | //under the TreeView's invisible root node. Once added into the TreeView via 85 | //that method, the depth of the node will be calculated appropriately. 86 | property int Depth 87 | { 88 | int get(); 89 | } 90 | 91 | event Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ TreeNodeChanged; 92 | 93 | private: 94 | TreeNode^ parentNode = nullptr; 95 | Object^ data = nullptr; 96 | bool isExpanded = false; 97 | Platform::Collections::Vector^ childrenVector = ref new Platform::Collections::Vector(); 98 | void ChildrenVectorChanged(Windows::Foundation::Collections::IObservableVector^ sender, Windows::Foundation::Collections::IVectorChangedEventArgs^ e); 99 | }; 100 | } 101 | -------------------------------------------------------------------------------- /TreeViewControl/TreeView.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "TreeView.h" 4 | 5 | using namespace Windows::UI::Xaml; 6 | using namespace Windows::UI::Xaml::Interop; 7 | using namespace Windows::UI::Xaml::Controls; 8 | 9 | namespace TreeViewControl { 10 | 11 | TreeView::TreeView() 12 | { 13 | flatViewModel = ref new ViewModel; 14 | rootNode = ref new TreeNode(); 15 | 16 | flatViewModel->ExpandNode(rootNode); 17 | 18 | CanReorderItems = true; 19 | AllowDrop = true; 20 | CanDragItems = true; 21 | 22 | rootNode->VectorChanged += ref new BindableVectorChangedEventHandler(flatViewModel, &ViewModel::TreeNodeVectorChanged); 23 | ItemClick += ref new Windows::UI::Xaml::Controls::ItemClickEventHandler(this, &TreeView::TreeView_OnItemClick); 24 | DragItemsStarting += ref new Windows::UI::Xaml::Controls::DragItemsStartingEventHandler(this, &TreeView::TreeView_DragItemsStarting); 25 | DragItemsCompleted += ref new Windows::Foundation::TypedEventHandler(this, &TreeView::TreeView_DragItemsCompleted); 26 | ItemsSource = flatViewModel; 27 | } 28 | 29 | void TreeView::TreeView_OnItemClick(Platform::Object^ sender, Windows::UI::Xaml::Controls::ItemClickEventArgs^ args) 30 | { 31 | TreeViewItemClickEventArgs^ treeViewArgs = ref new TreeViewItemClickEventArgs(); 32 | treeViewArgs->ClickedItem = args->ClickedItem; 33 | 34 | TreeViewItemClick(this, treeViewArgs); 35 | 36 | if (!treeViewArgs->IsHandled) 37 | { 38 | TreeNode^ targetNode = (TreeNode^)args->ClickedItem; 39 | if (targetNode->IsExpanded) 40 | { 41 | flatViewModel->CollapseNode(targetNode); 42 | } 43 | else 44 | { 45 | flatViewModel->ExpandNode(targetNode); 46 | } 47 | } 48 | } 49 | 50 | void TreeView::TreeView_DragItemsStarting(Platform::Object^ sender, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs^ e) 51 | { 52 | draggedTreeViewItem = (TreeViewItem^)this->ContainerFromItem(e->Items->GetAt(0)); 53 | } 54 | 55 | void TreeView::TreeView_DragItemsCompleted(Windows::UI::Xaml::Controls::ListViewBase^ sender, Windows::UI::Xaml::Controls::DragItemsCompletedEventArgs^ args) 56 | { 57 | draggedTreeViewItem = nullptr; 58 | } 59 | 60 | void TreeView::OnDrop(Windows::UI::Xaml::DragEventArgs^ e) 61 | { 62 | if (e->AcceptedOperation == Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move) 63 | { 64 | Panel^ panel = this->ItemsPanelRoot; 65 | Windows::Foundation::Point point = e->GetPosition(panel); 66 | 67 | int aboveIndex = -1; 68 | int belowIndex = -1; 69 | unsigned int relativeIndex; 70 | 71 | IInsertionPanel^ insertionPanel = (IInsertionPanel^)panel; 72 | 73 | if (insertionPanel != nullptr) 74 | { 75 | insertionPanel->GetInsertionIndexes(point, &aboveIndex, &belowIndex); 76 | 77 | TreeNode^ aboveNode = (TreeNode^)flatViewModel->GetAt(aboveIndex); 78 | TreeNode^ belowNode = (TreeNode^)flatViewModel->GetAt(belowIndex); 79 | TreeNode^ targetNode = (TreeNode^)this->ItemFromContainer(draggedTreeViewItem); 80 | 81 | //Between two items 82 | if (aboveNode && belowNode) 83 | { 84 | targetNode->ParentNode->IndexOf(targetNode, &relativeIndex); 85 | targetNode->ParentNode->RemoveAt(relativeIndex); 86 | 87 | if (belowNode->ParentNode == aboveNode) 88 | { 89 | aboveNode->InsertAt(0, targetNode); 90 | } 91 | else 92 | { 93 | aboveNode->ParentNode->IndexOf(aboveNode, &relativeIndex); 94 | aboveNode->ParentNode->InsertAt(relativeIndex + 1, targetNode); 95 | } 96 | } 97 | //Bottom of the list 98 | else if (aboveNode && !belowNode) 99 | { 100 | targetNode->ParentNode->IndexOf(targetNode, &relativeIndex); 101 | targetNode->ParentNode->RemoveAt(relativeIndex); 102 | 103 | aboveNode->ParentNode->IndexOf(aboveNode, &relativeIndex); 104 | aboveNode->ParentNode->InsertAt(relativeIndex + 1, targetNode); 105 | } 106 | //Top of the list 107 | else if (!aboveNode && belowNode) 108 | { 109 | targetNode->ParentNode->IndexOf(targetNode, &relativeIndex); 110 | targetNode->ParentNode->RemoveAt(relativeIndex); 111 | 112 | rootNode->InsertAt(0, targetNode); 113 | } 114 | } 115 | } 116 | 117 | e->Handled = true; 118 | ListViewBase::OnDrop(e); 119 | } 120 | 121 | void TreeView::OnDragOver(Windows::UI::Xaml::DragEventArgs^ e) 122 | { 123 | Windows::ApplicationModel::DataTransfer::DataPackageOperation savedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None; 124 | 125 | e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None; 126 | 127 | Panel^ panel = this->ItemsPanelRoot; 128 | Windows::Foundation::Point point = e->GetPosition(panel); 129 | 130 | int aboveIndex = -1; 131 | int belowIndex = -1; 132 | 133 | IInsertionPanel^ insertionPanel = (IInsertionPanel^)panel; 134 | 135 | if (insertionPanel != nullptr) 136 | { 137 | insertionPanel->GetInsertionIndexes(point, &aboveIndex, &belowIndex); 138 | 139 | if (aboveIndex > -1) 140 | { 141 | TreeNode^ aboveNode = (TreeNode^)flatViewModel->GetAt(aboveIndex); 142 | TreeNode^ targetNode = (TreeNode^)this->ItemFromContainer(draggedTreeViewItem); 143 | 144 | TreeNode^ ancestorNode = aboveNode; 145 | while (ancestorNode != nullptr && ancestorNode != targetNode) 146 | { 147 | ancestorNode = ancestorNode->ParentNode; 148 | } 149 | 150 | if (ancestorNode == nullptr) 151 | { 152 | savedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move; 153 | e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move; 154 | } 155 | } 156 | else 157 | { 158 | savedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move; 159 | e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move; 160 | } 161 | } 162 | 163 | ListViewBase::OnDragOver(e); 164 | e->AcceptedOperation = savedOperation; 165 | } 166 | 167 | void TreeView::ExpandNode(TreeNode^ targetNode) 168 | { 169 | flatViewModel->ExpandNode(targetNode); 170 | } 171 | 172 | void TreeView::CollapseNode(TreeNode^ targetNode) 173 | { 174 | flatViewModel->CollapseNode(targetNode); 175 | } 176 | 177 | void TreeView::PrepareContainerForItemOverride(DependencyObject^ element, Object^ item) 178 | { 179 | ((UIElement^)element)->AllowDrop = true; 180 | 181 | ListView::PrepareContainerForItemOverride(element, item); 182 | } 183 | 184 | DependencyObject^ TreeView::GetContainerForItemOverride() 185 | { 186 | TreeViewItem^ targetItem = ref new TreeViewItem(); 187 | return (DependencyObject^)targetItem; 188 | } 189 | } -------------------------------------------------------------------------------- /TreeViewControl/TreeView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TreeNode.h" 3 | #include "ViewModel.h" 4 | #include "TreeViewItem.h" 5 | 6 | namespace TreeViewControl { 7 | public ref class TreeViewItemClickEventArgs sealed 8 | { 9 | public: 10 | TreeViewItemClickEventArgs() {} 11 | 12 | property Object^ ClickedItem 13 | { 14 | Object^ get() { return clickedItem; }; 15 | void set(Object^ value) { clickedItem = value; }; 16 | } 17 | 18 | property bool IsHandled 19 | { 20 | bool get() { return isHandled; }; 21 | void set(bool value) { isHandled = value; }; 22 | } 23 | private: 24 | Object^ clickedItem = nullptr; 25 | bool isHandled = false; 26 | }; 27 | 28 | ref class TreeView; 29 | [Windows::Foundation::Metadata::WebHostHidden] 30 | public delegate void TreeViewItemClickHandler(TreeView^ sender, TreeViewItemClickEventArgs^ args); 31 | 32 | [Windows::Foundation::Metadata::WebHostHidden] 33 | public ref class TreeView sealed : Windows::UI::Xaml::Controls::ListView 34 | { 35 | public: 36 | TreeView(); 37 | 38 | //This event is used to expose an alternative to itemclick to developers. 39 | event TreeViewItemClickHandler^ TreeViewItemClick; 40 | 41 | //This RootNode property is used by the TreeView to handle additions into the TreeView and 42 | //accurate VectorChange with multiple 'root level nodes'. This node will not be placed 43 | //in the flatViewModel, but has it's vectorchanged event hooked up to flatViewModel's 44 | //handler. 45 | property TreeNode^ RootNode 46 | { 47 | TreeNode^ get() { return rootNode; }; 48 | } 49 | 50 | void TreeView_OnItemClick(Platform::Object^ sender, Windows::UI::Xaml::Controls::ItemClickEventArgs^ args); 51 | 52 | void TreeView_DragItemsStarting(Platform::Object^ sender, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs^ e); 53 | 54 | void TreeView_DragItemsCompleted(Windows::UI::Xaml::Controls::ListViewBase^ sender, Windows::UI::Xaml::Controls::DragItemsCompletedEventArgs^ args); 55 | 56 | void ExpandNode(TreeNode^ targetNode); 57 | 58 | void CollapseNode(TreeNode^ targetNode); 59 | 60 | protected: 61 | void PrepareContainerForItemOverride(DependencyObject^ element, Object^ item) override; 62 | Windows::UI::Xaml::DependencyObject^ GetContainerForItemOverride() override; 63 | 64 | void OnDrop(Windows::UI::Xaml::DragEventArgs^ e) override; 65 | void OnDragOver(Windows::UI::Xaml::DragEventArgs^ e) override; 66 | 67 | private: 68 | TreeNode^ rootNode; 69 | ViewModel^ flatViewModel; 70 | 71 | internal: 72 | TreeViewItem^ draggedTreeViewItem; 73 | }; 74 | } 75 | 76 | -------------------------------------------------------------------------------- /TreeViewControl/TreeViewControl.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | {94560d69-a345-4e44-b897-eaa2b0e23238} 31 | WindowsRuntimeComponent 32 | TreeViewControl 33 | TreeViewControl 34 | en-US 35 | 14.0 36 | true 37 | Windows Store 38 | 10.0.14393.0 39 | 10.0.14393.0 40 | 10.0 41 | 42 | 43 | 44 | DynamicLibrary 45 | true 46 | v140 47 | 48 | 49 | DynamicLibrary 50 | true 51 | v140 52 | 53 | 54 | DynamicLibrary 55 | true 56 | v140 57 | 58 | 59 | DynamicLibrary 60 | false 61 | true 62 | v140 63 | 64 | 65 | DynamicLibrary 66 | false 67 | true 68 | v140 69 | 70 | 71 | DynamicLibrary 72 | false 73 | true 74 | v140 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | false 103 | 104 | 105 | false 106 | 107 | 108 | false 109 | 110 | 111 | false 112 | 113 | 114 | false 115 | 116 | 117 | false 118 | 119 | 120 | 121 | Use 122 | _WINRT_DLL;%(PreprocessorDefinitions) 123 | pch.h 124 | $(IntDir)pch.pch 125 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 126 | /bigobj %(AdditionalOptions) 127 | 28204 128 | 129 | 130 | Console 131 | false 132 | 133 | 134 | 135 | 136 | Use 137 | _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 138 | pch.h 139 | $(IntDir)pch.pch 140 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 141 | /bigobj %(AdditionalOptions) 142 | 28204 143 | 144 | 145 | Console 146 | false 147 | 148 | 149 | 150 | 151 | Use 152 | _WINRT_DLL;%(PreprocessorDefinitions) 153 | pch.h 154 | $(IntDir)pch.pch 155 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 156 | /bigobj %(AdditionalOptions) 157 | 28204 158 | 159 | 160 | Console 161 | false 162 | 163 | 164 | 165 | 166 | Use 167 | _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 168 | pch.h 169 | $(IntDir)pch.pch 170 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 171 | /bigobj %(AdditionalOptions) 172 | 28204 173 | 174 | 175 | Console 176 | false 177 | 178 | 179 | 180 | 181 | Use 182 | _WINRT_DLL;%(PreprocessorDefinitions) 183 | pch.h 184 | $(IntDir)pch.pch 185 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 186 | /bigobj %(AdditionalOptions) 187 | 28204 188 | 189 | 190 | Console 191 | false 192 | 193 | 194 | 195 | 196 | Use 197 | _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 198 | pch.h 199 | $(IntDir)pch.pch 200 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 201 | /bigobj %(AdditionalOptions) 202 | 28204 203 | 204 | 205 | Console 206 | false 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | Create 222 | Create 223 | Create 224 | Create 225 | Create 226 | Create 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /TreeViewControl/TreeViewControl.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 96c875b2-800f-42e2-aba6-ef897e02ec12 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /TreeViewControl/TreeViewItem.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "TreeViewItem.h" 4 | #include "TreeViewItemAutomationPeer.h" 5 | 6 | using namespace Windows::UI::Xaml; 7 | using namespace Platform; 8 | 9 | namespace TreeViewControl { 10 | TreeViewItem::TreeViewItem() 11 | { 12 | } 13 | 14 | TreeViewItem::~TreeViewItem() 15 | { 16 | } 17 | 18 | Windows::UI::Xaml::Controls::ListView^ TreeViewItem::GetAncestorListView(TreeViewItem^ targetItem) 19 | { 20 | DependencyObject^ TreeViewItemAncestor = (DependencyObject^)this; 21 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = nullptr; 22 | while (TreeViewItemAncestor != nullptr && ancestorListView == nullptr) 23 | { 24 | TreeViewItemAncestor = Windows::UI::Xaml::Media::VisualTreeHelper::GetParent(TreeViewItemAncestor); 25 | ancestorListView = dynamic_cast(TreeViewItemAncestor); 26 | } 27 | return ancestorListView; 28 | } 29 | 30 | void TreeViewItem::OnDrop(Windows::UI::Xaml::DragEventArgs^ e) 31 | { 32 | if (e->AcceptedOperation == Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move) 33 | { 34 | TreeViewItem^ droppedOnItem = (TreeViewItem^)this; 35 | 36 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetAncestorListView(droppedOnItem); 37 | 38 | if (ancestorListView) 39 | { 40 | TreeView^ ancestorTreeView = (TreeView^)ancestorListView; 41 | TreeViewItem^ droppedItem = ancestorTreeView->draggedTreeViewItem; 42 | TreeNode^ droppedNode = (TreeNode^)ancestorTreeView->ItemFromContainer(droppedItem); 43 | TreeNode^ droppedOnNode = (TreeNode^)ancestorTreeView->ItemFromContainer(droppedOnItem); 44 | 45 | //Remove the item that was dragged 46 | unsigned int removeIndex; 47 | droppedNode->ParentNode->IndexOf(droppedNode, &removeIndex); 48 | 49 | if (droppedNode != droppedOnNode) 50 | { 51 | droppedNode->ParentNode->RemoveAt(removeIndex); 52 | 53 | //Append the dragged dropped item as a child of the node it was dropped onto 54 | droppedOnNode->Append(droppedNode); 55 | 56 | //If not set to true then the Reorder code of listview wil override what is being done here. 57 | e->Handled = true; 58 | } 59 | else 60 | { 61 | e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None; 62 | } 63 | } 64 | } 65 | } 66 | 67 | void TreeViewItem::OnDragEnter(Windows::UI::Xaml::DragEventArgs^ e) 68 | { 69 | TreeViewItem^ draggedOverItem = (TreeViewItem^)this; 70 | 71 | e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None; 72 | 73 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetAncestorListView(draggedOverItem); 74 | 75 | if (ancestorListView) 76 | { 77 | TreeView^ ancestorTreeView = (TreeView^)ancestorListView; 78 | TreeViewItem^ draggedTreeViewItem = ancestorTreeView->draggedTreeViewItem; 79 | TreeNode^ draggedNode = (TreeNode^)ancestorTreeView->ItemFromContainer(draggedTreeViewItem); 80 | TreeNode^ draggedOverNode = (TreeNode^)ancestorTreeView->ItemFromContainer(draggedOverItem); 81 | TreeNode^ walkNode = draggedOverNode->ParentNode; 82 | 83 | while (walkNode != nullptr && walkNode != draggedNode) 84 | { 85 | walkNode = walkNode->ParentNode; 86 | } 87 | 88 | if (walkNode != draggedNode && draggedNode != draggedOverNode) 89 | { 90 | e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move; 91 | } 92 | } 93 | } 94 | 95 | void TreeViewItem::OnDragOver(Windows::UI::Xaml::DragEventArgs^ e) 96 | { 97 | e->DragUIOverride->IsGlyphVisible = true; 98 | e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::None; 99 | 100 | TreeViewItem^ draggedOverItem = (TreeViewItem^)this; 101 | 102 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetAncestorListView(draggedOverItem); 103 | if (ancestorListView) 104 | { 105 | TreeView^ ancestorTreeView = (TreeView^)ancestorListView; 106 | TreeViewItem^ draggedTreeViewItem = ancestorTreeView->draggedTreeViewItem; 107 | TreeNode^ draggedNode = (TreeNode^)ancestorTreeView->ItemFromContainer(draggedTreeViewItem); 108 | TreeNode^ draggedOverNode = (TreeNode^)ancestorTreeView->ItemFromContainer(draggedOverItem); 109 | TreeNode^ walkNode = draggedOverNode->ParentNode; 110 | 111 | while (walkNode != nullptr && walkNode != draggedNode) 112 | { 113 | walkNode = walkNode->ParentNode; 114 | } 115 | 116 | if (walkNode != draggedNode && draggedNode != draggedOverNode) 117 | { 118 | e->AcceptedOperation = Windows::ApplicationModel::DataTransfer::DataPackageOperation::Move; 119 | } 120 | } 121 | } 122 | 123 | Windows::UI::Xaml::Automation::Peers::AutomationPeer^ TreeViewItem::OnCreateAutomationPeer() 124 | { 125 | return ref new TreeViewItemAutomationPeer(this); 126 | } 127 | } -------------------------------------------------------------------------------- /TreeViewControl/TreeViewItem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace TreeViewControl { 4 | [Windows::Foundation::Metadata::WebHostHidden] 5 | [Windows::UI::Xaml::Data::Bindable] 6 | public ref class TreeViewItem sealed : Windows::UI::Xaml::Controls::ListViewItem 7 | { 8 | public: 9 | TreeViewItem(); 10 | 11 | virtual ~TreeViewItem(); 12 | 13 | private: 14 | Windows::UI::Xaml::Controls::ListView^ GetAncestorListView(TreeViewItem^ targetItem); 15 | 16 | protected: 17 | void OnDrop(Windows::UI::Xaml::DragEventArgs^ e) override; 18 | void OnDragEnter(Windows::UI::Xaml::DragEventArgs^ e) override; 19 | void OnDragOver(Windows::UI::Xaml::DragEventArgs^ e) override; 20 | Windows::UI::Xaml::Automation::Peers::AutomationPeer^ OnCreateAutomationPeer() override; 21 | }; 22 | } -------------------------------------------------------------------------------- /TreeViewControl/TreeViewItemAutomationPeer.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "TreeViewItemAutomationPeer.h" 4 | #include "TreeNode.h" 5 | 6 | using namespace Windows::UI::Xaml; 7 | using namespace Windows::UI::Xaml::Automation; 8 | using namespace Windows::UI::Xaml::Controls; 9 | using namespace Windows::UI::Xaml::Data; 10 | 11 | 12 | namespace TreeViewControl { 13 | //IExpandCollapseProvider 14 | Windows::UI::Xaml::Automation::ExpandCollapseState TreeViewItemAutomationPeer::ExpandCollapseState::get() 15 | { 16 | Windows::UI::Xaml::Automation::ExpandCollapseState currentState = Windows::UI::Xaml::Automation::ExpandCollapseState::Collapsed; 17 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner); 18 | 19 | TreeNode^ targetNode; 20 | TreeNode^ targetParentNode; 21 | 22 | if (ancestorListView) 23 | { 24 | TreeView^ ancestorTreeView = (TreeView^)ancestorListView; 25 | targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner); 26 | 27 | if (Owner->AllowDrop) 28 | { 29 | if (targetNode->IsExpanded) 30 | { 31 | currentState = Windows::UI::Xaml::Automation::ExpandCollapseState::Expanded; 32 | } 33 | else 34 | { 35 | currentState = Windows::UI::Xaml::Automation::ExpandCollapseState::Collapsed; 36 | } 37 | } 38 | else 39 | { 40 | currentState = Windows::UI::Xaml::Automation::ExpandCollapseState::LeafNode; 41 | } 42 | } 43 | 44 | return currentState; 45 | } 46 | 47 | void TreeViewItemAutomationPeer::Collapse() 48 | { 49 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner); 50 | 51 | if (ancestorListView) 52 | { 53 | TreeView^ ancestorTreeView = (TreeView^)ancestorListView; 54 | TreeNode^ targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner); 55 | ancestorTreeView->CollapseNode(targetNode); 56 | RaiseExpandCollapseAutomationEvent(Windows::UI::Xaml::Automation::ExpandCollapseState::Collapsed); 57 | } 58 | } 59 | 60 | void TreeViewItemAutomationPeer::Expand() 61 | { 62 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner); 63 | 64 | if (ancestorListView) 65 | { 66 | TreeView^ ancestorTreeView = (TreeView^)ancestorListView; 67 | TreeNode^ targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner); 68 | ancestorTreeView->ExpandNode(targetNode); 69 | RaiseExpandCollapseAutomationEvent(Windows::UI::Xaml::Automation::ExpandCollapseState::Expanded); 70 | } 71 | } 72 | 73 | void TreeViewItemAutomationPeer::RaiseExpandCollapseAutomationEvent(Windows::UI::Xaml::Automation::ExpandCollapseState newState) 74 | { 75 | Windows::UI::Xaml::Automation::ExpandCollapseState oldState; 76 | 77 | if (newState == Windows::UI::Xaml::Automation::ExpandCollapseState::Expanded) 78 | { 79 | oldState = Windows::UI::Xaml::Automation::ExpandCollapseState::Collapsed; 80 | } 81 | else 82 | { 83 | oldState = Windows::UI::Xaml::Automation::ExpandCollapseState::Expanded; 84 | } 85 | 86 | RaisePropertyChangedEvent(ExpandCollapsePatternIdentifiers::ExpandCollapseStateProperty, oldState, newState); 87 | } 88 | 89 | //Position override 90 | 91 | //These methods are being overridden so that the TreeView under narrator reads out 92 | //the position of an item as compared to it's children, not it's overall position 93 | //in the listview. I've included an override for level as well, to give context on 94 | //how deep in the tree an item is. 95 | int TreeViewItemAutomationPeer::GetSizeOfSetCore() 96 | { 97 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner); 98 | 99 | TreeNode^ targetNode; 100 | TreeNode^ targetParentNode; 101 | 102 | int setSize = 0; 103 | 104 | if (ancestorListView) 105 | { 106 | TreeView^ ancestorTreeView = (TreeView^)ancestorListView; 107 | targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner); 108 | targetParentNode = targetNode->ParentNode; 109 | setSize = targetParentNode->Size; 110 | } 111 | 112 | return setSize; 113 | } 114 | 115 | int TreeViewItemAutomationPeer::GetPositionInSetCore() 116 | { 117 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner); 118 | 119 | TreeNode^ targetNode; 120 | TreeNode^ targetParentNode; 121 | 122 | int positionInSet = 0; 123 | 124 | if (ancestorListView) 125 | { 126 | TreeView^ ancestorTreeView = (TreeView^)ancestorListView; 127 | targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner); 128 | unsigned int positionInt; 129 | targetParentNode = targetNode->ParentNode; 130 | targetParentNode->IndexOf(targetNode, &positionInt); 131 | positionInSet = (int)positionInt + 1; 132 | } 133 | 134 | return positionInSet; 135 | } 136 | 137 | int TreeViewItemAutomationPeer::GetLevelCore() 138 | { 139 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = GetParentListView((DependencyObject^)Owner); 140 | 141 | TreeNode^ targetNode; 142 | TreeNode^ targetParentNode; 143 | 144 | int levelValue = 0; 145 | 146 | if (ancestorListView) 147 | { 148 | TreeView^ ancestorTreeView = (TreeView^)ancestorListView; 149 | targetNode = (TreeNode^)ancestorTreeView->ItemFromContainer((TreeViewItem^)Owner); 150 | levelValue = targetNode->Depth + 1; 151 | } 152 | 153 | return levelValue; 154 | } 155 | 156 | Platform::Object^ TreeViewItemAutomationPeer::GetPatternCore(Windows::UI::Xaml::Automation::Peers::PatternInterface patternInterface) 157 | { 158 | if (patternInterface == Windows::UI::Xaml::Automation::Peers::PatternInterface::ExpandCollapse) 159 | { 160 | return this; 161 | } 162 | 163 | return ListViewItemAutomationPeer::GetPatternCore(patternInterface); 164 | } 165 | 166 | Windows::UI::Xaml::Controls::ListView^ TreeViewItemAutomationPeer::GetParentListView(DependencyObject^ Owner) 167 | { 168 | DependencyObject^ treeViewItemAncestor = Owner; 169 | Windows::UI::Xaml::Controls::ListView^ ancestorListView = nullptr; 170 | while (treeViewItemAncestor != nullptr && ancestorListView == nullptr) 171 | { 172 | treeViewItemAncestor = Windows::UI::Xaml::Media::VisualTreeHelper::GetParent(treeViewItemAncestor); 173 | ancestorListView = dynamic_cast(treeViewItemAncestor); 174 | } 175 | 176 | return ancestorListView; 177 | } 178 | } -------------------------------------------------------------------------------- /TreeViewControl/TreeViewItemAutomationPeer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TreeViewItem.h" 3 | #include "TreeView.h" 4 | 5 | namespace TreeViewControl { 6 | [Windows::Foundation::Metadata::WebHostHidden] 7 | public ref class TreeViewItemAutomationPeer : Windows::UI::Xaml::Automation::Peers::ListViewItemAutomationPeer, Windows::UI::Xaml::Automation::Provider::IExpandCollapseProvider 8 | { 9 | internal: 10 | TreeViewItemAutomationPeer(TreeViewItem^ owner) :Windows::UI::Xaml::Automation::Peers::ListViewItemAutomationPeer(owner) {}; 11 | 12 | public: 13 | //IExpandCollapseProvider 14 | virtual void Collapse(); 15 | 16 | virtual void Expand(); 17 | 18 | property Windows::UI::Xaml::Automation::ExpandCollapseState ExpandCollapseState 19 | { 20 | virtual Windows::UI::Xaml::Automation::ExpandCollapseState get(); 21 | } 22 | 23 | void RaiseExpandCollapseAutomationEvent(Windows::UI::Xaml::Automation::ExpandCollapseState newState); 24 | 25 | //Position override 26 | int GetSizeOfSetCore() override; 27 | 28 | int GetPositionInSetCore() override; 29 | 30 | int GetLevelCore() override; 31 | 32 | protected: 33 | Platform::Object^ GetPatternCore(Windows::UI::Xaml::Automation::Peers::PatternInterface patternInterface) override; 34 | 35 | private: 36 | Windows::UI::Xaml::Controls::ListView^ GetParentListView(DependencyObject^ Owner); 37 | }; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /TreeViewControl/ViewModel.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "ViewModel.h" 4 | 5 | using namespace Platform; 6 | using namespace Windows::Foundation::Collections; 7 | using namespace Windows::UI::Xaml::Interop; 8 | using namespace Windows::UI::Xaml::Data; 9 | 10 | namespace TreeViewControl { 11 | ViewModel::ViewModel() 12 | { 13 | flatVectorRealizedItems->VectorChanged += ref new VectorChangedEventHandler(this, &ViewModel::UpdateTreeView); 14 | } 15 | 16 | void ViewModel::Append(Object^ value) 17 | { 18 | TreeNode^ targetNode = (TreeNode^)value; 19 | flatVectorRealizedItems->Append(targetNode); 20 | 21 | collectionChangedEventTokenVector.push_back(targetNode->VectorChanged += ref new BindableVectorChangedEventHandler(this, &ViewModel::TreeNodeVectorChanged)); 22 | propertyChangedEventTokenVector.push_back(targetNode->PropertyChanged += ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &ViewModel::TreeNodePropertyChanged)); 23 | } 24 | 25 | void ViewModel::Clear() 26 | { 27 | 28 | while (flatVectorRealizedItems->Size != 0) 29 | { 30 | RemoveAtEnd(); 31 | } 32 | } 33 | 34 | IBindableIterator^ ViewModel::First() 35 | { 36 | return dynamic_cast(flatVectorRealizedItems->First()); 37 | } 38 | 39 | Object^ ViewModel::GetAt(unsigned int index) 40 | { 41 | if ((int)index > -1 && (int)index < flatVectorRealizedItems->Size) 42 | { 43 | return flatVectorRealizedItems->GetAt(index); 44 | } 45 | 46 | return nullptr; 47 | } 48 | 49 | IBindableVectorView^ ViewModel::GetView() 50 | { 51 | return safe_cast(flatVectorRealizedItems->GetView()); 52 | } 53 | 54 | bool ViewModel::IndexOf(Object^ value, unsigned int* index) 55 | { 56 | return flatVectorRealizedItems->IndexOf((TreeNode^)value, index); 57 | } 58 | 59 | void ViewModel::InsertAt(unsigned int index, Object^ value) 60 | { 61 | if ((int)index > -1 && (int)index <= flatVectorRealizedItems->Size) 62 | { 63 | TreeNode^ targetNode = (TreeNode^)value; 64 | flatVectorRealizedItems->InsertAt(index, targetNode); 65 | 66 | auto eventIndex = collectionChangedEventTokenVector.begin() + index; 67 | collectionChangedEventTokenVector.insert(eventIndex, targetNode->VectorChanged += ref new BindableVectorChangedEventHandler(this, &ViewModel::TreeNodeVectorChanged)); 68 | 69 | eventIndex = propertyChangedEventTokenVector.begin() + index; 70 | propertyChangedEventTokenVector.insert(eventIndex,targetNode->PropertyChanged += ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &ViewModel::TreeNodePropertyChanged)); 71 | } 72 | } 73 | 74 | void ViewModel::RemoveAt(unsigned int index) 75 | { 76 | if ((int)index > -1 && (int)index < flatVectorRealizedItems->Size) 77 | { 78 | TreeNode^ targetNode = flatVectorRealizedItems->GetAt(index); 79 | flatVectorRealizedItems->RemoveAt(index); 80 | 81 | auto eventIndex = collectionChangedEventTokenVector.begin() + index; 82 | targetNode->VectorChanged -= collectionChangedEventTokenVector[index]; 83 | collectionChangedEventTokenVector.erase(eventIndex); 84 | 85 | eventIndex = propertyChangedEventTokenVector.begin() + index; 86 | targetNode->PropertyChanged -= propertyChangedEventTokenVector[index]; 87 | propertyChangedEventTokenVector.erase(eventIndex); 88 | } 89 | } 90 | 91 | void ViewModel::RemoveAtEnd() 92 | { 93 | int index = flatVectorRealizedItems->Size - 1; 94 | if (index >= 0) 95 | { 96 | TreeNode^ targetNode = flatVectorRealizedItems->GetAt(index); 97 | flatVectorRealizedItems->RemoveAt(index); 98 | 99 | auto eventIndex = collectionChangedEventTokenVector.begin() + index; 100 | targetNode->VectorChanged -= collectionChangedEventTokenVector[index]; 101 | collectionChangedEventTokenVector.erase(eventIndex); 102 | 103 | eventIndex = propertyChangedEventTokenVector.begin() + index; 104 | targetNode->PropertyChanged -= propertyChangedEventTokenVector[index]; 105 | propertyChangedEventTokenVector.erase(eventIndex); 106 | } 107 | } 108 | 109 | void ViewModel::SetAt(unsigned int index, Object^ value) 110 | { 111 | if ((int)index > -1 && (int)index < flatVectorRealizedItems->Size) 112 | { 113 | TreeNode^ targetNode = (TreeNode^)value; 114 | TreeNode^ removeNode = flatVectorRealizedItems->GetAt(index); 115 | flatVectorRealizedItems->SetAt(index, targetNode); 116 | 117 | auto eventIndex = collectionChangedEventTokenVector.begin() + index; 118 | removeNode->VectorChanged -= collectionChangedEventTokenVector[index]; 119 | collectionChangedEventTokenVector.erase(eventIndex); 120 | collectionChangedEventTokenVector.insert(eventIndex, targetNode->VectorChanged += ref new BindableVectorChangedEventHandler(this, &ViewModel::TreeNodeVectorChanged)); 121 | 122 | eventIndex = propertyChangedEventTokenVector.begin() + index; 123 | targetNode->PropertyChanged -= propertyChangedEventTokenVector[index]; 124 | propertyChangedEventTokenVector.erase(eventIndex); 125 | propertyChangedEventTokenVector.insert(eventIndex, targetNode->PropertyChanged += ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &ViewModel::TreeNodePropertyChanged)); 126 | } 127 | } 128 | 129 | void ViewModel::ExpandNode(TreeNode^ targetNode) 130 | { 131 | if (!targetNode->IsExpanded) 132 | { 133 | targetNode->IsExpanded = true; 134 | } 135 | } 136 | 137 | void ViewModel::CollapseNode(TreeNode^ targetNode) 138 | { 139 | if (targetNode->IsExpanded) 140 | { 141 | targetNode->IsExpanded = false; 142 | } 143 | } 144 | 145 | void ViewModel::AddNodeToView(TreeNode^ targetNode, int index) 146 | { 147 | InsertAt(index, targetNode); 148 | } 149 | 150 | int ViewModel::AddNodeDescendantsToView(TreeNode^ targetNode, int index, int offset) 151 | { 152 | if (targetNode->IsExpanded) 153 | { 154 | TreeNode^ childNode; 155 | for (int i = 0; i < (int)targetNode->Size; i++) 156 | { 157 | childNode = (TreeNode^)targetNode->GetAt(i); 158 | offset++; 159 | AddNodeToView(childNode, index + offset); 160 | offset = AddNodeDescendantsToView(childNode, index, offset); 161 | } 162 | 163 | return offset; 164 | } 165 | 166 | return offset; 167 | } 168 | 169 | void ViewModel::RemoveNodeAndDescendantsFromView(TreeNode^ targetNode) 170 | { 171 | if (targetNode->IsExpanded) 172 | { 173 | TreeNode^ childNode; 174 | for (int i = 0; i < (int)targetNode->Size; i++) 175 | { 176 | childNode = (TreeNode^)targetNode->GetAt(i); 177 | RemoveNodeAndDescendantsFromView(childNode); 178 | } 179 | } 180 | 181 | int index = IndexOf(targetNode); 182 | RemoveAt(index); 183 | } 184 | 185 | int ViewModel::CountDescendants(TreeNode^ targetNode) 186 | { 187 | int descendantCount = 0; 188 | TreeNode^ childNode; 189 | for (int i = 0; i < (int)targetNode->Size; i++) 190 | { 191 | childNode = (TreeNode^)targetNode->GetAt(i); 192 | descendantCount++; 193 | if (childNode->IsExpanded) 194 | { 195 | descendantCount = descendantCount + CountDescendants(childNode); 196 | } 197 | } 198 | 199 | return descendantCount; 200 | } 201 | 202 | int ViewModel::IndexOf(TreeNode^ targetNode) 203 | { 204 | unsigned int index; 205 | bool isIndexed = IndexOf(targetNode, &index); 206 | if (isIndexed) 207 | { 208 | return (int)index; 209 | } 210 | else 211 | { 212 | return -1; 213 | } 214 | } 215 | 216 | void ViewModel::UpdateTreeView(IObservableVector^ sender, IVectorChangedEventArgs^ e) 217 | { 218 | VectorChanged(this, e); 219 | } 220 | 221 | void ViewModel::TreeNodeVectorChanged(IBindableObservableVector^ sender, Platform::Object^ e) 222 | { 223 | CollectionChange CC = ((IVectorChangedEventArgs^)e)->CollectionChange; 224 | switch (CC) 225 | { 226 | //Reset case, commonly seen when a TreeNode is cleared. 227 | //removes all nodes that need removing then 228 | //toggles a collapse / expand to ensure order. 229 | case (CollectionChange::Reset) : 230 | { 231 | TreeNode^ resetNode = (TreeNode^)sender; 232 | int resetIndex = IndexOf(resetNode); 233 | if (resetIndex != Size - 1 && resetNode->IsExpanded) 234 | { 235 | TreeNode^ childNode = resetNode; 236 | TreeNode^ parentNode = resetNode->ParentNode; 237 | int stopIndex; 238 | bool isLastRelativeChild = true; 239 | while (parentNode != nullptr && isLastRelativeChild) 240 | { 241 | unsigned int relativeIndex; 242 | parentNode->IndexOf(childNode, &relativeIndex); 243 | if (parentNode->Size - 1 != relativeIndex) 244 | { 245 | isLastRelativeChild = false; 246 | } 247 | else 248 | { 249 | childNode = parentNode; 250 | parentNode = parentNode->ParentNode; 251 | } 252 | } 253 | 254 | if (parentNode != nullptr) 255 | { 256 | unsigned int siblingIndex; 257 | parentNode->IndexOf(childNode, &siblingIndex); 258 | TreeNode^ siblingNode = (TreeNode^)parentNode->GetAt(siblingIndex + 1); 259 | stopIndex = IndexOf(siblingNode); 260 | } 261 | else 262 | { 263 | stopIndex = Size; 264 | } 265 | 266 | for (int i = stopIndex - 1; i > resetIndex; i--) 267 | { 268 | if ((flatVectorRealizedItems->GetAt(i))->ParentNode == nullptr) 269 | { 270 | RemoveNodeAndDescendantsFromView(flatVectorRealizedItems->GetAt(i)); 271 | } 272 | } 273 | 274 | if (resetNode->IsExpanded) 275 | { 276 | CollapseNode(resetNode); 277 | ExpandNode(resetNode); 278 | } 279 | } 280 | 281 | break; 282 | } 283 | 284 | //Inserts the TreeNode into the correct index of the ViewModel 285 | case (CollectionChange::ItemInserted) : 286 | { 287 | //We will find the correct index of insertion by first checking if the 288 | //node we are inserting into is expanded. If it is we will start walking 289 | //down the tree and counting the open items. This is to ensure we place 290 | //the inserted item in the correct index. If along the way we bump into 291 | //the item being inserted, we insert there then return, because we don't 292 | //need to do anything further. 293 | unsigned int index = ((IVectorChangedEventArgs^)e)->Index; 294 | TreeNode^ targetNode = (TreeNode^)sender->GetAt(index); 295 | TreeNode^ parentNode = targetNode->ParentNode; 296 | TreeNode^ childNode; 297 | int parentIndex = IndexOf(parentNode); 298 | int allOpenedDescendantsCount = 0; 299 | if (parentNode->IsExpanded) 300 | { 301 | for (int i = 0; i < (int)parentNode->Size; i++) 302 | { 303 | childNode = (TreeNode^)parentNode->GetAt(i); 304 | if (childNode == targetNode) 305 | { 306 | AddNodeToView(targetNode, (parentIndex + i + 1 + allOpenedDescendantsCount)); 307 | if (targetNode->IsExpanded) 308 | { 309 | AddNodeDescendantsToView(targetNode, parentIndex + i + 1, allOpenedDescendantsCount); 310 | } 311 | 312 | return; 313 | } 314 | 315 | if (childNode->IsExpanded) 316 | { 317 | allOpenedDescendantsCount += CountDescendants(childNode); 318 | } 319 | } 320 | 321 | AddNodeToView(targetNode, (parentIndex + parentNode->Size + allOpenedDescendantsCount)); 322 | if (targetNode->IsExpanded) 323 | { 324 | AddNodeDescendantsToView(targetNode, parentIndex + parentNode->Size, allOpenedDescendantsCount); 325 | } 326 | } 327 | 328 | break; 329 | } 330 | 331 | //Removes a node from the ViewModel when a TreeNode 332 | //removes a child. 333 | case (CollectionChange::ItemRemoved) : 334 | { 335 | TreeNode^ removeNode = (TreeNode^)sender; 336 | int removeIndex = IndexOf(removeNode); 337 | 338 | if (removeIndex != Size - 1 && removeNode->IsExpanded) 339 | { 340 | TreeNode^ childNode = removeNode; 341 | TreeNode^ parentNode = removeNode->ParentNode; 342 | int stopIndex; 343 | bool isLastRelativeChild = true; 344 | while (parentNode != nullptr && isLastRelativeChild) 345 | { 346 | unsigned int relativeIndex; 347 | parentNode->IndexOf(childNode, &relativeIndex); 348 | if (parentNode->Size - 1 != relativeIndex) 349 | { 350 | isLastRelativeChild = false; 351 | } 352 | else 353 | { 354 | childNode = parentNode; 355 | parentNode = parentNode->ParentNode; 356 | } 357 | } 358 | 359 | if (parentNode != nullptr) 360 | { 361 | unsigned int siblingIndex; 362 | parentNode->IndexOf(childNode, &siblingIndex); 363 | TreeNode^ siblingNode = (TreeNode^)parentNode->GetAt(siblingIndex + 1); 364 | stopIndex = IndexOf(siblingNode); 365 | } 366 | else 367 | { 368 | stopIndex = Size; 369 | } 370 | 371 | for (int i = stopIndex - 1; i > removeIndex; i--) 372 | { 373 | if ((flatVectorRealizedItems->GetAt(i))->ParentNode == nullptr) 374 | { 375 | RemoveNodeAndDescendantsFromView(flatVectorRealizedItems->GetAt(i)); 376 | } 377 | } 378 | } 379 | 380 | break; 381 | } 382 | 383 | //Triggered by a replace such as SetAt. 384 | //Updates the TreeNode that changed in the ViewModel. 385 | case (CollectionChange::ItemChanged) : 386 | { 387 | unsigned int index = ((IVectorChangedEventArgs^)e)->Index; 388 | TreeNode^ targetNode = (TreeNode^)sender->GetAt(index); 389 | TreeNode^ parentNode = targetNode->ParentNode; 390 | TreeNode^ childNode; 391 | int allOpenedDescendantsCount = 0; 392 | int parentIndex = IndexOf(parentNode); 393 | 394 | for (int i = 0; i < (int)parentNode->Size; i++) 395 | { 396 | childNode = (TreeNode^)parentNode->GetAt(i); 397 | if (childNode->IsExpanded) 398 | { 399 | allOpenedDescendantsCount += CountDescendants(childNode); 400 | } 401 | } 402 | 403 | TreeNode^ removeNode = (TreeNode^)GetAt(parentIndex + index + allOpenedDescendantsCount + 1); 404 | if (removeNode->IsExpanded) 405 | { 406 | CollapseNode(removeNode); 407 | } 408 | 409 | RemoveAt(parentIndex + index + allOpenedDescendantsCount + 1); 410 | InsertAt(parentIndex + index + allOpenedDescendantsCount + 1, targetNode); 411 | 412 | break; 413 | } 414 | 415 | } 416 | } 417 | 418 | void ViewModel::TreeNodePropertyChanged(Object^ sender, PropertyChangedEventArgs^ e) 419 | { 420 | if (e->PropertyName == "IsExpanded") 421 | { 422 | TreeNode^ targetNode = (TreeNode^)sender; 423 | if (targetNode->IsExpanded) 424 | { 425 | if (targetNode->Size != 0) 426 | { 427 | int openedDescendantOffset = 0; 428 | int index = IndexOf(targetNode); 429 | index = index + 1; 430 | TreeNode^ childNode; 431 | for (int i = 0; i < (int)targetNode->Size; i++) 432 | { 433 | childNode = (TreeNode^)targetNode->GetAt(i); 434 | AddNodeToView(childNode, ((int)index + i + openedDescendantOffset)); 435 | openedDescendantOffset = AddNodeDescendantsToView(childNode, (index + i), openedDescendantOffset); 436 | } 437 | } 438 | } 439 | else 440 | { 441 | TreeNode^ childNode; 442 | for (int i = 0; i < (int)targetNode->Size; i++) 443 | { 444 | childNode = (TreeNode^)targetNode->GetAt(i); 445 | RemoveNodeAndDescendantsFromView(childNode); 446 | } 447 | } 448 | } 449 | } 450 | } -------------------------------------------------------------------------------- /TreeViewControl/ViewModel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TreeNode.h" 3 | 4 | namespace TreeViewControl { 5 | /// 6 | /// The ViewModel is responsible for flattening the heirarchical data into a flat list. 7 | /// It also tracks changes to the underlying data and updates the flat list accordingly. 8 | /// 9 | [Windows::Foundation::Metadata::WebHostHidden] 10 | ref class ViewModel sealed : Windows::UI::Xaml::Interop::IBindableObservableVector 11 | { 12 | internal: 13 | ViewModel(); 14 | 15 | public: 16 | /// 17 | /// Add root to the view model. In other cases the app should not 18 | /// use this api. 19 | /// 20 | virtual void Append(Object^ value); 21 | 22 | virtual void Clear(); 23 | 24 | virtual Windows::UI::Xaml::Interop::IBindableIterator^ First(); 25 | 26 | virtual Object^ GetAt(unsigned int index); 27 | 28 | virtual Windows::UI::Xaml::Interop::IBindableVectorView^ GetView(); 29 | 30 | virtual bool IndexOf(Object^ value, unsigned int* index); 31 | 32 | virtual void InsertAt(unsigned int index, Object^ value); 33 | 34 | virtual void RemoveAt(unsigned int index); 35 | 36 | virtual void RemoveAtEnd(); 37 | 38 | virtual void SetAt(unsigned int index, Object^ value); 39 | 40 | virtual property unsigned int Size 41 | { 42 | unsigned int get() { return flatVectorRealizedItems->Size; }; 43 | }; 44 | 45 | virtual event Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ VectorChanged 46 | { 47 | virtual Windows::Foundation::EventRegistrationToken add(Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ args) 48 | { 49 | return ViewModelChanged += args; 50 | } 51 | 52 | virtual void remove(Windows::Foundation::EventRegistrationToken token) 53 | { 54 | return ViewModelChanged -= token; 55 | } 56 | 57 | virtual void raise(Windows::UI::Xaml::Interop::IBindableObservableVector^ vector, Platform::Object^ e) 58 | { 59 | ViewModelChanged(vector, e); 60 | } 61 | } 62 | 63 | /// 64 | /// ExpandNode adds the children and all open descendants of the targetNode 65 | /// to the ViewModel in their correct flattened index. 66 | /// 67 | void ExpandNode(TreeNode^ targetNode); 68 | 69 | /// 70 | /// Collapse node removes all the descendants of the targetNode from the ViewModel. 71 | /// 72 | void CollapseNode(TreeNode^ targetNode); 73 | 74 | /// 75 | /// This is the collection changed handler for individual TreeNodes. The collection changes 76 | /// from the hierarchical TreeNodes need to be flattened so that we can keep our current 77 | /// flat list in sync. 78 | /// 79 | /// TreeNode that has already been changed 80 | void TreeNodeVectorChanged(Windows::UI::Xaml::Interop::IBindableObservableVector^ sender, Platform::Object^ e); 81 | 82 | void TreeNodePropertyChanged(Object^ sender, Windows::UI::Xaml::Data::PropertyChangedEventArgs^ e); 83 | 84 | private: 85 | event Windows::UI::Xaml::Interop::BindableVectorChangedEventHandler^ ViewModelChanged; 86 | 87 | Platform::Collections::Vector^ flatVectorRealizedItems = ref new Platform::Collections::Vector(); 88 | 89 | std::vector collectionChangedEventTokenVector; 90 | 91 | std::vector propertyChangedEventTokenVector; 92 | 93 | void AddNodeToView(TreeNode^ targetNode, int index); 94 | 95 | int AddNodeDescendantsToView(TreeNode^ targetNode, int start, int offset); 96 | 97 | void RemoveNodeAndDescendantsFromView(TreeNode^ targetNode); 98 | 99 | int CountDescendants(TreeNode^ targetNode); 100 | 101 | int IndexOf(TreeNode^ targetNode); 102 | 103 | void UpdateTreeView(Windows::Foundation::Collections::IObservableVector^ sender, Windows::Foundation::Collections::IVectorChangedEventArgs^ e); 104 | }; 105 | } -------------------------------------------------------------------------------- /TreeViewControl/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | -------------------------------------------------------------------------------- /TreeViewControl/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include -------------------------------------------------------------------------------- /VisualStudioShell.Controls/MenuFlyoutImageItem.cs: -------------------------------------------------------------------------------- 1 | using Windows.UI.Xaml; 2 | using Windows.UI.Xaml.Controls; 3 | using Windows.UI.Xaml.Media; 4 | 5 | namespace VisualStudioShell.Controls 6 | { 7 | public sealed class MenuFlyoutImageItem : MenuFlyoutItem 8 | { 9 | public MenuFlyoutImageItem() 10 | { 11 | this.DefaultStyleKey = typeof(MenuFlyoutImageItem); 12 | } 13 | 14 | public ImageSource Icon 15 | { 16 | get { return (ImageSource)GetValue(IconProperty); } 17 | set { SetValue(IconProperty, value); } 18 | } 19 | 20 | public static readonly DependencyProperty IconProperty = 21 | DependencyProperty.Register("Icon", typeof(ImageSource), typeof(MenuFlyoutImageItem), new PropertyMetadata(null)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /VisualStudioShell.Controls/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("VisualStudioShell.Controls")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("VisualStudioShell.Controls")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /VisualStudioShell.Controls/Properties/VisualStudioShell.Controls.rd.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /VisualStudioShell.Controls/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 88 | 89 | -------------------------------------------------------------------------------- /VisualStudioShell.Controls/VisualStudioShell.Controls.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B} 8 | Library 9 | Properties 10 | VisualStudioShell.Controls 11 | VisualStudioShell.Controls 12 | en-US 13 | UAP 14 | 10.0.14393.0 15 | 10.0.14393.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | 20 | 21 | AnyCPU 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 27 | prompt 28 | 4 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE;NETFX_CORE;WINDOWS_UWP 36 | prompt 37 | 4 38 | 39 | 40 | x86 41 | true 42 | bin\x86\Debug\ 43 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 44 | ;2008 45 | full 46 | x86 47 | false 48 | prompt 49 | 50 | 51 | x86 52 | bin\x86\Release\ 53 | TRACE;NETFX_CORE;WINDOWS_UWP 54 | true 55 | ;2008 56 | pdbonly 57 | x86 58 | false 59 | prompt 60 | 61 | 62 | ARM 63 | true 64 | bin\ARM\Debug\ 65 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 66 | ;2008 67 | full 68 | ARM 69 | false 70 | prompt 71 | 72 | 73 | ARM 74 | bin\ARM\Release\ 75 | TRACE;NETFX_CORE;WINDOWS_UWP 76 | true 77 | ;2008 78 | pdbonly 79 | ARM 80 | false 81 | prompt 82 | 83 | 84 | x64 85 | true 86 | bin\x64\Debug\ 87 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 88 | ;2008 89 | full 90 | x64 91 | false 92 | prompt 93 | 94 | 95 | x64 96 | bin\x64\Release\ 97 | TRACE;NETFX_CORE;WINDOWS_UWP 98 | true 99 | ;2008 100 | pdbonly 101 | x64 102 | false 103 | prompt 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | MSBuild:Compile 117 | Designer 118 | 119 | 120 | 121 | 14.0 122 | 123 | 124 | 131 | -------------------------------------------------------------------------------- /VisualStudioShell.Controls/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2" 4 | }, 5 | "frameworks": { 6 | "uap10.0": {} 7 | }, 8 | "runtimes": { 9 | "win10-arm": {}, 10 | "win10-arm-aot": {}, 11 | "win10-x86": {}, 12 | "win10-x86-aot": {}, 13 | "win10-x64": {}, 14 | "win10-x64-aot": {} 15 | } 16 | } -------------------------------------------------------------------------------- /VisualStudioShell.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26206.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualStudioShell", "VisualStudioShell\VisualStudioShell.csproj", "{93B47051-1900-4376-8AAF-B8F11CDC68F5}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualStudioShell.Controls", "VisualStudioShell.Controls\VisualStudioShell.Controls.csproj", "{A4CB1F68-5C63-4D6F-9066-6501407C5D3B}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TreeViewControl", "TreeViewControl\TreeViewControl.vcxproj", "{94560D69-A345-4E44-B897-EAA2B0E23238}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "App", "App", "{6E70D3F1-D05D-4BDC-8A52-B32B16692293}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Controls", "Controls", "{BBE3A0C5-9276-4308-A6F1-96809857515E}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Debug|ARM = Debug|ARM 20 | Debug|x64 = Debug|x64 21 | Debug|x86 = Debug|x86 22 | Release|Any CPU = Release|Any CPU 23 | Release|ARM = Release|ARM 24 | Release|x64 = Release|x64 25 | Release|x86 = Release|x86 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|Any CPU.ActiveCfg = Debug|x86 29 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|ARM.ActiveCfg = Debug|ARM 30 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|ARM.Build.0 = Debug|ARM 31 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|ARM.Deploy.0 = Debug|ARM 32 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|x64.ActiveCfg = Debug|x64 33 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|x64.Build.0 = Debug|x64 34 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|x64.Deploy.0 = Debug|x64 35 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|x86.ActiveCfg = Debug|x86 36 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|x86.Build.0 = Debug|x86 37 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Debug|x86.Deploy.0 = Debug|x86 38 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|Any CPU.ActiveCfg = Release|x86 39 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|ARM.ActiveCfg = Release|ARM 40 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|ARM.Build.0 = Release|ARM 41 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|ARM.Deploy.0 = Release|ARM 42 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|x64.ActiveCfg = Release|x64 43 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|x64.Build.0 = Release|x64 44 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|x64.Deploy.0 = Release|x64 45 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|x86.ActiveCfg = Release|x86 46 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|x86.Build.0 = Release|x86 47 | {93B47051-1900-4376-8AAF-B8F11CDC68F5}.Release|x86.Deploy.0 = Release|x86 48 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Debug|ARM.ActiveCfg = Debug|ARM 51 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Debug|ARM.Build.0 = Debug|ARM 52 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Debug|x64.ActiveCfg = Debug|x64 53 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Debug|x64.Build.0 = Debug|x64 54 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Debug|x86.ActiveCfg = Debug|x86 55 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Debug|x86.Build.0 = Debug|x86 56 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Release|Any CPU.ActiveCfg = Release|Any CPU 57 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Release|Any CPU.Build.0 = Release|Any CPU 58 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Release|ARM.ActiveCfg = Release|ARM 59 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Release|ARM.Build.0 = Release|ARM 60 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Release|x64.ActiveCfg = Release|x64 61 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Release|x64.Build.0 = Release|x64 62 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Release|x86.ActiveCfg = Release|x86 63 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B}.Release|x86.Build.0 = Release|x86 64 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Debug|Any CPU.ActiveCfg = Debug|Win32 65 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Debug|ARM.ActiveCfg = Debug|ARM 66 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Debug|ARM.Build.0 = Debug|ARM 67 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Debug|x64.ActiveCfg = Debug|x64 68 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Debug|x64.Build.0 = Debug|x64 69 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Debug|x86.ActiveCfg = Debug|Win32 70 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Debug|x86.Build.0 = Debug|Win32 71 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Release|Any CPU.ActiveCfg = Release|Win32 72 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Release|ARM.ActiveCfg = Release|ARM 73 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Release|ARM.Build.0 = Release|ARM 74 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Release|x64.ActiveCfg = Release|x64 75 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Release|x64.Build.0 = Release|x64 76 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Release|x86.ActiveCfg = Release|Win32 77 | {94560D69-A345-4E44-B897-EAA2B0E23238}.Release|x86.Build.0 = Release|Win32 78 | EndGlobalSection 79 | GlobalSection(SolutionProperties) = preSolution 80 | HideSolutionNode = FALSE 81 | EndGlobalSection 82 | GlobalSection(NestedProjects) = preSolution 83 | {93B47051-1900-4376-8AAF-B8F11CDC68F5} = {6E70D3F1-D05D-4BDC-8A52-B32B16692293} 84 | {A4CB1F68-5C63-4D6F-9066-6501407C5D3B} = {BBE3A0C5-9276-4308-A6F1-96809857515E} 85 | {94560D69-A345-4E44-B897-EAA2B0E23238} = {BBE3A0C5-9276-4308-A6F1-96809857515E} 86 | EndGlobalSection 87 | EndGlobal 88 | -------------------------------------------------------------------------------- /VisualStudioShell/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 0 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /VisualStudioShell/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.ApplicationModel; 7 | using Windows.ApplicationModel.Activation; 8 | using Windows.Foundation; 9 | using Windows.Foundation.Collections; 10 | using Windows.UI.Xaml; 11 | using Windows.UI.Xaml.Controls; 12 | using Windows.UI.Xaml.Controls.Primitives; 13 | using Windows.UI.Xaml.Data; 14 | using Windows.UI.Xaml.Input; 15 | using Windows.UI.Xaml.Media; 16 | using Windows.UI.Xaml.Navigation; 17 | 18 | namespace VisualStudioShell 19 | { 20 | /// 21 | /// Provides application-specific behavior to supplement the default Application class. 22 | /// 23 | sealed partial class App : Application 24 | { 25 | /// 26 | /// Initializes the singleton application object. This is the first line of authored code 27 | /// executed, and as such is the logical equivalent of main() or WinMain(). 28 | /// 29 | public App() 30 | { 31 | this.InitializeComponent(); 32 | this.Suspending += OnSuspending; 33 | } 34 | 35 | /// 36 | /// Invoked when the application is launched normally by the end user. Other entry points 37 | /// will be used such as when the application is launched to open a specific file. 38 | /// 39 | /// Details about the launch request and process. 40 | protected override void OnLaunched(LaunchActivatedEventArgs e) 41 | { 42 | Frame rootFrame = Window.Current.Content as Frame; 43 | 44 | // Do not repeat app initialization when the Window already has content, 45 | // just ensure that the window is active 46 | if (rootFrame == null) 47 | { 48 | // Create a Frame to act as the navigation context and navigate to the first page 49 | rootFrame = new Frame(); 50 | 51 | rootFrame.NavigationFailed += OnNavigationFailed; 52 | 53 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 54 | { 55 | //TODO: Load state from previously suspended application 56 | } 57 | 58 | // Place the frame in the current Window 59 | Window.Current.Content = rootFrame; 60 | } 61 | 62 | if (e.PrelaunchActivated == false) 63 | { 64 | if (rootFrame.Content == null) 65 | { 66 | // When the navigation stack isn't restored navigate to the first page, 67 | // configuring the new page by passing required information as a navigation 68 | // parameter 69 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 70 | } 71 | // Ensure the current window is active 72 | Window.Current.Activate(); 73 | } 74 | } 75 | 76 | /// 77 | /// Invoked when Navigation to a certain page fails 78 | /// 79 | /// The Frame which failed navigation 80 | /// Details about the navigation failure 81 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 82 | { 83 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 84 | } 85 | 86 | /// 87 | /// Invoked when application execution is being suspended. Application state is saved 88 | /// without knowing whether the application will be terminated or resumed with the contents 89 | /// of memory still intact. 90 | /// 91 | /// The source of the suspend request. 92 | /// Details about the suspend request. 93 | private void OnSuspending(object sender, SuspendingEventArgs e) 94 | { 95 | var deferral = e.SuspendingOperation.GetDeferral(); 96 | //TODO: Save application state and stop any background activity 97 | deferral.Complete(); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /VisualStudioShell/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.altform-unplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.altform-unplated_targetsize-16.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.altform-unplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.altform-unplated_targetsize-256.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.altform-unplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.altform-unplated_targetsize-32.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.altform-unplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.altform-unplated_targetsize-48.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.scale-125.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.scale-150.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.targetsize-24.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.targetsize-32.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/StoreLogo.png -------------------------------------------------------------------------------- /VisualStudioShell/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /VisualStudioShell/Controls/DiagnosticTools.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/DiagnosticTools.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.Foundation; 7 | using Windows.Foundation.Collections; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls; 10 | using Windows.UI.Xaml.Controls.Primitives; 11 | using Windows.UI.Xaml.Data; 12 | using Windows.UI.Xaml.Input; 13 | using Windows.UI.Xaml.Media; 14 | using Windows.UI.Xaml.Navigation; 15 | 16 | // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 17 | 18 | namespace VisualStudioShell.Controls 19 | { 20 | public sealed partial class DiagnosticTools : UserControl 21 | { 22 | public DiagnosticTools() 23 | { 24 | this.InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/LiveVisualTree.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 29 | 30 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 53 | 54 | 55 | 58 | 59 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/LiveVisualTree.xaml.cs: -------------------------------------------------------------------------------- 1 | using TreeViewControl; 2 | using Windows.UI.Xaml; 3 | using Windows.UI.Xaml.Controls; 4 | using Windows.UI.Xaml.Media; 5 | 6 | namespace VisualStudioShell.Controls 7 | { 8 | public sealed partial class LiveVisualTree : UserControl 9 | { 10 | public LiveVisualTree() 11 | { 12 | this.InitializeComponent(); 13 | this.Loaded += LiveVisualTree_Loaded; 14 | } 15 | 16 | private void LiveVisualTree_Loaded(object sender, RoutedEventArgs e) 17 | { 18 | var rootElement = Window.Current.Content; 19 | int level = 0; 20 | var rootNode = new TreeNode { Data = new TreeNodeDataBase(rootElement.GetType().Name), IsExpanded = true }; 21 | AddChildren(rootNode, rootElement,level); 22 | 23 | treeView.RootNode.Add(rootNode); 24 | } 25 | 26 | private void AddChildren(TreeNode parentNode, UIElement parentElement, int level) 27 | { 28 | level++; 29 | var count = VisualTreeHelper.GetChildrenCount(parentElement); 30 | for (int i = 0; i < count; i++) 31 | { 32 | var childElement = VisualTreeHelper.GetChild(parentElement, i) as UIElement; 33 | if (childElement != null) 34 | { 35 | var childNode = new TreeNode { Data = new TreeNodeDataBase(ElementToString(childElement)) }; 36 | 37 | // Don't expand all, as it takes ages. :-) 38 | if(level<6) 39 | { 40 | childNode.IsExpanded = true; 41 | } 42 | parentNode.Add(childNode); 43 | AddChildren(childNode, childElement, level); 44 | } 45 | } 46 | } 47 | 48 | private string ElementToString(UIElement childElement) 49 | { 50 | var s = ""; 51 | 52 | var f = childElement as FrameworkElement; 53 | if (f != null) 54 | { 55 | s = f.Name + " "; 56 | } 57 | s += $"[{childElement.GetType().Name}]"; 58 | 59 | return s; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/Notifications.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/Notifications.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.Foundation; 7 | using Windows.Foundation.Collections; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls; 10 | using Windows.UI.Xaml.Controls.Primitives; 11 | using Windows.UI.Xaml.Data; 12 | using Windows.UI.Xaml.Input; 13 | using Windows.UI.Xaml.Media; 14 | using Windows.UI.Xaml.Navigation; 15 | 16 | // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 17 | 18 | namespace VisualStudioShell.Controls 19 | { 20 | public sealed partial class Notifications : UserControl 21 | { 22 | public Notifications() 23 | { 24 | this.InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/SolutionExplorer.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 29 | 30 | 31 | 32 | 33 | 41 | 42 | 43 | 44 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 69 | 70 | 73 | 74 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/SolutionExplorer.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using TreeViewControl; 3 | using Windows.UI.Xaml; 4 | using Windows.UI.Xaml.Controls; 5 | 6 | namespace VisualStudioShell.Controls 7 | { 8 | public sealed partial class SolutionExplorer : UserControl, INotifyPropertyChanged 9 | { 10 | public event PropertyChangedEventHandler PropertyChanged; 11 | private bool _isPinned = true; 12 | 13 | public SolutionExplorer() 14 | { 15 | this.InitializeComponent(); 16 | this.Loaded += SolutionExplorer_Loaded; 17 | } 18 | 19 | public bool IsPinned 20 | { 21 | get { return _isPinned; } 22 | set 23 | { 24 | _isPinned = value; 25 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsPinned))); 26 | } 27 | } 28 | 29 | private void SolutionExplorer_Loaded(object sender, RoutedEventArgs e) 30 | { 31 | BuildTreeView(); 32 | } 33 | 34 | private void BuildTreeView() 35 | { 36 | 37 | var rootNode = CreateTreeNode("Solution 'VisualStudioShell'", false, "Solution.png"); 38 | var uiProjectNode = CreateUIProjectNode(); 39 | var controlsProjectNode = CreateControlsProjectNode(); 40 | rootNode.Add(uiProjectNode); 41 | rootNode.Add(controlsProjectNode); 42 | 43 | rootNode.IsExpanded = true; 44 | 45 | treeView.RootNode.Add(rootNode); 46 | } 47 | 48 | private TreeNode CreateUIProjectNode() 49 | { 50 | var projectRootNode = CreateTreeNode("VisualStudioShell (Universal Windows)", false, "ProjectCSharp.png"); 51 | var referencesUI = CreateTreeNode("References", false, "References.png"); 52 | referencesUI.Add(CreateTreeNode("TreeViewControl", false, "References.png")); 53 | referencesUI.Add(CreateTreeNode("Universal Windows", false, "References.png")); 54 | referencesUI.Add(CreateTreeNode("VisualStudioShell.Controls", false, "References.png")); 55 | projectRootNode.Add(referencesUI); 56 | 57 | 58 | var converter = CreateTreeNode("Converter", true); 59 | converter.Add(CreateTreeNode("BooleanToVisibilityConverter", false, "FileCs.png")); 60 | converter.Add(CreateTreeNode("GlyphConverter", false, "FileCs.png")); 61 | projectRootNode.Add(converter); 62 | 63 | var appXaml = CreateTreeNode("App.xaml", false, "FileXaml.png"); 64 | appXaml.Add(CreateTreeNode("App.xaml.cs", false, "FileXamlCs.png")); 65 | projectRootNode.Add(appXaml); 66 | 67 | var mainXaml = CreateTreeNode("Main.xaml", false, "FileXaml.png"); 68 | mainXaml.Add(CreateTreeNode("Main.xaml.cs", false, "FileXamlCs.png")); 69 | projectRootNode.Add(mainXaml); 70 | 71 | 72 | projectRootNode.IsExpanded = true; 73 | referencesUI.IsExpanded = true; 74 | converter.IsExpanded = true; 75 | appXaml.IsExpanded = true; 76 | mainXaml.IsExpanded = true; 77 | 78 | return projectRootNode; 79 | } 80 | 81 | private TreeNode CreateControlsProjectNode() 82 | { 83 | var projectRootNode = CreateTreeNode("VisualStudioShell.Controls (Universal Windows)", false, "ProjectCSharp.png"); 84 | var referencesControls = CreateTreeNode("References", false, "References.png"); 85 | referencesControls.Add(CreateTreeNode("Universal Windows", false, "References.png")); 86 | projectRootNode.Add(referencesControls); 87 | 88 | var themesNode = CreateTreeNode("Themes", true); 89 | themesNode.Add(CreateTreeNode("Generic.xaml", false, "FileXaml.png")); 90 | projectRootNode.Add(themesNode); 91 | 92 | projectRootNode.Add(CreateTreeNode("MenuFlyoutImageItem", false, "FileCs.png")); 93 | 94 | return projectRootNode; 95 | } 96 | 97 | private TreeNode CreateTreeNode(string name, bool isFolder, string image = null) 98 | { 99 | return new TreeNode 100 | { 101 | Data = new TreeNodeData(name, isFolder, image) 102 | }; 103 | } 104 | 105 | private void SolutionExplorerPinButton_Click(object sender, RoutedEventArgs e) 106 | { 107 | IsPinned = !IsPinned; 108 | imgPinned.Visibility = IsPinned ? Visibility.Visible : Visibility.Collapsed; 109 | imgUnpinned.Visibility = !IsPinned ? Visibility.Visible : Visibility.Collapsed; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/Toolbox.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/Toolbox.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.Foundation; 7 | using Windows.Foundation.Collections; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls; 10 | using Windows.UI.Xaml.Controls.Primitives; 11 | using Windows.UI.Xaml.Data; 12 | using Windows.UI.Xaml.Input; 13 | using Windows.UI.Xaml.Media; 14 | using Windows.UI.Xaml.Navigation; 15 | 16 | // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 17 | 18 | namespace VisualStudioShell.Controls 19 | { 20 | public sealed partial class Toolbox : UserControl 21 | { 22 | public Toolbox() 23 | { 24 | this.InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /VisualStudioShell/Controls/TreeNodeData.cs: -------------------------------------------------------------------------------- 1 | namespace VisualStudioShell.Controls 2 | { 3 | public class TreeNodeDataBase 4 | { 5 | public TreeNodeDataBase(string name) 6 | { 7 | Name = name; 8 | } 9 | public string Name { get; set; } 10 | } 11 | public class TreeNodeData : TreeNodeDataBase 12 | { 13 | public TreeNodeData(string name, bool isFolder, string image = null) : base(name) 14 | { 15 | IsFolder = isFolder; 16 | ImagePath = "/Images/SolutionExplorer/" + image; 17 | } 18 | public string ImagePath { get; set; } 19 | public bool IsFolder { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /VisualStudioShell/Converter/BooleanToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Windows.UI.Xaml; 3 | using Windows.UI.Xaml.Data; 4 | 5 | namespace VisualStudioShell.Converter 6 | { 7 | class BooleanToVisibilityConverter : IValueConverter 8 | { 9 | public bool IsInverse { get; set; } 10 | public object Convert(object value, Type targetType, object parameter, string language) 11 | { 12 | bool visibility = (bool)value; 13 | if (IsInverse) 14 | { 15 | visibility = !visibility; 16 | } 17 | 18 | return visibility ? Visibility.Visible : Visibility.Collapsed; 19 | } 20 | 21 | public object ConvertBack(object value, Type targetType, object parameter, string language) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /VisualStudioShell/Converter/GlyphConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Windows.UI.Xaml.Data; 3 | 4 | namespace VisualStudioShell.Converter 5 | { 6 | public sealed class GlyphConverter : IValueConverter 7 | { 8 | public string ExpandedGlyph { get; set; } 9 | public string CollapsedGlyph { get; set; } 10 | 11 | public object Convert(object value, Type targetType, object parameter, string language) 12 | { 13 | var isExpanded = value as bool?; 14 | 15 | if (isExpanded.HasValue && isExpanded.Value) 16 | { 17 | return ExpandedGlyph; 18 | } 19 | else 20 | { 21 | return CollapsedGlyph; 22 | } 23 | } 24 | 25 | public object ConvertBack(object value, Type targetType, object parameter, string language) 26 | { 27 | throw new NotImplementedException(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /VisualStudioShell/Images/Menu/CloseSolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/Menu/CloseSolution.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/Menu/Debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/Menu/Debug.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/Menu/NewProject.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/Menu/NewProject.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/Menu/NewWebsite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/Menu/NewWebsite.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/Menu/Save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/Menu/Save.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/Menu/SaveAll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/Menu/SaveAll.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/SolutionExplorer/FileCs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/SolutionExplorer/FileCs.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/SolutionExplorer/FileXaml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/SolutionExplorer/FileXaml.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/SolutionExplorer/FileXamlCs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/SolutionExplorer/FileXamlCs.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/SolutionExplorer/HeaderPinned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/SolutionExplorer/HeaderPinned.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/SolutionExplorer/HeaderUnpinned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/SolutionExplorer/HeaderUnpinned.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/SolutionExplorer/ProjectCSharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/SolutionExplorer/ProjectCSharp.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/SolutionExplorer/References.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/SolutionExplorer/References.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/SolutionExplorer/Solution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/SolutionExplorer/Solution.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/Titlebar/Feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/Titlebar/Feedback.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/Titlebar/Notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/Titlebar/Notifications.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/VisualStudioIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/VisualStudioIcon.png -------------------------------------------------------------------------------- /VisualStudioShell/Images/thomas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasclaudiushuber/Uwp-Visual-Studio-Shell/6ee26f9957f426de6ad41b0a87a93350b051daa9/VisualStudioShell/Images/thomas.png -------------------------------------------------------------------------------- /VisualStudioShell/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 106 | 62 | 63 | 64 | 132 | 133 | 134 | 202 | 203 | 204 | 248 | 249 | -------------------------------------------------------------------------------- /VisualStudioShell/Resources/MenuFlyoutSubItem.xaml: -------------------------------------------------------------------------------- 1 |  4 | 106 | 107 | -------------------------------------------------------------------------------- /VisualStudioShell/Resources/PivotHeaderItem.xaml: -------------------------------------------------------------------------------- 1 |  5 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 60 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 137 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /VisualStudioShell/VisualStudioShell.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x86 7 | {93B47051-1900-4376-8AAF-B8F11CDC68F5} 8 | AppContainerExe 9 | Properties 10 | VisualStudioShell 11 | VisualStudioShell 12 | en-US 13 | UAP 14 | 10.0.14393.0 15 | 10.0.14393.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | true 20 | VisualStudioShell_TemporaryKey.pfx 21 | 22 | 23 | true 24 | bin\x86\Debug\ 25 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 26 | ;2008 27 | full 28 | x86 29 | false 30 | prompt 31 | true 32 | 33 | 34 | bin\x86\Release\ 35 | TRACE;NETFX_CORE;WINDOWS_UWP 36 | true 37 | ;2008 38 | pdbonly 39 | x86 40 | false 41 | prompt 42 | true 43 | true 44 | 45 | 46 | true 47 | bin\ARM\Debug\ 48 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 49 | ;2008 50 | full 51 | ARM 52 | false 53 | prompt 54 | true 55 | 56 | 57 | bin\ARM\Release\ 58 | TRACE;NETFX_CORE;WINDOWS_UWP 59 | true 60 | ;2008 61 | pdbonly 62 | ARM 63 | false 64 | prompt 65 | true 66 | true 67 | 68 | 69 | true 70 | bin\x64\Debug\ 71 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 72 | ;2008 73 | full 74 | x64 75 | false 76 | prompt 77 | true 78 | 79 | 80 | bin\x64\Release\ 81 | TRACE;NETFX_CORE;WINDOWS_UWP 82 | true 83 | ;2008 84 | pdbonly 85 | x64 86 | false 87 | prompt 88 | true 89 | true 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | App.xaml 98 | 99 | 100 | DiagnosticTools.xaml 101 | 102 | 103 | LiveVisualTree.xaml 104 | 105 | 106 | Notifications.xaml 107 | 108 | 109 | SolutionExplorer.xaml 110 | 111 | 112 | Toolbox.xaml 113 | 114 | 115 | 116 | 117 | 118 | MainPage.xaml 119 | Always 120 | 121 | 122 | 123 | 124 | 125 | Designer 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | MSBuild:Compile 173 | Designer 174 | 175 | 176 | Designer 177 | MSBuild:Compile 178 | 179 | 180 | Designer 181 | MSBuild:Compile 182 | 183 | 184 | Designer 185 | MSBuild:Compile 186 | 187 | 188 | Designer 189 | MSBuild:Compile 190 | 191 | 192 | MSBuild:Compile 193 | Designer 194 | 195 | 196 | MSBuild:Compile 197 | Designer 198 | Always 199 | 200 | 201 | Designer 202 | MSBuild:Compile 203 | PreserveNewest 204 | 205 | 206 | Designer 207 | MSBuild:Compile 208 | PreserveNewest 209 | 210 | 211 | Designer 212 | MSBuild:Compile 213 | PreserveNewest 214 | 215 | 216 | Designer 217 | MSBuild:Compile 218 | PreserveNewest 219 | 220 | 221 | Designer 222 | MSBuild:Compile 223 | PreserveNewest 224 | 225 | 226 | 227 | 228 | 229 | {94560d69-a345-4e44-b897-eaa2b0e23238} 230 | TreeViewControl 231 | 232 | 233 | {a4cb1f68-5c63-4d6f-9066-6501407c5d3b} 234 | VisualStudioShell.Controls 235 | 236 | 237 | 238 | 14.0 239 | 240 | 241 | 248 | -------------------------------------------------------------------------------- /VisualStudioShell/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2", 4 | "Microsoft.Toolkit.Uwp": "1.3.1", 5 | "Microsoft.Toolkit.Uwp.UI.Controls": "1.3.1" 6 | }, 7 | "frameworks": { 8 | "uap10.0": {} 9 | }, 10 | "runtimes": { 11 | "win10-arm": {}, 12 | "win10-arm-aot": {}, 13 | "win10-x86": {}, 14 | "win10-x86-aot": {}, 15 | "win10-x64": {}, 16 | "win10-x64-aot": {} 17 | } 18 | } --------------------------------------------------------------------------------