C# 选择和嵌套列表框的问题 介绍

C# 选择和嵌套列表框的问题 介绍,c#,wpf,listbox,selection,C#,Wpf,Listbox,Selection,首先,我为这个模糊的标题道歉,但对于我提出的问题,我想不出更好的表达方式: 我正在开发一个C#/WPF应用程序,需要在UI中显示嵌套列表结构。有一个应该显示的对象列表,但每个对象都有一个子列表(可能为空),其中的对象必须以嵌套方式显示。为了实现这一点,我使用了一个ListBox,它有一个包含嵌套ListBox的项目模板来显示子列表 我已经实现了确保一次只能选择一个项目(无论是外部项目还是内部项目)的目标,但我现在正在努力解决以下两个问题,我需要一些帮助: 我需要一种方法来禁用某些项目的选择,以及

首先,我为这个模糊的标题道歉,但对于我提出的问题,我想不出更好的表达方式:

我正在开发一个C#/WPF应用程序,需要在UI中显示嵌套列表结构。有一个应该显示的对象列表,但每个对象都有一个子列表(可能为空),其中的对象必须以嵌套方式显示。为了实现这一点,我使用了一个
ListBox
,它有一个包含嵌套
ListBox
的项目模板来显示子列表

我已经实现了确保一次只能选择一个项目(无论是外部项目还是内部项目)的目标,但我现在正在努力解决以下两个问题,我需要一些帮助:

  • 我需要一种方法来禁用某些项目的选择,以及鼠标悬停时的高亮显示,但不禁用所有内部UI元素。在下面的示例中,这将禁用选择/突出显示带有红色文本的条目,以及此条目的子列表,但在将鼠标悬停在文本上时仍能看到
    工具提示
  • 当鼠标位于子列表中的内部
    ListBoxItem
    上时,禁用突出显示外部
    ListBoxItem
    。因此,一次只能在一个
    ListBoxItem
    上高亮显示,尽管高亮显示外部
    ListBoxItem
    也可能会在内部子列表上高亮显示

  • 例子 下面是运行我组合的示例所需的两个文件:

    main window.xaml

    <Window x:Class="WpfApplication1.MainWindow"
            x:Name="TopLevelWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
            xmlns:local="clr-namespace:WpfApplication1"
            DataContext="{Binding RelativeSource={RelativeSource Self}}"
            Title="MainWindow" Height="350" Width="525">
       <ScrollViewer>
          <ScrollViewer.Resources>
             <local:InvertConverter x:Key="InvertConverter"/>
    
             <CollectionViewSource Source="{Binding Items}" x:Key="ItemsView">
                <CollectionViewSource.SortDescriptions>
                   <scm:SortDescription PropertyName="BoolProperty" Direction="Descending"/>
                   <scm:SortDescription PropertyName="Text" Direction="Ascending"/>
                </CollectionViewSource.SortDescriptions>
             </CollectionViewSource>
    
             <DataTemplate x:Key="ItemTemplate">
                <DockPanel Margin="4,4,2,4"
                           LastChildFill="True">
                   <TextBlock Text="{Binding Text}"
                              DockPanel.Dock="Top"
                              ToolTip="ERROR"
                              ToolTipService.IsEnabled="{Binding BoolProperty,
                                                                 Converter={StaticResource InvertConverter}}">
                      <TextBlock.Style>
                         <Style TargetType="{x:Type TextBlock}">
                            <Style.Triggers>
                               <DataTrigger Binding="{Binding BoolProperty}" Value="False">
                                  <Setter Property="Foreground" Value="Red"/>
                               </DataTrigger>
                            </Style.Triggers>
                         </Style>
                      </TextBlock.Style>
                   </TextBlock>
                   <ListBox x:Name="InnerListBox"
                            ItemsSource="{Binding Items}"
                            SelectedItem="{Binding ElementName=TopLevelWindow,
                                                   Path=DataContext.SelectedInnerItem}"
                            BorderThickness="0"
                            Background="Transparent"
                            MouseEnter="InnerListBox_MouseEnter"
                            MouseLeave="InnerListBox_MouseLeave"/>
                </DockPanel>
             </DataTemplate>
          </ScrollViewer.Resources>
    
          <ListBox ItemsSource="{Binding Source={StaticResource ItemsView}}"
                   ItemTemplate="{StaticResource ItemTemplate}"
                   SelectedItem="{Binding SelectedOuterItem}"
                   BorderThickness="0"/>
       </ScrollViewer>
    </Window>
    
    
    
    MainWindow.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Globalization;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    
    namespace WpfApplication1
    {
       /// <summary>
       /// Interaction logic for MainWindow.xaml
       /// </summary>
       public partial class MainWindow : Window, INotifyPropertyChanged
       {
          public event PropertyChangedEventHandler PropertyChanged;
    
          private OuterClass _selectedOuterItem;
          private string _selectedInnerItem;
    
          public ObservableCollection<OuterClass> Items { get; set; }
          public OuterClass SelectedOuterItem
          {
             get { return _selectedOuterItem; }
             set
             {
                if (_selectedOuterItem != value)
                {
                   _selectedOuterItem = value;
                   _selectedInnerItem = null;
                   PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedOuterItem)));
                   PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedInnerItem)));
                }
             }
          }
          public string SelectedInnerItem
          {
             get { return _selectedInnerItem; }
             set
             {
                if (_selectedInnerItem != value)
                {
                   _selectedInnerItem = value;
                   _selectedOuterItem = null;
                   PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedInnerItem)));
                   PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedOuterItem)));
                }
             }
          }
    
          public MainWindow()
          {
             Items = new ObservableCollection<OuterClass>()
             {
                new OuterClass("Beep", true, new List<string>()
                {
                   "Beep - A",
                   "Beep - B",
                   "Beep - C"
                }),
                new OuterClass("Boop", true, new List<string>()
                {
                   "Boop - A",
                   "Boop - B"
                }),
                new OuterClass("Baap", false, new List<string>()),
                new OuterClass("Biip", true, new List<string>()),
                new OuterClass("Buup", false, new List<string>()
                {
                   "Buup - A",
                   "Buup - B",
                   "Buup - C",
                   "Buup - D",
                   "Buup - E"
                })
             };
             InitializeComponent();
          }
    
          private void InnerListBox_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
          {
             ListBox listBox = e.Source as ListBox;
             if (listBox != null)
             {
                OuterClass dc = listBox.DataContext as OuterClass;
                if (dc != null)
                {
                   dc.MouseOverInternal = true;
                }
             }
          }
    
          private void InnerListBox_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
          {
             ListBox listBox = e.Source as ListBox;
             if (listBox != null)
             {
                OuterClass dc = listBox.DataContext as OuterClass;
                if (dc != null)
                {
                   dc.MouseOverInternal = false;
                }
             }
          }
       }
    
       public class OuterClass : INotifyPropertyChanged
       {
          private bool _mouseOverInternal;
    
          public string Text { get; set; }
          public bool BoolProperty { get; set; }
          public ObservableCollection<string> Items { get; set; }
          public bool MouseOverInternal
          {
             get { return _mouseOverInternal; }
             set
             {
                if (_mouseOverInternal != value)
                {
                   _mouseOverInternal = value;
                   PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MouseOverInternal)));
                }
             }
          }
    
          public OuterClass(string x, bool y, IEnumerable<string> z)
          {
             Text = x;
             BoolProperty = y;
             Items = new ObservableCollection<string>(z);
          }
    
          public event PropertyChangedEventHandler PropertyChanged;
       }
    
       public class InvertConverter : IValueConverter
       {
          public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
          {
             return foo(value);
          }
    
          public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
          {
             return foo(value);
          }
    
          private bool? foo(object val)
          {
             bool? boolVal = val as bool?;
             if (boolVal.HasValue)
             {
                return !boolVal.Value;
             }
             return null;
          }
       }
    }
    
    使用系统;
    使用System.Collections.Generic;
    使用System.Collections.ObjectModel;
    使用系统组件模型;
    利用制度全球化;
    使用System.Windows;
    使用System.Windows.Controls;
    使用System.Windows.Data;
    命名空间WpfApplication1
    {
    /// 
    ///MainWindow.xaml的交互逻辑
    /// 
    公共部分类主窗口:窗口,INotifyPropertyChanged
    {
    公共事件属性更改事件处理程序属性更改;
    专用外部类\u选择外部项;
    私有字符串\u选择的子项;
    公共ObservableCollection项{get;set;}
    public OuterClass SelectedOutItem
    {
    获取{return\u selectedOutItem;}
    设置
    {
    如果(_selectedOutItem!=值)
    {
    _SelectedOutItem=值;
    _selectedInnerItem=null;
    PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称)(SelectedOutItem));
    PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称)(SelectedInnerItem));
    }
    }
    }
    公共字符串SelectedInnerItem
    {
    获取{return\u selectedInnerItem;}
    设置
    {
    如果(_selectedInnerItem!=值)
    {
    _selectedInnerItem=值;
    _SelectedOutItem=null;
    PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称)(SelectedInnerItem));
    PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称)(SelectedOutItem));
    }
    }
    }
    公共主窗口()
    {
    Items=新的ObservableCollection()
    {
    新的外部类(“嘟嘟声”,正确,新列表()
    {
    “哔-A”,
    “哔-B”,
    “哔-C”
    }),
    新的外部类(“Boop”,真,新列表()
    {
    “Boop-A”,
    “Boop-B”
    }),
    新建外部类(“Baap”,false,new List()),
    新的外部类(“Biip”,true,new List()),
    新外部类(“Buup”,false,新列表()
    {
    “Buup-A”,
    “Buup-B”,
    “Buup-C”,
    “Buup-D”,
    “Buup-E”
    })
    };
    初始化组件();
    }
    private void InnerListBox_MouseEnter(对象发送方,System.Windows.Input.MouseEventArgs e)
    {
    ListBox ListBox=e.源为ListBox;
    如果(列表框!=null)
    {
    OuterClass dc=listBox.DataContext作为OuterClass;
    如果(dc!=null)
    {
    dc.MouseOverInternal=true;
    }
    }
    }
    私有void InnerListBox_MouseLeave(对象发送方,System.Windows.Input.MouseEventArgs e)
    {
    ListBox ListBox=e.源为ListBox;
    如果(列表框!=null)
    {
    OuterClass dc=listBox.DataContext作为OuterClass;
    如果(dc!=null)
    {
    dc.MouseOverInternal=false;
    }
    }
    }
    }
    公共类外部类:INotifyPropertyChanged
    {
    私人布勒(mouseOverInternal),;
    公共字符串文本{get;set;}
    公共布尔布尔属性{get;set;}
    公共ObservableCollection项{get;set;}
    公共布尔鼠标内部
    {
    获取{return\u mouseOverInternal;}
    设置
    {
    if(_mouseOverInternal!=值)
    {
    _mouseOverInternal=值;
    PropertyChanged?.Invoke(这是新的propertychangedventargs(nameof(MouseOverInternal));
    }
    }
    }
    公共外部类(字符串x、布尔y、IEnumerable z)
    {
    Text=x;
    BoolProperty=y;
    项目=新观测值a