CopyPastor

Detecting plagiarism made easy.

Score: 1; Reported for: Exact paragraph match Open both answers

Possible Plagiarism

Plagiarized on 2022-11-24
by Peregrine

Original Post

Original - Posted on 2015-10-20
by Chaitanya Kadamati



            
Present in both answers; Present only in the new answer; Present only in the old answer;

`TreeView.SelectedItem` is read only, so a value can't be pushed from the ViewModel.
The way I've handled this is via the use of a `Behavior` class.
1 - Create a base class for TreeView item data, that includes IsSelected and IsExpanded properties.
public class perTreeViewItemViewModelBase : perViewModelBase { private bool _isSelected;     public bool IsSelected { get => _isSelected; set => Set(nameof(IsSelected), ref _isSelected, value); }
private bool _isExpanded;     public bool IsExpanded { get => _isSelected; set => Set(nameof(IsExpanded), ref _isExpanded, value); }

... }
2 - Create a helper class for TreeView controls to implement the behavior, with a `BoundSelectedItem` attached property.
public class perTreeViewHelper : Behavior<TreeView> { public object BoundSelectedItem { get => GetValue(BoundSelectedItemProperty); set => SetValue(BoundSelectedItemProperty, value); }
public static readonly DependencyProperty BoundSelectedItemProperty = DependencyProperty.Register("BoundSelectedItem", typeof(object), typeof(perTreeViewHelper), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnBoundSelectedItemChanged));
private static void OnBoundSelectedItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { if (args.NewValue is perTreeViewItemViewModelBase item) { item.IsSelected = true; } }
protected override void OnAttached() { base.OnAttached(); AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged; }
protected override void OnDetaching() { AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged; base.OnDetaching(); }
private void OnTreeViewSelectedItemChanged(object obj, RoutedPropertyChangedEventArgs<object> args) { BoundSelectedItem = args.NewValue; } }
3 - Create styles for TreeViewItem and TreeView to bind the IsSelected property of the perTreeViewItemViewModelBase instance to the corresponding TreeViewItem property
<Style x:Key="perTreeViewItemContainerStyle" TargetType="{x:Type TreeViewItem}"> <!-- Link the properties of perTreeViewItemViewModelBase to the corresponding ones on the TreeViewItem --> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" /> <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
...
</Style>
<Style TargetType="{x:Type TreeView}"> <Setter Property="ItemContainerStyle" Value="{StaticResource perTreeViewItemContainerStyle}" /> </Style>
4 - In the View, use the behavior class to bind the BoundSelectedItem attached proprety to a corresponding property in the ViewModel
<TreeView ItemsSource="{Binding ...}">
<i:Interaction.Behaviors> <vhelp:perTreeViewHelper BoundSelectedItem="{Binding SelectedItem}" /> </i:Interaction.Behaviors>

For more details on my take on how to handle TreeView controls in a MVVM context (including check boxes for item selection and lazy loading of item data), check out my [blog post][1].

[1]: http://peregrinesview.uk/wpf-behaviors-part-2-treeview/
My requirement was for PRISM-MVVM based solution where a TreeView was needed and the bound object is of type Collection<> and hence needs HierarchicalDataTemplate. The default BindableSelectedItemBehavior wont be able to identify the child TreeViewItem. To make it to work in this scenario.
public class BindableSelectedItemBehavior : Behavior<TreeView> { #region SelectedItem Property
public object SelectedItem { get { return (object)GetValue(SelectedItemProperty); } set { SetValue(SelectedItemProperty, value); } }
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(BindableSelectedItemBehavior), new UIPropertyMetadata(null, OnSelectedItemChanged));
private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { var behavior = sender as BindableSelectedItemBehavior; if (behavior == null) return; var tree = behavior.AssociatedObject; if (tree == null) return; if (e.NewValue == null) foreach (var item in tree.Items.OfType<TreeViewItem>()) item.SetValue(TreeViewItem.IsSelectedProperty, false); var treeViewItem = e.NewValue as TreeViewItem; if (treeViewItem != null) treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true); else { var itemsHostProperty = tree.GetType().GetProperty("ItemsHost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (itemsHostProperty == null) return; var itemsHost = itemsHostProperty.GetValue(tree, null) as Panel; if (itemsHost == null) return; foreach (var item in itemsHost.Children.OfType<TreeViewItem>()) { if (WalkTreeViewItem(item, e.NewValue)) break; } } }
public static bool WalkTreeViewItem(TreeViewItem treeViewItem, object selectedValue) { if (treeViewItem.DataContext == selectedValue) { treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true); treeViewItem.Focus(); return true; } var itemsHostProperty = treeViewItem.GetType().GetProperty("ItemsHost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (itemsHostProperty == null) return false; var itemsHost = itemsHostProperty.GetValue(treeViewItem, null) as Panel; if (itemsHost == null) return false; foreach (var item in itemsHost.Children.OfType<TreeViewItem>()) { if (WalkTreeViewItem(item, selectedValue)) break; } return false; } #endregion
protected override void OnAttached() { base.OnAttached(); this.AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged; }
protected override void OnDetaching() { base.OnDetaching(); if (this.AssociatedObject != null) { this.AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged; } }
private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { this.SelectedItem = e.NewValue; } } This enables to iterate through all the elements irrespective of the level.

        
Present in both answers; Present only in the new answer; Present only in the old answer;