Я пытаюсь отобразить древовидную структуру в своем приложении, но каким-то образом я не могу заставить работать привязку, и приложение отображает пустую древовидную структуру. Вот исходный код.
MainWindow.xaml
<Window x:Class="TreeViewTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TreeViewTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<ListBox x:Name="listbox" MinWidth="200" MinHeight="300">
<TreeView x:Name="treeView" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Regions}"
MinWidth="200" MinHeight="300">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Region}" ItemsSource="{Binding Customers}" >
<CheckBox Content="{Binding Name}" IsChecked="{Binding Path=(local:CustomerDataHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Visibility" Value="Visible"/>
</Style>
</CheckBox.Style>
</CheckBox>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:Customer}" >
<CheckBox Content="{Binding Name}" IsChecked="{Binding Path=(local:CustomerDataHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Visibility" Value="Visible"/>
</Style>
</CheckBox.Style>
</CheckBox>
</DataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</ListBox>
<Button Content="?" Click="Button_Click" />
<TextBlock x:Name="textBoxCrew"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public ObservableCollection<Region> Regions { get; }
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
string crew = "";
foreach (Region Region in this.Regions)
foreach (Customer Customer in Region.Customers)
if (CustomerDataHelper.GetIsChecked(Customer) == true)
crew += Customer.Name + ", ";
crew = crew.TrimEnd(new char[] { ',', ' ' });
this.textBoxCrew.Text = "Selected customers: " + crew;
}
}
MainWindowViewModel.cs
class MainWindowViewModel
{
public MainWindowViewModel()
{
Regions = new ObservableCollection<Region>();
Regions.Add(new Region() { Name = "North", Customers = new List<Customer>() { new Customer() { Name = "N1" }, new Customer() { Name = "N2" } } });
Regions.Add(new Region() { Name = "East", Customers = new List<Customer>() { new Customer() { Name = "E1" }, new Customer() { Name = "E2" } } });
Regions.Add(new Region() { Name = "South", Customers = new List<Customer>() { new Customer() { Name = "S1" } } });
foreach (Region Region in this.Regions)
foreach (Customer Customer in Region.Customers)
Customer.SetValue(CustomerDataHelper.ParentProperty, Region);
}
public ObservableCollection<Region> Regions { get; }
}
Клиенты .cs
public class Region : DependencyObject
{
public string Name { get; set; }
public List<Customer> Customers { get; set; }
}
public class Customer : DependencyObject
{
public string Name { get; set; }
}
CustomerDataHelper.cs
public class CustomerDataHelper : DependencyObject
{
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.RegisterAttached("IsChecked", typeof(bool?), typeof(CustomerDataHelper), new PropertyMetadata(false, new PropertyChangedCallback(OnIsCheckedPropertyChanged)));
public static void SetIsChecked(DependencyObject element, bool? IsChecked)
{
element.SetValue(CustomerDataHelper.IsCheckedProperty, IsChecked);
}
public static bool? GetIsChecked(DependencyObject element)
{
return (bool?)element.GetValue(CustomerDataHelper.IsCheckedProperty);
}
public static readonly DependencyProperty ParentProperty = DependencyProperty.RegisterAttached("Parent", typeof(object), typeof(CustomerDataHelper));
public static void SetParent(DependencyObject element, object Parent)
{
element.SetValue(CustomerDataHelper.ParentProperty, Parent);
}
public static object GetParent(DependencyObject element)
{
return (object)element.GetValue(CustomerDataHelper.ParentProperty);
}
private static void OnIsCheckedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Region && ((bool?)e.NewValue).HasValue)
foreach (Customer p in (d as Region).Customers)
CustomerDataHelper.SetIsChecked(p, (bool?)e.NewValue);
if (d is Customer)
{
int checkedCount = ((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as Region).Customers.Where(x => CustomerDataHelper.GetIsChecked(x) == true).Count();
int uncheckedCount = ((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as Region).Customers.Where(x => CustomerDataHelper.GetIsChecked(x) == false).Count();
if (uncheckedCount > 0 && checkedCount > 0)
{
CustomerDataHelper.SetIsChecked((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as DependencyObject, null);
return;
}
if (checkedCount > 0)
{
CustomerDataHelper.SetIsChecked((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as DependencyObject, true);
return;
}
CustomerDataHelper.SetIsChecked((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as DependencyObject, false);
}
}
}
Если я добавлю код ctor модели представления в код, стоящий за ctor, и запустится, он будет работать, и я смогу увидеть отображаемые элементы представления дерева , Не могу понять, что мне не хватает.