【问题标题】:WPF: Make a UserControl with a Treeview behave like a vanilla TreeviewWPF:使带有 Treeview 的 UserControl 表现得像普通的 Treeview
【发布时间】:2014-01-18 17:35:03
【问题描述】:

我正在学习 WPF,但我认为我在用户控件方面缺少一些东西。我将尝试通过示例进行演示。基本上,假设我有一个树视图,并且我想将标签文本绑定到树视图 selectedItem。这看起来很简单:

<!-- Window.xaml -->
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="100" />
    </Grid.RowDefinitions>

    <TreeView Name="MyTreeView">
        <TreeViewItem Header="Root">
            <TreeViewItem Header="Item1"></TreeViewItem>
            <TreeViewItem Header="Item2"></TreeViewItem>
        </TreeViewItem>
    </TreeView>

    <Label Content="{Binding ElementName=MyTreeView, Path=SelectedItem.Header}" Grid.Row="1"></Label>
</Grid>

现在,为了使事情复杂化,我将添加一个用户控件。用户控件基本上是网格中的 TreeView:

<!-- ExampleUserControl.xaml -->
<UserControl>
    <Grid>
        <TreeView Name="UserControlTreeView">
            <TreeViewItem Header="Root">
                <TreeViewItem Header="Item1"></TreeViewItem>
                <TreeViewItem Header="Item2"></TreeViewItem>
            </TreeViewItem>
        </TreeView>
    </Grid>
</UserControl>

目的是用用户控件替换上面使用的香草树视图,并根据选择的内容更改标签内容。所以,我尝试这样的事情:

<Window>    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>

        <local:ExampleUserControl1 x:Name="MyUserControl">            
        </local:ExampleUserControl1>

        <Label Content="{Binding ElementName=MyUserControl, Path=SelectedItem.Header}" Grid.Row="1"></Label>
    </Grid>
</Window>

这会编译并运行,但是当我在树视图中选择项目时,标签不会改变。我想我明白为什么:用户控件包含树视图,但显然不是树视图。我不确定解决此问题的最佳方法。我能想到一种似乎有问题的方法:

  • 在代码中向用户控件添加属性“SelectedItem”,以返回树视图中的选定项。

这适用于一个或几个属性,但是为树视图中的每个属性执行此操作的想法似乎严重浪费了代码和时间。有什么方法可以继续使用用户控件,但让它表现得像一个普通的 TreeView?

【问题讨论】:

    标签: c# wpf xaml user-controls treeview


    【解决方案1】:

    无法像这样从外部访问子控件。一种方法是在SelectedItem 的代码中包含包装器属性,并从您已经提到的外部绑定到该属性。

    但我建议使用 UserControl 的 Tag 属性来包含 TreeView 的引用并从外部绑定到 Tag 属性。这样您就不必在后面的代码中创建多个属性。

    使用x:Reference绑定到TreeView:

    <UserControl Tag="{Binding Source={x:Reference UserControlTreeView}}">
        <Grid>
            <TreeView Name="UserControlTreeView">
                <TreeViewItem Header="Root">
                    <TreeViewItem Header="Item1"></TreeViewItem>
                    <TreeViewItem Header="Item2"></TreeViewItem>
                </TreeViewItem>
            </TreeView>
        </Grid>
    </UserControl>
    

    现在绑定标签控件:

    <Label Content="{Binding ElementName=MyUserControl,
                             Path=Tag.SelectedItem.Header}"/>
    

    【讨论】:

    • 这很酷。没想到你可以这样使用绑定标签。
    • 这就是 XAML 的美妙之处。
    【解决方案2】:

    试试下面的方法。

    在您的用户控件中创建 TreeView 类型的公共属性并返回树视图,如下所示。

        //ExampleUserControl.xaml.cs
        public TreeView UTreeView
        {
            get
            {
                return UserControlTreeView;
            }
        }
    

    然后在 Window.xaml 中使用此属性,如下所示。

      <local:ExampleUserControl1 x:Name="MyUserControl">
        </local:ExampleUserControl1>
    
        <Label Content="{Binding ElementName=MyUserControl, Path=UTreeView.SelectedItem.Header}" Grid.Row="1"></Label>
    

    【讨论】:

    • 哇,这非常简单。我觉得我想太多了。标记为答案,因为它可以很容易地扩展到用户控件中的其他控件。
    【解决方案3】:

    您对为什么它不起作用的推理是正确的。 SelectedItem 属性对标签不可见。

    您可以像平常一样使用 TreeView,但要绑定到它的 ItemsSource,而不是使用 UserControl 来简单地托管 TreeView。例如:

    <!--MainWindow.xaml-->
    <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:coll="clr-namespace:System.Collections;assembly=mscorlib"
        Title="MainWindow" Height="350" Width="525">
        <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
            <Grid.Resources>
            <coll:ArrayList x:Key="data">
                <TreeViewItem Header="Parent 1">
                    <TreeViewItem Header="Child 1"/>
                    <TreeViewItem Header="Child 2"/>
                </TreeViewItem>
                <TreeViewItem Header="Parent 2">
                    <TreeViewItem Header="Child 1"/>
                    <TreeViewItem Header="Child 2"/>
                </TreeViewItem>
            </coll:ArrayList>
        </Grid.Resources>
    
        <TreeView Grid.Row="0" ItemsSource="{StaticResource data}" x:Name="tv1"/>
    
        <Label Grid.Row="1" Content="{Binding ElementName=tv1, Path=SelectedItem.Header}"/>
        </Grid>
    </Window>
    

    对于这个例子,我使用的是静态资源,它不是动态的……但是,你所要做的就是绑定到 itemsource。恕我直言,这是处理多个 TreeViews 的最佳方式。

    编辑:

    再看一遍,我发现您更想使用户控件表现得像树视图,而不仅仅是获得结果。

    你不能完全用 UserControl 做你所说的。

    您想要做的是创建一个扩展树视图的新类。它不需要是用户控件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-31
      • 1970-01-01
      相关资源
      最近更新 更多