簡體   English   中英

我的treeView填充了一個奇怪的孩子:WPF MVVM

[英]My treeView populate a strange children : WPF MVVM

在這篇非常好的文章的幫助下,我構造了一個treeView WPF MVVM。然后,我為某些節點創建了一個contextMenu,允許我從選定的父級添加子級。

問題是,如果我沒有手動擴展所選節點(父級)就單擊“添加”,則除了單擊“添加”時預期會生成的節點外,還會自動創建一個奇怪的子級。

我試圖檢測到此問題,因此將以下代碼從以下位置更改:

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

至:

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

下圖1顯示了該測試的結果,圖2顯示了treeView必須顯示的內容。

  • 圖片1 在此處輸入圖片說明

  • image2

在此處輸入圖片說明

Rq:我使用了我談論的文章中的圖片。 另外,我使用了文章中介紹的相同方法(包括類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,除了我要創建的孩子,我還創建了另一個孩子

編輯我將下面的statemnt添加到我的add()方法中,現在我沒有任何問題:

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

我可以在您的代碼中看到該錯誤。

重現步驟如下:

  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); }
    }

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM