在代码隐藏中更改项目后刷新TreeView

时间:2018-10-17 08:38:10

标签: c# wpf treeview refresh treeviewitem

我面临一个问题。我在代码隐藏中使用TreeViewItem的不同阶段创建了TreeView。我添加了一个带有功能“添加项目”的ContextMenu。当我调用此函数时,我将创建一个新项并将其添加到TreeView中。 问题在于视图永远不会改变。 我确定新项目属于TreeViewItem的列表(我在调试时看过)。 我试过了:

adjustedMap

还有:

tree.Items.Refresh 

有我的代码:

this.UpdateLayout();

当我单击“验证”按钮时,它将启动此功能:

public void FillTree(TreeView tree, ObservableCollection<MyObject> nodes)
    {
        tree.Items.Clear();
        TreeViewItem Items= new TreeViewItem();
        Items.Header = "Items";
        TreeViewItem Item1;
        TreeViewItem Item2;
        for (int i = 0; i < nodes.Count; i++)
        {
            Item1 = new TreeViewItem();
            Item1.Header = nodes[i].Name;
            if(nodes[i].list != null && nodes[i].list.Count>0)
            {
                for(int j = 0; j < nodes[i].list.Count; j++)
                {
                     Item2 = new TreeViewItem();
                     Item2.Header = nodes[i].list[j].Name;
                     Item1.Items.Add(Item2);
                 }
             }
             Items.Items.Add(Items1);
        }
        tree.Items.Add(Items);
    }

如果有人有刷新视图的想法,对我会有很大帮助

先谢谢您

2 个答案:

答案 0 :(得分:0)

要将以上内容移到允许正确绑定数据的结构中,您需要在DataContext类中添加以下属性:

public ObservableCollection<TreeViewItemContext> Collection { get => this._Collection; set { this._Collection = value; this.RaisePropertyChanged(); } }
private ObservableCollection<TreeViewItemContext> _Collection;

TreeViewItemContext类必须看起来像这样才能迭代所有项目:

public class TreeViewItemContext
{
    public ObservableCollection<TreeViewItemContext> Children { get; }
    public MyObject Wrapped { get; }

    /* Other properties etc. go in here. */

    public TreeViewItemContext(MyObject wrapped)
    {
        this.Children = new ObservableCollection<TreeViewItemContext>();
        this.Wrapped = wrapped;
    }

    public IEnumerable<TreeViewItemContext> IterateTree()
    {
        yield return this;
        foreach (var tvic in this.Children)
        {
            foreach (var it in tvic.IterateTree())
            {
                yield return it;
            }
        }
    }
}

您的XAML代码将像这样简单:

<TreeView ItemsSource="{Binding Collection}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}>
            <Setter Property="Header" Value="{Binding Wrapped.Name}"/>
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.Resources>
        <HierarchialDataTemplate ItemsSource="{Binding Children}">
            <!-- Your DataTemplate-Content Goes In Here -->
        </HierarchialDataTemplate>
    </TreeView.Resources>
</TreeView>

然后要遍历TreeView中的所有项目,只需在主DataContext对象中执行Collection.SelectMany((it) => it.IterateTree())并对其进行处理即可。

然后执行此操作还可以使您通过向集合中添加/删除项目或仅创建一个新集合来“仅”更新集合。

RaisePropertyChanged方法顺便说一句。总是差不多:

public class AnyClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName]string callee = "") => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(callee));
    //...
}

您所有的“更新”问题都将消失。

答案 1 :(得分:0)

使用WPF的模板功能可以轻松解决此问题,而不必尝试构建整个UI。在代码中。

您已经有一个可观察的项目集合,因此只需将TreeView的ItemsSource设置为该项目即可。在树中,使用HierachicalDataTemplate指定每个项目的显示方式。

<TreeView.Resources>
    <HierarchicalDataTemplate DataType="{x:Type MyObject}"
                              ItemsSource="{Binding list}">
        <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>
</TreeView.Resources>

请注意,列表和名称必须是MyObject类的公共属性(而不是字段)。

这样,您可以根据需要具有任意数量的嵌套项目,而不仅限于代码将支持的两个子级别。

如果list也是一个可观察的集合,并且Name(以及您要显示的任何其他属性)实现了INotifyPropertyChanged模式,则在对MyObject项进行任何更改之后,TreeView显示将自动更新,而无需进一步的处理。 / p>

如果您想全力以赴并完全实现MVVM设计模式,那么可以在我的blog post上找到介绍。