【问题标题】:My treeView populate a strange children : WPF MVVM我的 treeView 填充了一个奇怪的孩子:WPF MVVM
【发布时间】:2015-10-08 23:10:45
【问题描述】:

我在这个非常好的article 的帮助下构建了一个 treeView WPF MVVM 然后我为某个节点创建了一个 contextMenu,允许我从选定的父节点添加子节点。

问题是如果我点击“添加”而不手动展开选定的节点(父节点),除了点击“添加”时预期生成的节点外,还会自动创建一个奇怪的子节点。

我试图检测问题,因此我将以下代码更改为:

<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />

到:

<Setter Property="IsExpanded" Value="True" />

下面的图 1 显示了此测试的结果,或者图 2 显示了我的 treeView 必须显示的内容。

  • 图像1

  • image2

Rq:我使用了我谈到的article 中的图像。另外,我使用了文章中描述的相同方法(包括类 TreeViewItemViewModel.cs )

  • 所有 ViewModel 的基类

    公共类 TreeViewItemViewModel : INotifyPropertyChanged { #region 数据

    static readonly TreeViewItemViewModel DummyChild = new TreeViewItemViewModel();
    
    readonly ObservableCollection<TreeViewItemViewModel> _children;
    readonly TreeViewItemViewModel _parent;
    
    bool _isExpanded;
    bool _isSelected;
    
    #endregion // Data
    
    #region Constructors
    
    protected TreeViewItemViewModel(TreeViewItemViewModel parent, bool lazyLoadChildren)
    {
        _parent = parent;
    
        _children = new ObservableCollection<TreeViewItemViewModel>();
    
        if (lazyLoadChildren)
            _children.Add(DummyChild);
    }
    
    // This is used to create the DummyChild instance.
    private TreeViewItemViewModel()
    {
    }
    
    #endregion // Constructors
    
    #region Presentation Members
    
    #region Children
    
    /// <summary>
    /// Returns the logical child items of this object.
    /// </summary>
    public ObservableCollection<TreeViewItemViewModel> Children
    {
        get { return _children; }
    }
    
    #endregion // Children
    
    #region HasLoadedChildren
    
    /// <summary>
    /// Returns true if this object's Children have not yet been populated.
    /// </summary>
    public bool HasDummyChild
    {
        get { return this.Children.Count == 1 && this.Children[0] == DummyChild; }
    }
    
    #endregion // HasLoadedChildren
    
    #region IsExpanded
    
    /// <summary>
    /// Gets/sets whether the TreeViewItem 
    /// associated with this object is expanded.
    /// </summary>
    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
            if (value != _isExpanded)
            {
                _isExpanded = value;
                this.OnPropertyChanged("IsExpanded");
            }
    
            // Expand all the way up to the root.
            if (_isExpanded && _parent != null)
                _parent.IsExpanded = true;
    
            // Lazy load the child items, if necessary.
            if (this.HasDummyChild)
            {
                this.Children.Remove(DummyChild);
                this.LoadChildren();
            }
        }
    }
    
    #endregion // IsExpanded
    
    #region IsSelected
    
    /// <summary>
    /// Gets/sets whether the TreeViewItem 
    /// associated with this object is selected.
    /// </summary>
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (value != _isSelected)
            {
                _isSelected = value;
                this.OnPropertyChanged("IsSelected");
            }
        }
    }
    
    #endregion // IsSelected
    
    #region LoadChildren
    
    /// <summary>
    /// Invoked when the child items need to be loaded on demand.
    /// Subclasses can override this to populate the Children collection.
    /// </summary>
    protected virtual void LoadChildren()
    {
    }
    
    #endregion // LoadChildren
    
    #region Parent
    
    public TreeViewItemViewModel Parent
    {
        get { return _parent; }
    }
    
    #endregion // Parent
    
    #endregion // Presentation Members
    
    #region INotifyPropertyChanged Members
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    
    #endregion // INotifyPropertyChanged Members
    

    }

  • Myxml:

<TreeView ItemsSource="{Binding Regions}" IsEnabled="{Binding EnableTree}" > <TreeView.ItemContainerStyle> <!-- This Style binds a TreeViewItem to a TreeViewItemViewModel. --> <Style TargetType="{x:Type TreeViewItem}"> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" /> <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" /> <Setter Property="FontWeight" Value="Normal" /> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="FontWeight" Value="Bold" /> </Trigger> </Style.Triggers> </Style> </TreeView.ItemContainerStyle> <TreeView.Resources> <ContextMenu x:Key="AddCity" ItemsSource="{Binding AddCityItems}"/> <HierarchicalDataTemplate DataType="{x:Type local:StateViewModel}" ItemsSource="{Binding Children}" > <StackPanel Orientation="Horizontal" ContextMenu="{StaticResource AddCity}"> <Image Width="16" Height="16" Margin="3,0" Source="Images\Region.png" /> <TextBlock Text="{Binding RegionName}" /> </StackPanel> </HierarchicalDataTemplate> </TreeView.Resources>

  • RegionViewModel:

`公共类StateViewModel:TreeViewItemViewModel {

   readonly State _state;
   public ICommand AddCityCommand { get; private set; }
   public List<MenuItem> AddCityItems { get; set; }

    public StateViewModel(State state, RegionViewModel parentRegion)
        : base(parentRegion, true)
    {
        _state = state;
        AddCityItems = new List<MenuItem>();
        AddCityCommand = new DelegateCommand<CancelEventArgs>(OnAddCityCommandExecute, OnAddCityCommandCanExecute);
        AddCityItems.Add(new MenuItem() { Header = "Add City", Command = AddCityCommand });
    }

    public string StateName
    {
        get { return _state.StateName; }
    }

    protected override void LoadChildren()
    {
        foreach (City city in Database.GetCities(_state))
            base.Children.Add(new CityViewModel(city, this));
    }


    bool OnAddCityCommandCanExecute(CancelEventArgs parameter)
    {
        return true;
    }

    public void OnAddCityCommandExecute(CancelEventArgs parameter)
    {
        var myNewCity = new city();
        Children.Add(new CityViewModel(myNewCity, this));
    }
}`

顺便说一句,如果我展开我的父节点然后我点击添加城市,我得到了预期的结果,但是如果我不展开父节点并且我点击 contextMenu,除了我想要的孩子之外,我还创建了另一个孩子创建

编辑 我将下面的语句添加到我的 add() 方法中,现在我没有任何问题:

public void OnAddCityCommandExecute(CancelEventArgs parameter)
    {
        var myNewCity = new city();
        Children.Add(new CityViewModel(myNewCity, this));
        //the modif
        this.Children.Remove(DummyChild);
    }

【问题讨论】:

  • 代码在哪里?
  • 我可以看到您直接绑定到 ViewModel 对象,因为您的节点在 Image1 中显示文本。输出只是 ViewModel.ToString()。在您将 xmal 和 ViewModel 进行审核之前,我们无法为您提供帮助
  • @cscmh99,我给了你我用它来创建我的 TreeView 的文章。我使用了完全相同的代码。那么,如果我们拥有所有源代码,我为什么要放置我的代码。 !您能否解释一下“我直接绑定 ViewModel 对象”是什么意思!
  • @EmpereurAiman 你可以打开上面的文章
  • @SADOK 您可以发布最低限度的代码让我们理解,而无需阅读一篇大文章。请参阅:stackoverflow.com/help/mcve

标签: c# wpf xaml mvvm treeview


【解决方案1】:

我可以在您的代码中看到错误。

重现的步骤如下:

  1. 在状态节点(切勿先展开)
  2. 如果不预先扩展子级,您的 StateViewModel 的子级包含一个 DummyChild。
  3. 在列表中添加了 1 个新城市,导致 HasDummyChild 无法工作,因为现在儿童列表中的计数为 2
  4. 然后当你尝试展开节点来检查结果。您的树列表将包含 DummyChild,它是一个搞砸一切的基类

所以,基本上这就是为什么“扩展”首先是您问题的关键,因为当时 HasDummyChild 在比较 .Count == 1 时仍然有效。如果您添加,树不会从您的孩子列表中删除 DummyChild使 .Count == 2 的列表中多了一个孩子。

根据要求提供附加信息

只需将 HasDummyChild 更改如下

    public bool HasDummyChild
    {
        //get { return this.Children.Count == 1 && this.Children[0] == DummyChild; }
        get { return Children.Any() && Children.Contains(DummyChild); }
    }

【讨论】:

  • 我不确定我是否完全理解你所说的。但是我知道您给了我一个想法,我实现了它并纠正了 pb(请参见上面的编辑),但我仍然想知道当您使用示例时没有发现问题。您能否编辑您的答案并输入您的代码。 (只是您添加的修改,我将尝试在文章中的项目中对其进行测试)
  • 我无法弄清楚为什么我的回答无法解释正在发生的事情,但无论如何都会为您提供解决方案。
  • 为了确保您认真对待这一点,我实际上迁移了您的代码并重现了您的错误。所以,再次阅读我的描述,试图理解我在答案中的内容
  • 哦......我想我没有在评论中回答你的问题。这仅仅是因为我认为在 Children 中预先设置一个 DummyChild 在我眼中是如此令人讨厌并删除所有这些相关代码(这只是一种习惯)。所以我没有像你一样的问题。 Com'on ...我是唯一一个怀疑您的添加节点实现并猜测有一个错误类型的实例被添加到列表中的人,您不认为这是出于某种原因吗? =)..无论如何..我的答案在哪里??
  • 你也应该得到一个赞成票。我还有另外两个关于 TreeView 的问题。我构建了我所有的节点并且知道我试图纠正一些像这个问题这样的错误。所以我会提出另一个问题,我会建议你。
猜你喜欢
  • 2021-10-10
  • 2012-01-28
  • 1970-01-01
  • 2016-12-30
  • 2011-08-22
  • 2017-05-25
  • 2015-10-28
  • 2017-08-03
  • 1970-01-01
相关资源
最近更新 更多