Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

Програмно снять выделение с TreeView

#c_sharp #wpf #treeview


Необходимо снять выделение с TreeView при удалении элемента. По умолчанию выделяется
первый элемент, а задать SelectedItem = null не получается так как это свойство только
для чтения. Как это реализовать?
    


Ответы

Ответ 1



В обычном случае вы не создаёте элементы TreeView вручную, а генерируете их автоматически, используя ItemsSource + ItemTemplate. При этом treeView.SelectedItem будет не TreeViewItem, а элемент коллекции, привязанной к ItemsSource. Так что приведение к типу TreeViewItem не сработает. Чтобы получить из этого собственно визуальный элемент, обычно применяется конструкция list.ItemContainerGenerator.ContainerFromItem(selectedItem);. Но в случае TreeView она, к сожалению, работает лишь на верхнем уровне: каждый TreeViewItem рекурсивно сам является TreeView, и заботится сам о своих контейнерах, так что list.ItemContainerGenerator ничего не знает о вложенных частях дерева. Неплохое универсально работающее (но многословное) решение — следить за изменением выделенного элемента, и запоминать его в code behind. Пример: public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new[] { new DataHolder("Привет-привет", null), new DataHolder("Пока-пока", null), new DataHolder(null, new[] { new DataHolder("Я очень", null), new DataHolder("буду ждать", new[] { new DataHolder("звонка", null) }), }), }; TreeViewItem selectedItemTV = null; TV.AddHandler(TreeViewItem.SelectedEvent, (RoutedEventHandler)((sender, args) => selectedItemTV = (TreeViewItem)args.OriginalSource)); TreeViewItem selectedItemTV2 = null; TV2.AddHandler(TreeViewItem.SelectedEvent, (RoutedEventHandler)((sender, args) => selectedItemTV2 = (TreeViewItem)args.OriginalSource)); var dt = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(5) }; dt.Tick += (sender, args) => { if (selectedItemTV != null) { selectedItemTV.IsSelected = false; selectedItemTV = null; } if (selectedItemTV2 != null) { selectedItemTV2.IsSelected = false; selectedItemTV2 = null; } }; dt.Start(); } } public class DataHolder { public string Key { get; private set; } public IEnumerable Value { get; private set; } public DataHolder(string key, IEnumerable value) { Key = key; Value = value; } } Ну или вы можете подписаться обычным способом в XAML'е: TreeViewItem.Selected="TVItemSelected". Ещё есть решение с полным рекурсивным обходном дерева, и поиском TreeViewItem'а, как описано здесь. Но оно мне кажется слишком уж неэффективным, и наверняка плохо дружит с виртуализацией.

Ответ 2



Реализовал так: ((TreeViewItem)treeView.SelectedItem).IsSelected = false;

Комментариев нет:

Отправить комментарий