Добрый день.
На форме есть такое:
<TreeView>
<TreeView.Resources>
<Style x:Key="TreeViewItem_NoExpanded" TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</TreeView.Resources>
<TreeViewItem Header="Root" IsExpanded="True"
ItemsSource="{Binding Path=xxx, ElementName=window1}"/>
</TreeView>
соответсвенно xxx — это ObservableCollection, у элементов которой есть свойство IsSelected — если true, то элемент выделяется в дереве, если — false — снимается выделение.
Так вот после "выделения" объекта мышкой, последующего программного снятия выделения — SelectedValue.IsSelected = false и последующего выделения этого-же объекта мышкой — он не выделяется..., если кликнуть по другому элементу, то он выделется без проблем. Такое ощущение, что первый элемент осьается выделенным после IsSelected = false. Никто с таким не сталкивался?
Здравствуйте, Аноним, Вы писали:
А>соответсвенно xxx — это ObservableCollection, у элементов которой есть свойство IsSelected — если true, то элемент выделяется в дереве, если — false — снимается выделение.
А>Так вот после "выделения" объекта мышкой, последующего программного снятия выделения — SelectedValue.IsSelected = false и последующего выделения этого-же объекта мышкой — он не выделяется..., если кликнуть по другому элементу, то он выделется без проблем. Такое ощущение, что первый элемент осьается выделенным после IsSelected = false. Никто с таким не сталкивался?
Сталкивался. Проблема в том, что выделение элемента в TreeView по нажатию мыши делается через фокусировку. Происходит следующее. Мышь нажимается на TreeViewItem, зовется метод Focus, в результате которого зовется метод GotFocus, который перекрыт в TreeViewItem и вызывает Select, выделяя элемент в дереве. Далее IsSelected делается false, и выделение хоть и уходит, но фокусировка остается. Следом мышь снова нажимается, и снова зовется Focus, однако на этот раз элемент уже сфокусирован прошлым нажатием мыши. Следовательно изменения фокуса не происходит, а значит не будет вызова GotFocus, а следовательно не будет вызова Select. Как это побороть? — добиться ухода фокуса с TreeViewItem. Можно написать attached behavior, который при изменении IsSelected в false, будет снимать фокус с TreeViewItem. Вопрос в том, на кого этот фокус перекинуть. В последнем WPF появился метод
Keyboard.ClearFocus, возможно он подойдет. Что касается моего случая, то я в итоге просто забил на эту проблему, т.к. красиво решить ее не выходит, а описанная последовательность действий не такая уж частая, мне кажется.
Здравствуйте, MxMsk,
В WPF 4 проблема решается двумя вызовами после IsSelected = false:
private void OnCalcsTreePreviewMouseDown(object sender, MouseButtonEventArgs e)
{
TreeView Source = sender as TreeView;
if (e.OriginalSource.GetType().Name == "ScrollViewer")
{
if (Source.SelectedItem != null)
{
TreeViewItem Container = Source.GetContainerByObject(Source.SelectedItem);
if (Container != null)
{
Container.IsSelected = false;
FocusManager.SetFocusedElement(Source, e.OriginalSource as IInputElement);
Keyboard.Focus(Source );
}
}
}
}
public static class TreeViewExtensions
{
public static TreeViewItem GetContainerByObject(this TreeView treeView, Object reference)
{
return GetContainerByObjectInternal(treeView, reference);
}
private static TreeViewItem GetContainerByObjectInternal(ItemsControl itemsControl, Object reference)
{
ValidateItemsControl(itemsControl);
if (itemsControl.Items.Contains(reference))
return itemsControl.ItemContainerGenerator.ContainerFromItem(reference) as TreeViewItem;
else
{
foreach (Object item in itemsControl.Items)
{
TreeViewItem CurrentItem = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
if (CurrentItem != null)
{
TreeViewItem FindedContainer = GetContainerByObjectInternal(CurrentItem, reference);
if (FindedContainer != null)
return FindedContainer;
}
}
}
return null;
}
private static void ValidateItemsControl(ItemsControl itemsControl)
{
Debug.Assert(itemsControl is TreeViewItem || itemsControl is TreeView);
}
}