Skip to content

Commit 91b8710

Browse files
committed
Merge branch 'FixTreeView' of https://github.com/l1pton17/MaterialDesignInXamlToolkit into l1pton17-FixTreeView
2 parents 83875cf + 00279b3 commit 91b8710

File tree

6 files changed

+266
-3
lines changed

6 files changed

+266
-3
lines changed

MainDemo.Wpf/Domain/BindableBase.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.Linq;
5+
using System.Runtime.CompilerServices;
6+
using System.Text;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
10+
namespace MaterialDesignColors.WpfExample.Domain
11+
{
12+
public abstract class BindableBase : INotifyPropertyChanged
13+
{
14+
public event PropertyChangedEventHandler PropertyChanged;
15+
16+
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
17+
{
18+
Volatile.Read(ref PropertyChanged)?.Invoke(this, new PropertyChangedEventArgs(propertyName));
19+
}
20+
}
21+
}

MainDemo.Wpf/Domain/TreesViewModel.cs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.ComponentModel;
5+
using System.Linq;
6+
using System.Runtime.CompilerServices;
7+
using System.Text;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
11+
namespace MaterialDesignColors.WpfExample.Domain
12+
{
13+
public sealed class Movie : BindableBase
14+
{
15+
private string _name;
16+
17+
public string Name
18+
{
19+
get { return _name; }
20+
set
21+
{
22+
_name = value;
23+
OnPropertyChanged();
24+
}
25+
}
26+
27+
private string _director;
28+
29+
public string Director
30+
{
31+
get { return _director; }
32+
set
33+
{
34+
_director = value;
35+
OnPropertyChanged();
36+
}
37+
}
38+
}
39+
40+
public sealed class MovieCategory : BindableBase
41+
{
42+
public string Name { get; }
43+
44+
public ObservableCollection<Movie> Movies { get; }
45+
46+
public MovieCategory(string name)
47+
{
48+
Name = name;
49+
Movies = new ObservableCollection<Movie>();
50+
}
51+
}
52+
53+
public sealed class TreesViewModel : BindableBase
54+
{
55+
public ObservableCollection<MovieCategory> MovieCategories { get; }
56+
57+
public AnotherCommandImplementation AddCommand { get; }
58+
59+
public AnotherCommandImplementation RemoveSelectedItemCommand { get; }
60+
61+
private object _selectedItem;
62+
public object SelectedItem
63+
{
64+
get { return _selectedItem; }
65+
set
66+
{
67+
_selectedItem = value;
68+
OnPropertyChanged();
69+
}
70+
}
71+
72+
public TreesViewModel()
73+
{
74+
MovieCategories = new ObservableCollection<MovieCategory>
75+
{
76+
new MovieCategory("Action")
77+
{
78+
Movies =
79+
{
80+
new Movie
81+
{
82+
Name = "Predator",
83+
Director = "John McTiernan"
84+
},
85+
new Movie
86+
{
87+
Name = "Alien",
88+
Director = "Ridley Scott"
89+
},
90+
new Movie
91+
{
92+
Name = "Prometheus",
93+
Director = "Ridley Scott"
94+
}
95+
}
96+
},
97+
new MovieCategory("Comedy")
98+
{
99+
Movies =
100+
{
101+
new Movie
102+
{
103+
Name = "EuroTrip",
104+
Director = "Jeff Schaffer"
105+
},
106+
new Movie
107+
{
108+
Name = "EuroTrip",
109+
Director = "Jeff Schaffer"
110+
}
111+
}
112+
}
113+
};
114+
115+
AddCommand = new AnotherCommandImplementation(
116+
_ =>
117+
{
118+
if (!MovieCategories.Any())
119+
{
120+
MovieCategories.Add(new MovieCategory(GenerateString(15)));
121+
}
122+
else
123+
{
124+
int index = new Random().Next(0, MovieCategories.Count);
125+
126+
MovieCategories[index].Movies.Add(
127+
new Movie
128+
{
129+
Name = GenerateString(15),
130+
Director = GenerateString(20)
131+
});
132+
}
133+
});
134+
135+
RemoveSelectedItemCommand = new AnotherCommandImplementation(
136+
_ =>
137+
{
138+
if (SelectedItem is MovieCategory)
139+
{
140+
MovieCategories.Remove(SelectedItem as MovieCategory);
141+
}
142+
else if (SelectedItem is Movie)
143+
{
144+
var movie = SelectedItem as Movie;
145+
MovieCategories.FirstOrDefault(v => v.Movies.Contains(movie))?.Movies.Remove(movie);
146+
}
147+
},
148+
_ => SelectedItem != null);
149+
}
150+
151+
private static string GenerateString(int length)
152+
{
153+
var random = new Random();
154+
155+
return String.Join(String.Empty,
156+
Enumerable.Range(0, length)
157+
.Select(v => (char) random.Next((int)'a', (int)'z' + 1)));
158+
}
159+
}
160+
}

MainDemo.Wpf/MainDemo.Wpf.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
<DependentUpon>Dialogs.xaml</DependentUpon>
8383
</Compile>
8484
<Compile Include="Domain\AnotherCommandImplementation.cs" />
85+
<Compile Include="Domain\BindableBase.cs" />
8586
<Compile Include="Domain\DemoItem.cs" />
8687
<Compile Include="Domain\DialogsViewModel.cs" />
8788
<Compile Include="Domain\ListFieldsViewModel.cs" />
@@ -96,6 +97,7 @@
9697
</Compile>
9798
<Compile Include="Domain\SelectableViewModel.cs" />
9899
<Compile Include="Domain\TextFieldsViewModel.cs" />
100+
<Compile Include="Domain\TreesViewModel.cs" />
99101
<Compile Include="Expander.xaml.cs">
100102
<DependentUpon>Expander.xaml</DependentUpon>
101103
</Compile>

MainDemo.Wpf/MainWindow.xaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@
110110
</domain:DemoItem>
111111
<domain:DemoItem Name="Trees">
112112
<domain:DemoItem.Content>
113-
<wpfExample:Trees />
113+
<wpfExample:Trees>
114+
<wpfExample:Trees.DataContext>
115+
<domain:TreesViewModel/>
116+
</wpfExample:Trees.DataContext>
117+
</wpfExample:Trees>
114118
</domain:DemoItem.Content>
115119
</domain:DemoItem>
116120
<domain:DemoItem Name="Grids">

MainDemo.Wpf/Trees.xaml

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,25 @@
22
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5-
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
7+
xmlns:domain="clr-namespace:MaterialDesignColors.WpfExample.Domain"
68
mc:Ignorable="d"
79
d:DesignHeight="300" d:DesignWidth="300">
10+
<UserControl.Resources>
11+
<ResourceDictionary>
12+
<ResourceDictionary.MergedDictionaries>
13+
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
14+
</ResourceDictionary.MergedDictionaries>
15+
</ResourceDictionary>
16+
</UserControl.Resources>
817
<Grid>
9-
<TreeView HorizontalAlignment="Left" MinWidth="220">
18+
<Grid.ColumnDefinitions>
19+
<ColumnDefinition Width="Auto"/>
20+
<ColumnDefinition Width="Auto"/>
21+
</Grid.ColumnDefinitions>
22+
<TreeView Grid.Column="0"
23+
MinWidth="220">
1024
<TreeViewItem Header="Fruit">
1125
<TreeViewItem>
1226
<TreeViewItem.Header>
@@ -74,5 +88,52 @@
7488
</TreeViewItem>
7589
<TreeViewItem Header="Empty" />
7690
</TreeView>
91+
<Grid Grid.Column="1"
92+
MinWidth="220"
93+
VerticalAlignment="Top">
94+
<Grid.RowDefinitions>
95+
<RowDefinition Height="*"/>
96+
<RowDefinition Height="Auto"/>
97+
</Grid.RowDefinitions>
98+
<TreeView Grid.Row="0"
99+
ItemsSource="{Binding MovieCategories}"
100+
MinWidth="220"
101+
SelectedItemChanged="TreeView_SelectedItemChanged">
102+
<TreeView.Resources>
103+
<HierarchicalDataTemplate DataType="{x:Type domain:MovieCategory}"
104+
ItemsSource="{Binding Movies}">
105+
<TextBlock Text="{Binding Name}" Margin="3 2"/>
106+
</HierarchicalDataTemplate>
107+
<DataTemplate DataType="{x:Type domain:Movie}">
108+
<TextBlock Text="{Binding Name}" Margin="3 2"
109+
ToolTip="{Binding Director}"/>
110+
</DataTemplate>
111+
</TreeView.Resources>
112+
</TreeView>
113+
<materialDesign:PopupBox Grid.Row="1"
114+
Style="{StaticResource MaterialDesignMultiFloatingActionPopupBox}"
115+
PlacementMode="LeftAndAlignTopEdges"
116+
ToolTipService.Placement="Bottom"
117+
ToolTip="Manage items"
118+
Margin="0 0 10 10"
119+
HorizontalAlignment="Right" VerticalAlignment="Bottom">
120+
<StackPanel>
121+
<Button ToolTip="Add an item"
122+
Command="{Binding AddCommand}">
123+
<Path Data="M19,13H13V19H11V13H5V11H11V5H13V11H19V13Z"
124+
Stretch="Uniform"
125+
Width="15" Height="15"
126+
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"/>
127+
</Button>
128+
<Button ToolTip="Remove selected item"
129+
Command="{Binding RemoveSelectedItemCommand}">
130+
<Path Data="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z"
131+
Stretch="Uniform"
132+
Width="15" Height="15"
133+
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"/>
134+
</Button>
135+
</StackPanel>
136+
</materialDesign:PopupBox>
137+
</Grid>
77138
</Grid>
78139
</UserControl>

MainDemo.Wpf/Trees.xaml.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Windows.Media.Imaging;
1313
using System.Windows.Navigation;
1414
using System.Windows.Shapes;
15+
using MaterialDesignColors.WpfExample.Domain;
1516

1617
namespace MaterialDesignColors.WpfExample
1718
{
@@ -24,5 +25,19 @@ public Trees()
2425
{
2526
InitializeComponent();
2627
}
28+
29+
public TreesViewModel ViewModel => DataContext as TreesViewModel;
30+
31+
/// <summary>
32+
/// TreesView's SelectedItem is read-only. Hence we can't bind it. There is a way to obtain a selected item.
33+
/// </summary>
34+
/// <param name="sender"></param>
35+
/// <param name="e"></param>
36+
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
37+
{
38+
if (ViewModel == null) return;
39+
40+
ViewModel.SelectedItem = e.NewValue;
41+
}
2742
}
2843
}

0 commit comments

Comments
 (0)