即使我的节点没有任何孩子,我的treeView的可扩展加号总是存在

时间:2015-10-09 21:03:20

标签: c# wpf mvvm treeview

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

问题是:当我创建一个新节点时,它带有可扩展的加号或我的新节点没有任何孩子!

我该如何纠正这个。

public class TreeViewItemViewModel : INotifyPropertyChanged
{ 
#region Data
    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>`

MyRegionViewModel(下面我添加了我的代码以创建contextMenu以添加子项以及上面的所有代码,您可以在article中找到它)

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

1 个答案:

答案 0 :(得分:1)

你可能真的需要更好地理解它的程序逻辑。

这是示例项目提供的“延迟加载功能”的问题

您可能已经注意到“可扩展指标”始终在地区和州级别可用,但在城市级别不可用。不同的是构造函数中的“islazyload”标志。这是所谓的通用树形图的设计问题,实际上ASSUME某些节点总是会有子节点,但是叶节点永远不会有子节点(CityViewModel)甚至没有实现LoadChildren方法来大声喊叫。

正如我上次提到的那样,对于“DummyChild”的存在,实施是非常讨厌的。 DummyChild是一个讨厌的黑客,该项目的创建者用于使父节点“假装”在节点“IsExpand”之前生成子节点,然后在IsExpand setter处加载真实子节点。让我再次强调它。我认为这是一个永远存在的可怕黑客。

要快速解决此问题,只需在所有级别将isLazyLoad标志设置为false,并在构造函数中加载所有子项。然后“可扩展指标”将反映节点的实际状态。