我正在努力在列表框中创建一个标题,该标题将变成灰色,并且其中有一个冒号,而其余条目(列表框项目)将为黑色。
我想做的是,如果该值与列表字符串中的类型之一匹配,那么它将变成灰色并成为标题。当它成为标题后,我想禁用项目框,使其不可单击,而其余条目可单击。
这是我的功能:
private void PopulateItems(List<string> items, string groupName)
{
listbx.Items.Clear();
List<string> itemsList = items;
string founditemtype = null;
foreach (string item in items)
{
foreach (string itemtype in Type)
{
if(item == itemtype)
{
founditemtype = itemtype;
Label label = new Label();
label.Content = itemtype + ":";
label.FontWeight = FontWeights.Bold;
label.Foreground = Brushes.Gray;
// Handle the PreviewMouseLeftButtonDown event to prevent the grayed text to be selected:
label.PreviewMouseLeftButtonDown += (sender, e) =>
{
if (label.Content.ToString().Contains(":"))
{
e.Handled = true;
}
};
listbx.Items.Add(label);
}
}
if(item != founditemtype)
{
listbx.Items.Add(item);
}
}
这是我的列表框的 WPf:
<ListBox x:Name="listbx" BorderBrush="Black" BorderThickness="2" Grid.Row="2" VerticalAlignment="Top" HorizontalAlignment="Left" Width="525" Height="200" SelectionMode="Multiple" />
但是,每次我运行该应用程序时,列表框总是允许用户选择应该变灰的项目,使其可单击和选择。即使打开多选模式,当用户选择其他项目并误选择标题项目时,仍然可以选择它。我在这里做错了什么?
您应该避免直接在
ItemsControl.Items
属性上工作。相反,创建一个可以操作的成员变量。
此外,切勿直接向 ItemsControl 添加控件。这将极大地影响性能(因为这样做会禁用
ListBox
的 UI 虚拟化)。
您可以通过使用所有
UIElement
元素的内置行为来简化代码:当您将 UIElement.IsEnabled
上的 ListBoxItem
属性设置为 false
时,项目容器将自动禁用,意味着变灰并且不可点击。
要实现此目的,您需要访问
ListBoxItem
。MultiBinding
和 IMultiValueConverter
可以轻松解决您的问题,避免不必要的迭代。
我还建议一般使用数据绑定 Microsoft Learn:WPF 中的数据绑定概述。
如果您最初的目标是实现分组,请查看 Microsoft Learn:集合视图 和分组。
ListBox
能够自动创建组。
ListBoxValueToHeaderConverter.cs
public class ListBoxValueToHeaderConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string currentItem = values
.OfType<string>()
.First();
ListBoxItem currentItemContainer = values
.OfType<ListBoxItem>()
.First();
IEnumerable<string> predicateCollection = values
.OfType<IEnumerable<string>>()
.First();
if (predicateCollection.Contains(currentItem))
{
// Disable the item container to make it automatically not clickable
// and to be rendered as grayed out
currentItemContainer.IsEnabled = false;
return ":";
}
return currentItem;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
MainWindow.xaml.cs
partial class MainWindow : Window
{
// You should assign a new collection if you want to modify it.
// This will update the MultiBinding (in XAML).
// In general, when binding an ItemsCOntrol to a collection
// prefer to clear/replace the items to improve the performance of the control.
// Because this collection is not the binding source for a control
// replacing in this scenario is fine.
public ObservableCollection<string> Type { get; private set; }
// Declare this property as public if you want to bind to it
private ObservableCollection<string> Items { get; }
public MainWindow(TestViewModel dataContext, INavigator navigator)
{
InitializeComponent();
this.Items = new ObservableCollection<string>();
// It's generally recommended to use data binding instead of explicit assignment.
this.ListBox.ItemsSource = this. Items;
}
private void PopulateItems(List<string> newItems, string groupName)
{
this.Items.Clear();
newItems.ForEach(this.Items.Add);
}
}
MainWindow.xaml
<Window>
<Window.Resources>
<local:ListBoxValueToHeaderConverter x:Key="ListBoxValueToHeaderConverter" />
</Window.Resources>
<ListBox x:Name="ListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Content">
<Setter.Value>
<MultiBinding Converter="{StaticResource ListBoxValueToHeaderConverter}">
<!-- The current item -->
<Binding />
<!-- The item container (ListBoxItem) -->
<Binding RelativeSource="{RelativeSource Self}" />
<!-- The filter predicate collection defined in the parent Window -->
<Binding RelativeSource="{RelativeSource AncestorType=Window}"
Path="Type" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<!-- Define a trigger to change the look of the disabled ListBoxItem -->
<Trigger Property="IsEnabled"
Value="False">
<Setter Property="FontWeight"
Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Window>