WPF TreeView HierarchicalDataTemplate获取TreeViewItem

时间:2010-07-04 08:07:29

标签: c# wpf treeview hierarchicaldatatemplate

我正在使用HierarchicalDataTemplate将我的类绑定到带有复选框的TreeView。我的代码工作正常,一切都很好,但我希望能够在树视图中获得一个项目的子项列表。

单击复选框时,我希望能够选择父节点和子节点。如果我有权访问应该包装复选框的TreeViewItem,那么我可以轻松地执行此操作,但Checkbox的Parent属性为null ...我似乎只能访问在HierarchicalDataTemplate中映射的类。

<TreeView Margin="12" Name="trv1" SelectedItemChanged="trv1_SelectedItemChanged">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type src:Location}" ItemsSource="{Binding Path=Sublocations}">
                <CheckBox Content="{Binding Name}" Tag="{Binding}" IsChecked="{Binding IsChecked}" Click="checkBox_Click"/>
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate DataType="{x:Type src:Sublocation}" ItemsSource="{Binding Path=Children}">
                <CheckBox Content="{Binding Name}" Tag="{Binding}" IsChecked="{Binding IsChecked}" Click="checkBox_Click"/>
            </HierarchicalDataTemplate>

            <DataTemplate DataType="{x:Type src:Child}">
                <CheckBox Content="{Binding Name}" Tag="{Binding}" IsChecked="{Binding IsChecked}" Click="checkBox_Click"/>
            </DataTemplate>

        </TreeView.Resources>
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsSelected" Value="{Binding IsChecked}"/>
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

4 个答案:

答案 0 :(得分:1)

您需要在TreeViewItem类中添加Children和Parent节点。您需要在初始化时设置父/子。

<HierarchicalDataTemplate x:Key="TreeViewItem" ItemsSource="{Binding Children}">
    <CheckBox Margin="2" IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Name}" />
</HierarchicalDataTemplate>
<TreeView ItemsSource="{Binding Countries}" ItemTemplate="{StaticResource TreeViewItem}" />

在你的viewModels中。

public class MainPageViewModel
{
    public ObservableCollection<Country> Countries {get;set;}
}

public class Country
{
    public string Name {get; set;}
    public bool IsChecked {get;set;}
    public IEnumerable<State> Children {get; set;}
    // Do not need parent for this.
}

public class State
{
    public string Name {get; set;}
    public bool IsChecked {get; set;}
    public Country Parent {get; set;}
    public IEnumerable<City> Children {get; set;}
}

public class City
{
    public string Name {get; set;}
    public bool IsChecked {get; set;} 
    public State Parent {get; set;}
}

答案 1 :(得分:0)

我想出了一个可能不是最佳解决方案的解决方案,但它确实有效。我在TreeView样式中添加了一个EventSetter,并为TreeViewItem对象分配了一个click事件。

            <TreeView.ItemContainerStyle>
                <Style TargetType="TreeViewItem">
                    <Setter Property="IsSelected" Value="{Binding IsChecked}"/>
                    <EventSetter Event="Selected" Handler="tvi_Selected"/>
                </Style>
            </TreeView.ItemContainerStyle>

这样我就可以访问发送者对象,它是一个TreeViewItem,并在节点中导航。

编辑: 这个“解决方案”只给了我最顶层的TreeViewItem对象,而不是选中的对象,它是对象的子对象。

编辑2: treeviewitems似乎实际上不允许我访问子treeviewitems或父treeviewitems。我想我错了。

答案 2 :(得分:0)

仅供参考:而不是必须获取TreeViewItem我发现最好在您的Nodes类中包含对模型中父级的引用:

Node.Parent {get{return this._parent;}}

然后在构建你的收藏时,你必须设置这些值,但它会使生活变得非常容易:想象得到你父母的任何级别:

myNode.Parent.Parent.Parent

获取TreeViewItem:(来自我的回答:How to get TreeViewItem from HierarchicalDataTemplate item?

我必须在路由的TreeViewItem.Selected事件中设置最后一个选定的TreeViewItem,它会冒泡到树视图(TreeViewItem本身在设计时不存在,因为我们使用的是HierarchicalDataTemplate)。

事件可以在XAML中捕获,如下所示:

然后可以在事件中设置最后选择的TreeViewItem:

private void TreeViewItemSelected(object sender, RoutedEventArgs e)
{
    TreeViewItem tvi = e.OriginalSource as TreeViewItem;

    // set the last tree view item selected variable which may be used elsewhere as there is no other way I have found to obtain the TreeViewItem container (may be null)
    this.lastSelectedTreeViewItem = tvi;

    ...
 }

答案 3 :(得分:0)

如果您想坚持MVVM pattern,您应该执行以下操作: 选择更改时触发命令(我在谈论TreeView.SelectedItemChanged事件)。

然后,使用此命令更新视图模型中的“SelectedItems”属性。

public class MyViewModel
{
    // your view model code...
    // ........................

    // this object better be more strongly typed
    private object _mySelectedItem; 

    public object MySelectedItem
    {
        get { return _mySelectedItem; }
        set { 
              _mySelectedItem = value;

              // the following method will handle the changed item. Problem solved              
              HandleTheNewChangedItem(value);
            }
    }
}