Отключить выбор WPF TreeView (или TreeViewItem)?

Есть ли хороший способ (кроме повторного создания всего TreeViewItem.Template) отключить выделение в TreeView?

Я в основном ищу стиль ItemsControl для TreeView (ItemsControl - лучшее применение для "отключения" выбора на ListBox, прочтите this сообщение)


person Shimmy Weitzhandler    schedule 29.12.2010    source источник
comment
Вот еще один подход: stackoverflow.com/questions/1398559/   -  person    schedule 26.04.2011


Ответы (8)


Каждый раз, когда элемент выбран, вы можете «отменить выбор». Бывший. измените код из http://www.codeproject.com/KB/WPF/TreeView_SelectionWPF.aspx или используйте подход MVVM (см. http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx) и всегда возвращать IsSelected значение false.

person Daniel Rose    schedule 29.12.2010
comment
Хотя теоретически это может дать ответ на вопрос, мы хотели бы, чтобы вы включили в свой ответ основные части связанной статьи и предоставили ссылку для ссылка. Если этого не сделать, ответ окажется под угрозой из-за гниения ссылок. - person Kev; 31.10.2012

Попробуй это:

<Trigger Property="HasItems" Value="true">
   <Setter Property="Focusable" Value="false" />
</Trigger>
person Morten Strand    schedule 27.11.2013
comment
Чтобы расширить этот ответ, также появляется установка Focusable на false на листе TreeViewItems, чтобы предотвратить их выбор. - person ravuya; 02.03.2016
comment
Это также предотвращает выбор узлов без дочерних узлов, учтите это. - person Ravid Goldenberg; 18.10.2018
comment
К сожалению, при сворачивании узла это все еще может привести к выделению корневого элемента. - person Wobbles; 11.06.2019

Основываясь на ссылках на принятый в настоящее время ответ, я реализовал это в своем проекте:

<ListView.ItemContainerStyle>
    <Style TargetType="{x:Type ListViewItem}">
        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
    </Style>
</ListView.ItemContainerStyle>

Также работает для TreeViewItem. И в модели представления:

protected bool _DisableSelection;
private bool _IsSelected;
public bool IsSelected
{
    get { return _IsSelected; }
    set
    {
        if (value == _IsSelected) return;
        _IsSelected = _DisableSelection ? false : value;
        NotifyPropertyChanged();
    }
}

Теперь тебе не нужно идти на охоту!

person Balki    schedule 26.07.2013

Это помогло мне (на основе этого ответа, но не привязанного к элементу - выбор вообще отключен):

<TreeView>
  <TreeView.ItemContainerStyle>
    <Style TargetType="TreeViewItem">
      <Setter Property="Focusable" Value="False" />
    </Style>
  </TreeView.ItemContainerStyle>
</TreeView>
person Shimmy Weitzhandler    schedule 05.03.2018

Я решил написать многоразовое поведение HTH:

Namespace Components
  Public NotInheritable Class TreeViewBehavior

    Public Shared Function GetIsTransparent(
      ByVal element As TreeViewItem) As Boolean
      If element Is Nothing Then Throw New ArgumentNullException("element")
      Return element.GetValue(IsTransparentProperty)
    End Function
    Public Shared Sub SetIsTransparent(ByVal element As TreeViewItem,
                                       ByVal value As Boolean)
      If element Is Nothing Then Throw New ArgumentNullException("element")
      element.SetValue(IsTransparentProperty, value)
    End Sub
    Public Shared ReadOnly IsTransparentProperty As DependencyProperty =
      DependencyProperty.RegisterAttached("IsTransparent", GetType(Boolean),
        GetType(TreeViewBehavior),
        New FrameworkPropertyMetadata(False,
          AddressOf IsTransparent_PropertyChanged))
    Private Shared Sub IsTransparent_PropertyChanged(
      ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs)
      Dim tvi = DirectCast(sender, TreeViewItem)
      Dim isTransparent = CBool(e.NewValue)

      If isTransparent Then
        AddHandler tvi.Selected, AddressOf tvi_Selected
      Else
        RemoveHandler tvi.Selected, AddressOf tvi_Selected
      End If
    End Sub
    Private Shared Sub tvi_Selected(ByVal sender As Object,
                                    ByVal e As RoutedEventArgs)
      Dim treeViewItem = DirectCast(sender, TreeViewItem)
      If Not treeViewItem.IsSelected Then Exit Sub

      treeViewItem.Dispatcher.Invoke(
        Sub(tvi As TreeViewItem) tvi.IsSelected = False,
        System.Windows.Threading.DispatcherPriority.Send,
        treeViewItem)
    End Sub

  End Class
End Namespace

Использование:

<Window xmlns:components="clr-namespace:WpfApplication.Components">
  <TreeView>
    <TreeView.ItemContainerStyle>
      <Style TargetType="TreeViewItem">
        <Setter 
          Property="components:TreeViewBehavior.IsTransparent" 
          Value="True" />
      </Style>
    </TreeView.ItemContainerStyle>
  </TreeView>
</Window> 
person Shimmy Weitzhandler    schedule 29.12.2010

Я пробовал это, и у меня это сработало. Потому что у меня простое, а не динамическое древовидное представление. Но я думаю, что это может сработать, если оформить его в стиле

<TreeViewItem ... Focusable="False" IsSelected="False"/>
person CongoTM    schedule 18.09.2020
comment
Хотя этот фрагмент кода может быть решением, включая объяснение действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос для читателей в будущем, и эти люди могут не знать причины вашего предложения кода. - person Neo Anderson; 18.09.2020
comment
Спасибо @NeoAnderson. Я здесь новенький, но я просто хочу помочь. - person CongoTM; 21.09.2020
comment
Мы все хотим помочь. Наша цель - сделать это максимально эффективно. Спасибо за объяснение фрагмента кода. - person Neo Anderson; 21.09.2020

Я просто снял выделение с TreeViewItems по мере их выбора. Я использую TreeView только один раз. Однако, если бы я добавил это в нескольких местах, я бы подумал о том, чтобы добавить это в Attached Behavior.

Xaml:

<TreeView SelectedItemChanged="TreeView_SelectionChanged">

Код позади:

private void TreeView_SelectionChanged(object sender, RoutedEventArgs e)
{
    if (!(sender is TreeView myTreeView)) return;
    var selectedItem = (TreeViewItem)myTreeView.SelectedItem;
    if (selectedItem == null) return;
    selectedItem.IsSelected = false;
}
person Henrik Bøgelund Lavstsen    schedule 21.09.2016

Я сделал это иначе, чем принятый ответ:

Допустим, у вас есть свойство в вашей ViewModel (скажем, ShouldPreventSelection). Теперь, когда ShouldPreventSelection имеет значение true, вы хотите, чтобы выбор был отключен:

В вашем TreeView запустите событие PreviewSelected следующим образом:

<TreeView Name="TreeView1"
     ...
     PreviewSelected="TreeView1_PreviewSelected"
     ..
/>

Затем в выделенном коде вы можете следующее:

private void TreeView1_PreviewSelected(object sender, RoutedEventArgs e)
{
    MyViewModel myViewModel = TreeView1.DataContext as MyViewModel;
    if (myViewModel == null)
    {
        return;
    }
    if (myViewModel .ShouldPreventSelection)
    {
        e.Handled = true;
    }

}
person Danield    schedule 01.02.2012
comment
Похоже, что в WPF TreeView нет PreviewSelected события. - person svick; 06.11.2012
comment
хм, я использовал RadTreeView от Telerik и предполагал, что событие PreviewSelected было доступно в обычном TreeView. - person Danield; 07.11.2012