简体   繁体   中英

How to properly expose properties of internal controls?

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!

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM