Reputation: 402
I have a custom control named CustomTreeView
which contains a TreeView
. I would like to expose the SelectedItem
Property of the TreeView
to users of the custom control.
For that I tried to add a new dependency property to the custom control and bind that property to the SelectedItem
Property of the TreeView
.
Unfortunatly I seem to be getting it wrong. Could you take a look?
TreeView.xaml
<UserControl x:Class="Fis.UI.Windows.BacNet.Views.RestructuredView.View.Controls.CustomTreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Selected="{Binding ElementName=treeView, Path=SelectedItem}">
<TreeView x:Name="treeView"/>
</UserControl>
TreeView.xaml.cs
public partial class CustomTreeView : UserControl
{
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
"Selected", typeof(Node),
typeof(TreeView)
);
public Node Selected
{
get { return (Node)GetValue(IsSelectedProperty); }
set { SetValue(IsSelectedProperty, value); }
}
public TreeView()
{
InitializeComponent();
}
}
Thanks!
Upvotes: 0
Views: 161
Reputation: 37059
Part of your solution is in this answer here. It's a link-only answer with a dead link (or was -- I just improved it), but it does mention the key point.
You can't bind TreeView.SelectedItem
. Your dependency property definition is broken in multiple ways and it should be named SelectedItem
in accordance with standard WPF practice. Here's the usercontrol code behind, which defines the dependency property along with event handlers as a substitute for the binding.
public partial class CustomTreeView : UserControl
{
public CustomTreeView()
{
InitializeComponent();
}
#region SelectedItem Property
public Node SelectedItem
{
get { return (Node)GetValue(SelectedProperty); }
set { SetValue(SelectedProperty, value); }
}
public static readonly DependencyProperty SelectedProperty =
DependencyProperty.Register(nameof(SelectedItem), typeof(Node), typeof(CustomTreeView),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
Selected_PropertyChanged)
{ DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
protected static void Selected_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as CustomTreeView).OnSelectedChanged(e.OldValue);
}
private void OnSelectedChanged(object oldValue)
{
if (SelectedItem != treeView.SelectedItem)
{
var tvi = treeView.ItemContainerGenerator.ContainerFromItem(SelectedItem) as TreeViewItem;
if (tvi != null)
{
tvi.IsSelected = true;
}
}
}
#endregion SelectedItem Property
private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (SelectedItem != e.NewValue)
{
SelectedItem = e.NewValue as Node;
}
}
}
And here's the TreeView in the UserControl XAML. I'm omitting ItemsSource and ItemTemplate as irrelevant.
<TreeView
x:Name="treeView"
SelectedItemChanged="treeView_SelectedItemChanged"
/>
And here's the snippet from MainWindow.xaml I used for testing it:
<StackPanel>
<local:CustomTreeView x:Name="treeControl" />
<Label
Content="{Binding SelectedItem.Text, ElementName=treeControl}"
/>
</StackPanel>
My Node
class has a Text
property and I'm populating the tree via the DataContext to save having to set up another dependency property for the items.
Upvotes: 1