2015-10-08 6 views
0

Я построил treeView WPF MVVM с помощью этого очень хорошего article Затем я создал contextMenu для некоторого узла, что позволило мне добавить детей из выбранного родителя.My treeView населяет странных детей: WPF MVVM

Проблема заключается в том, что если я нажимаю «Добавить», не разворачивая вручную выбранный узел (родительский), в дополнение к узлу, который, как ожидается, будет создан при нажатии «Добавить», автоматически создается дополнительный ребенок.

Я пытался обнаружить проблему, так что я изменить код ниже от:

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

к:

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

Изображение 1 ниже показывает результат этого теста или Image 2 показывает, что мой TreeView должен показать.

  • image1 enter image description here

  • image2

enter image description here

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, у меня есть еще один ребенок, созданный в дополнение к ребенку, который я хочу t о создании

EDIT добавляет statemnt ниже мое дополнение() метод, и у меня нет никакой проблемы в настоящее время:

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

А где код? –

+0

Я вижу, что вы привязываетесь к объекту ViewModel непосредственно в качестве отображаемого текста вашего узла в Image1. Результатом является просто ViewModel.ToString(). Мы не можем вам помочь, пока вы не разместите xmal и ViewModel для обзора – cscmh99

+0

@ cscmh99, я дал вам статью, которую я использую для создания моего TreeView.Я использовал точно такой же код. Так почему я должен поместить свой код, если у нас есть весь исходный код. ! Не могли бы вы объяснить, что вы имели в виду под «Я напрямую привязываю объект ViewModel»! – xtensa1408

ответ

1

Я вижу ошибку в коде.

Вот шаги для воспроизведения:

  1. На государственном узле (не расширять его первым)
  2. без расширения Ребенок заранее, дети вашего StateViewModel содержат в DummyChild.
  3. Добавлен 1 новый Город в список, который вызывает HasDummyChild, не будет работать, так как счет теперь 2 в списке детей
  4. Затем, когда вы пытаетесь развернуть узел, чтобы проверить результат. Ваш TreeList будет иметь DummyChild, который является базовым классом, который облажался все

Таким образом, в основном, именно поэтому «Expand» первый ключ вашей проблемы, как в то время HasDummyChild по-прежнему работает, как он сравнивает .Count == 1. дерево не удалит DummyChild из вашего списка детей, если добавить еще один ребенок в список, который делает .Count == 2.

дополнительную информацию по запросу

Просто измените HasDummyChild в качестве следующие

enter image description here

+0

Я не уверен, что хорошо понимаю, что вы говорите. но я знаю, что вы даете мне представление о том, что я его реализую, и я исправляю pb (см. выше), но я все еще хочу знать, как не найти проблему, когда вы играете с образцом. Не могли бы вы отредактировать свой ответ и поместить свой код. (только модификация, которую вы добавили, и я попытаюсь проверить ее в проекте из статьи) – xtensa1408

+0

Я не могу понять, почему мой ответ не мог объяснить, что происходит, но в любом случае предоставит вам исправление. – cscmh99

+0

Просто, чтобы быть уверенным, что вы серьезно относитесь к этому, я действительно переместил ваш код и воспроизвел вашу ошибку. Итак, прочитайте мое описание снова, пытаясь понять, что я положил в ответ – cscmh99