// // Copyright (c) Microsoft. All rights reserved. // // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.ComponentModel; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Controls; using System.Windows.Data; namespace HierarchicalDataTemplate { /// /// This sample shows how to bind the SelectedItem property of a TreeView to ... /// 1. A TextBox using XAML. This should use a Converter to take care for levels /// of the HierarchicalDataTemplates. /// 2. A DependencyProperty coded here to mock usage in a ViewModel. /// /// In both cases the TreeView.SelectedItem is used as Source with a OneWay /// binding to convince the Readonly handling to accept the binding. /// public partial class MainWindow : Window, INotifyPropertyChanged { //*---------------------------------------------------------------------------------------------* // >> DependencyProperty SelectedItem // The OnHasChange call back is used to get the value of the SelectedItem. This shows the // selection of different DataTemplates classes. This is taken from the official MS sample ;-) // This value is copied to a normal property "SelectedData" which notification ta a bound // Control. This is the second Textbox. // public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( "SelectedItem", typeof( object ), typeof( MainWindow ), new PropertyMetadata( new PropertyChangedCallback(OnHasChanged) ) ); private static void OnHasChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { if ((d as MainWindow).SelectedItem is League selectedLeague) { ((MainWindow)d).SelectedData = selectedLeague.Name; } if ((d as MainWindow).SelectedItem is Division selectedDivision) { ((MainWindow)d).SelectedData = selectedDivision.Name; } if ((d as MainWindow).SelectedItem is Team selectedTeam) { ((MainWindow)d).SelectedData = selectedTeam.Name; } if ((d as MainWindow).SelectedItem is TreeViewItem treeViewItem) { ((MainWindow)d).SelectedData = (treeViewItem.Header is string header) ? header : treeViewItem.Name; } } public object SelectedItem { get { return (object)GetValue( SelectedItemProperty ); } set { SetValue( SelectedItemProperty, value ); } } //*---------------------------------------------------------------------------------------------* // >> Other Fields and Properties // private Binding siBinding; private string selectedData; public string SelectedData { get => selectedData; private set { selectedData = value; Changed(); } } //*---------------------------------------------------------------------------------------------* // >> Constructor // The Aa... fields are used to sort these Properties at the top of the local view in debugger // private TreeViewItem AaTreeViewItem; private TreeView AaTreeView; public MainWindow() { InitializeComponent(); AaMain = this; AaTreeView = FindName( "TreeBase" ) as TreeView; AaTreeViewItem = FindName( "TreeItem" ) as TreeViewItem; } // *-------------------------------------------------------------------------------------* // >> Property Change Handling // public event PropertyChangedEventHandler PropertyChanged; protected void Changed( [CallerMemberName] string propertyName = null ) { PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( propertyName ) ); } // *-------------------------------------------------------------------------------------* // >> TreeView SelectedItemChanged Handling used to write a protocol // private void TreeView_SelectedItemChanged( object sender, RoutedPropertyChangedEventArgs e ) { if (sender is TreeView treeView) { Debug.Print( $">> (**) TreeView SelectedItem:{treeView.SelectedItem};" + $" SelectedValue:{treeView.SelectedValue}; SelectedValuePath:{treeView.SelectedValuePath};" + $" OldValue:{e.OldValue}; NewValue:{e.NewValue}; O-Source:{e.OriginalSource};" ); } } // *-------------------------------------------------------------------------------------* // >> Loaded Event // Used to generate a binding from this DP as a target to TreeView as a source // private void Window_Loaded( object sender, RoutedEventArgs e ) { siBinding = new Binding( "SelectedItem" ) { Mode = BindingMode.OneWay, Source = AaTreeView, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, IsAsync = true, TargetNullValue = string.Empty }; BindingExpression bindingExpression; bindingExpression = (BindingExpression)BindingOperations.SetBinding( AaMain, SelectedItemProperty, siBinding ); } // *-------------------------------------------------------------------------------------* // >> TargetUpdated Event - Refers to our DP here // Used to generate a break for further tracing // private void ShowItem_TargetUpdated( object sender, DataTransferEventArgs e ) { } } }