Я построил 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 должен показать.
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);
}
А где код? –
Я вижу, что вы привязываетесь к объекту ViewModel непосредственно в качестве отображаемого текста вашего узла в Image1. Результатом является просто ViewModel.ToString(). Мы не можем вам помочь, пока вы не разместите xmal и ViewModel для обзора – cscmh99
@ cscmh99, я дал вам статью, которую я использую для создания моего TreeView.Я использовал точно такой же код. Так почему я должен поместить свой код, если у нас есть весь исходный код. ! Не могли бы вы объяснить, что вы имели в виду под «Я напрямую привязываю объект ViewModel»! – xtensa1408