So I want the IsExpanded Property of the TreeView Item so be reflected in the datacontext.
<TreeView x:Name="TreeViewMonitorEvents" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Column="0" Grid.Row="1" Grid.RowSpan="5"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Page}, Path=MonitorEventCatagories}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type tree:TreeGroup}" ItemsSource="{Binding Members}" >
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" MouseMove="DragDrop_MouseMove_TreeGroup">
<CheckBox Name="CheckboxTreeGroup" IsChecked="{Binding Path=(tree:TreeItemHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Template="{DynamicResource MonitoringUICheckBox}" Style="{StaticResource MonitoringUICheckBoxStyling}"
MouseMove="DragDrop_MouseMove_TreeGroup" Checked="CheckboxTreeGroup_Checked" Unchecked="CheckboxTreeGroup_Unchecked">
</CheckBox>
<TextBlock Text="{Binding Name}" Style="{StaticResource MonitorUIText}" MouseMove="DragDrop_MouseMove_TreeGroup"/>
</StackPanel>
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" >
<Setter Property="IsExpanded" Value="{Binding IsExpanded,Mode=TwoWay}" />
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
</HierarchicalDataTemplate>
I.e the TreeGroup Class. See Treegroup here:
namespace RTX64MonitorUtility.TreeView
{
//Data class. Holds information in the Datacontext section of the UI Elements it is attached to.
public class TreeGroup : DependencyObject, IParent<object>
{
public string Name { get; set; }
public List<TreeMonitoringEvent> Members { get; set; }
public IEnumerable<object> GetChildren()
{
return Members;
}
public bool IsExpanded { get; set; } = false;
}
}
Here is the List it's drawing from:
namespace RTX64MonitorUtility.Pages
{
/// <summary>
/// Interaction logic for EventsAndTriggers.xaml
/// </summary>
public partial class EventsAndTriggers : Page
{
public ObservableCollection<TreeGroup> MonitorEventCatagories { get; set; }
...
}
}
My primary goal here is that if the TreeGroup Item is not expanded then the chidren's Checked
and Unchecked
events do not get triggered so I need to do the required actions for them. If I can find out a way of reading the IsExpanded
value from those events that would also be a solution.
CodePudding user response:
You usually bind the item container's properties like TreeViewItem.IsExpanded
or ListBoxItem.IsSelected
etc. to your data model by using a Style
that targets the item container. The DataContext
of the item container is the data model:
<TreeView>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Next, implement the data model properly. The properties that are the source of the data binding must be implemented as dependency properties (for dependency objects) or raise INotifyPropertyChanged.PropertyChanged
event.
Since DependencyObject
extends DispatcherObject
, any class that extends DependencyObject is thread affine: in WPF, a DispatcherObject
can only be accessed by the Dispatcher it is associated with.
For this reason you usually prefer INotifyPropertyChanged
on data models.
DependencyObject
is for UI objects that are bound to the Dispatcher
thread by definition.
// Let the model implement the INotifyPropertyChanged interface
public class TreeGroup : INotifyPropertyChanged, IParent<object>
{
// Follow this pattern for all properties that will change
// and are source of a data binding.
private bool isExpanded;
public IsExpanded
{
get => this.isExpanded;
set;
{
this.isExpanded = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
=> this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}