я новичок в WPF mvvm, я создал древовидную структуру и хочу установить значение isSelected для определенного элемента древовидной структуры в этом дереве (например, элемент с «19-ASDFDSSD»), но я не знаю, как это сделать. Вы можете помочь мне? Любая помощь будет оценена.
TreeView.SelectedItem
доступен только для чтения, поэтому значение не может быть передано из ViewModel.
Я справился с этим с помощью класса Behavior
.
1. Создайте базовый класс для данных элемента TreeView, который включает свойства IsSelected и IsExpanded.
public class perTreeViewItemViewModelBase : perViewModelBase
{
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set => Set(nameof(IsSelected), ref _isSelected, value);
}
private bool _isExpanded;
public bool IsExpanded
{
get => _isSelected;
set => Set(nameof(IsExpanded), ref _isExpanded, value);
}
...
}
2. Создайте вспомогательный класс для элементов управления TreeView для реализации поведения с прикрепленным свойством BoundSelectedItem
.
public class perTreeViewHelper : Behavior<TreeView>
{
public object BoundSelectedItem
{
get => GetValue(BoundSelectedItemProperty);
set => SetValue(BoundSelectedItemProperty, value);
}
public static readonly DependencyProperty BoundSelectedItemProperty =
DependencyProperty.Register("BoundSelectedItem",
typeof(object),
typeof(perTreeViewHelper),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnBoundSelectedItemChanged));
private static void OnBoundSelectedItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (args.NewValue is perTreeViewItemViewModelBase item)
{
item.IsSelected = true;
}
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
}
protected override void OnDetaching()
{
AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
base.OnDetaching();
}
private void OnTreeViewSelectedItemChanged(object obj, RoutedPropertyChangedEventArgs<object> args)
{
BoundSelectedItem = args.NewValue;
}
}
3. Создайте стили для TreeViewItem и TreeView, чтобы привязать свойство IsSelected экземпляра perTreeViewItemViewModelBase к соответствующему свойству TreeViewItem.
<Style x:Key = "perTreeViewItemContainerStyle" TargetType = "{x:Type TreeViewItem}">
<!-- Link the properties of perTreeViewItemViewModelBase to the corresponding ones on the TreeViewItem -->
<Setter Property = "IsExpanded" Value = "{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property = "IsSelected" Value = "{Binding IsSelected, Mode=TwoWay}" />
...
</Style>
<Style TargetType = "{x:Type TreeView}">
<Setter Property = "ItemContainerStyle" Value = "{StaticResource perTreeViewItemContainerStyle}" />
</Style>
4. В представлении используйте класс поведения для привязки присоединенного свойства BoundSelectedItem к соответствующему свойству в ViewModel.
<TreeView ItemsSource = "{Binding ...}">
<i:Interaction.Behaviors>
<vhelp:perTreeViewHelper BoundSelectedItem = "{Binding SelectedItem}" />
</i:Interaction.Behaviors>
Для получения более подробной информации о моем понимании того, как обрабатывать элементы управления TreeView в контексте MVVM (включая флажки для выбора элемента и отложенную загрузку данных элемента), ознакомьтесь с моим сообщением в блоге.
Это должно сработать. Поместите первые две строки кода в метод. Treeview — это имя вашего дерева. Элемент из основного источника элементов (ваши данные)
var treeviewitem = GetTreeViewItem(treeview, item);
treeviewitem.IsSelected = true;
public TreeViewItem GetTreeViewItem(ItemsControl container, object item)
{
if (container != null)
{
if (container.DataContext == item)
return container as TreeViewItem;
container.ApplyTemplate();
ItemsPresenter itemsPresenter = (ItemsPresenter)container.Template.FindName("ItemsHost", container);
if (itemsPresenter != null)
{
itemsPresenter.ApplyTemplate();
}
else
{
itemsPresenter = FindVisualChild<ItemsPresenter>(container);
if (itemsPresenter == null)
{
container.UpdateLayout();
itemsPresenter = FindVisualChild<ItemsPresenter>(container);
}
}
Panel itemsHostPanel = (Panel)VisualTreeHelper.GetChild(itemsPresenter, 0);
UIElementCollection children = itemsHostPanel.Children;
foreach (TreeViewItem treeviewitem in children)
{
TreeViewItem resulttreeviewitem = SelectItem(treeviewitem, item);
if (resulttreeviewitem != null)
{
resulttreeviewitem.BringIntoView();
return resulttreeviewitem;
}
}
}
return null;
}
private static T FindVisualChild<T>(Visual visual) where T : Visual
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
{
Visual child = (Visual)VisualTreeHelper.GetChild(visual, i);
if (child != null)
{
T correctlyTyped = child as T;
if (correctlyTyped != null)
return correctlyTyped;
T descendent = FindVisualChild<T>(child);
if (descendent != null)
return descendent;
}
}
return null;
}
Большое спасибо, ваше решение немного сложно для меня, но я, гость, знаю, как оно работает. Чтобы упростить ваше решение, я добавил логический атрибут «IsSelected» в свой класс JobsDTO и добавил <Setter Property = «IsSelected» Value = «{Binding IsSelected»> в свой wpf. Итак, если я хочу установить выбранное задание в моем представлении в виде дерева , я изменю его на истину.