Необходимо снять выделение с 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'а,
как описано здесь. Но оно мне кажется слишком уж неэффективным, и наверняка плохо дружит
с виртуализацией.
Как можно сделать такие полосы (штриховку) в TreeView?
Перегуглил как мог, нигде и намёка нет на подобную штуку
javafx:
swing:
Ответы
Ответ 1
Очень просто:
TreeItem item=new TreeItem(new HBox(new ImageView(new Image(inputStream)),new
Label("Root")));
item.getChildren().add(new TreeItem(new HBox(new ImageView(new Image(inputStream)),new
Label("Item1"))));
TreeView treeView=new TreeView(item);
При желании можно сделать вместо HBox класс, который будет автоматически менять изображение
в зависимости от строения TreeItem.
Здравствуйте, имею в своём приложении собственный обозреватель папок. В целом он
функционирует хорошо, но есть один недочёт: если нажать на тот, или иной TreeViewItem,
то он обводиться стандартным и не красивым синим прямоугольником. Как это можно изменить?
Надо заменить этот прямоугольник чем-то...
Ответы
Ответ 1
Элементы TreeView неявно (или явно, если ваш код это указывает) кладутся в TreeViewItem.
Визуализация выбранных элементов/элементов с фокусом делается в TreeViewItem'е. То
есть, вам нужно переопределить, как он выглядит.
Насколько я понимаю, для этого вам нужно поменять его стиль (ItemContainerStyle),
причём целиком. Кажется, нет возможности подменять лишь часть стиля. Вот здесь дан
код, как этот стиль определён по умолчанию. (Ищите Style TargetType="controls:TreeViewItem".)
Определение реально большое, но правильное.
Его можно переопределить например так, как описано здесь (хотя техника немного устарела:
вместо триггеров нужно бы использовать VisualState). Или вы можете базироваться на
стиле по умолчанию, и подменить нужные части.
Ответ 2
Вам следует переопределить системный цвет, который хранится в ресурсе SystemColors.HighlightBrushKey
на который и ссылается стандартный стиль TreeViewItem. Пример:
Ветки нужно перемещать ноды на уровень выше в материнские и ниже в дочерние.
Моё дерево:
На другом примере работает нормально но в моём нет.
1
-2
--3
4
-5
--6
У меня любую ноду можно переместить в корень или в ту же ноду, в которой и находится.
Например 3 можно переместить в корень либо в 2, где он уже есть.
В другие почему-то не перемещается.
public class Node
{
public string name_ { get; set; }
public ObservableCollection collection_node { get; set; }
public Node()
{
collection_node = new ObservableCollection();
}
}
Ответы
Ответ 1
Рекомендую использовать GongSolutions.WPF.DragDrop, которую можно легко установить
добавив соответствующий NuGet-пакет.
Дальше к своему TreeViewпросто добавляете два свойства:
где dd:
xmlns:dd="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop"
Теперь вы можете легко перетаскивать элементы:
Пытаюсь разобраться с привязкой "горячих" клавиш к дереву. Не получается передать в качестве параметра к команде саму выбранную ветку дерева. Хочу, чтобы при нажатии F2 открывалось окно редактирования наименования ветки дерева (или даже лучше не отдельного окна, а напрямую в самом дереве, но с этим как мне показалось еще более сложно. Хотя бы через дополнительное окно) На текущий момент через контекстное меню работает правильно, так как к каждому элементу дерева привязано свое контекстное меню и в качестве параметра эта ветка и передается. А вот с привязкой команды по горячей кнопке для меня оказалось сложнее. Команда объявлена в окне: Горячая клавиша объявлена в дереве: В качестве контекста у дерева в инициализации формы присваивается список: tp_View.DataContext = TPTree; public ObservableCollection TPTree = new ObservableCollection();
Который отдельно заполняется через другие команды. Что необходимо передать в CommandParameter, чтобы в команду e.Parameter помещался не весь список дерева, а только выбранный в данный момент? Или нужно делать вообще по другому и я не в ту сторону копаю? PS: Команда должна привязываться именно к дереву, так как на форме будет несколько деревьев и у каждого клавиша F2 должна вызывать редактирование именно своей ветки. Спасибо.
Ответ
У вас команда привязана ко всему TreeView, соответственно Binding возвращает TreeView.DataContext, а он может быть каким угодно. Решение очевидное - передавать явно текущий элемент TreeView Ну и так как при активном TreeView выбранного элемента может не быть - вы должны в коде команды первым делом проверить параметр: void RenameNode(NodeVm node)
{
if (node == null) return;
Либо составить правильный CanExecute, но это сложнее, думаю.
Так как же все-таки реализовать редактирование элемента прямо в дереве? Давайте попробуем сделать это! Я воспользуюсь паттерном MVVM, у меня есть соответствующие заготовки для классов команды: class DelegateCommand : ICommand
{
protected readonly Predicate
Необходимо снять выделение с TreeView при удалении элемента. По умолчанию выделяется первый элемент, а задать SelectedItem = null не получается так как это свойство только для чтения. Как это реализовать?
Ответ
В обычном случае вы не создаёте элементы 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'а, как описано здесь. Но оно мне кажется слишком уж неэффективным, и наверняка плохо дружит с виртуализацией.
Как можно сделать такие полосы (штриховку) в TreeView?
Перегуглил как мог, нигде и намёка нет на подобную штуку javafx:
swing:
Ответ
Очень просто: TreeItem item=new TreeItem(new HBox(new ImageView(new Image(inputStream)),new Label("Root")));
item.getChildren().add(new TreeItem(new HBox(new ImageView(new Image(inputStream)),new Label("Item1"))));
TreeView treeView=new TreeView(item);
При желании можно сделать вместо HBox класс, который будет автоматически менять изображение в зависимости от строения TreeItem.
Здравствуйте, имею в своём приложении собственный обозреватель папок. В целом он функционирует хорошо, но есть один недочёт: если нажать на тот, или иной TreeViewItem, то он обводиться стандартным и не красивым синим прямоугольником. Как это можно изменить? Надо заменить этот прямоугольник чем-то...
Ответ
Элементы TreeView неявно (или явно, если ваш код это указывает) кладутся в TreeViewItem. Визуализация выбранных элементов/элементов с фокусом делается в TreeViewItem'е. То есть, вам нужно переопределить, как он выглядит. Насколько я понимаю, для этого вам нужно поменять его стиль (ItemContainerStyle), причём целиком. Кажется, нет возможности подменять лишь часть стиля. Вот здесь дан код, как этот стиль определён по умолчанию. (Ищите Style TargetType="controls:TreeViewItem".) Определение реально большое, но правильное. Его можно переопределить например так, как описано здесь (хотя техника немного устарела: вместо триггеров нужно бы использовать VisualState). Или вы можете базироваться на стиле по умолчанию, и подменить нужные части.
Ветки нужно перемещать ноды на уровень выше в материнские и ниже в дочерние. Моё дерево: >
На другом примере работает нормально но в моём нет. 1
-2
--3
4
-5
--6
У меня любую ноду можно переместить в корень или в ту же ноду, в которой и находится. Например 3 можно переместить в корень либо в 2, где он уже есть. В другие почему-то не перемещается. public class Node
{
public string name_ { get; set; }
public ObservableCollection collection_node { get; set; } public Node()
{ collection_node = new ObservableCollection();
}
}
Ответ
Рекомендую использовать GongSolutions.WPF.DragDrop, которую можно легко установить добавив соответствующий NuGet-пакет. Дальше к своему TreeViewпросто добавляете два свойства: где dd xmlns:dd="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop"
Теперь вы можете легко перетаскивать элементы: