[英]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必須顯示的內容。
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>
`公共類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);
}
我可以在您的代碼中看到該錯誤。
重現步驟如下:
因此,基本上,這就是為什么首先“擴展”是您的問題的關鍵所在,因為那時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.