WPF:使用Treeview创建UserControl就像一个vanilla Treeview

时间:2013-12-31 21:03:44

标签: c# wpf xaml user-controls treeview

我正在学习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>

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

<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?

3 个答案:

答案 0 :(得分:2)

无法从外部访问子控件。一种方法是在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}"/>

答案 1 :(得分:1)

你的理由是正确的,因为它不起作用。 LabelI看不到SelectedItem属性。

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

<!--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>

对于这个例子,我使用的是StaticResource,它不是动态的...... BUT ,你所要做的就是绑定到itemsource。这是IMHO处理多个TreeView的最佳方式。

修改

再看一遍,我发现你更倾向于让usercontrol像树视图一样,而不仅仅是得到结果。

你无法完全按照UserControl进行操作。

你想要做的是创建一个扩展treeview的新类。它不需要是用户控件。

答案 2 :(得分:1)

尝试以下方式。

在用户控件中创建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>