可以用以下方法完成Binding
, DataTrigger
and INotifyPropertyChanged
接口实现(WPF 的强大功能广泛应用于MVVM https://learn.microsoft.com/en-us/archive/msdn-magazine/2009/february/patterns-wpf-apps-with-the-model-view-viewmodel-design-pattern编程模式)。
我将使用 MVVM 方法作为您要求的示例。
示例功能
- 用户可以输入任意文本
TextBox
并按Search
按钮,所有包含搜索文本的项目将以黄色背景突出显示。
第 0 步:助手
以下类需要通知 UI 有关属性的更改。我将从其他类中派生并简单地调用OnPropertyChanged()
在属性设置器中。
通知属性更改.cs
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
在 MVVM 中,开发人员不使用Click
活动因为有更强大的Command
存在。下一堂课实施ICommand
接口(从上面链接的文档页面获取)。它需要在主代码中轻松实现命令。
RelayCommand.cs
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
}
第 1 步:数据
人物.cs
public class Person : NotifyPropertyChanged
{
private bool _highlighted;
public string Name { get; set; }
public bool Highlighted
{
get => _highlighted;
set
{
_highlighted = value;
OnPropertyChanged();
}
}
}
第2步:查看模型
查看模型 in MVVM是类哪里View(UI/XAML) 可以设置其DataContext
这需要Binding
.
MainViewModel.cs
public class MainViewModel : NotifyPropertyChanged
{
private ObservableCollection<Person> _persons;
private ICommand _searchCommand;
public ObservableCollection<Person> Persons
{
get => _persons;
set
{
_persons = value;
OnPropertyChanged();
}
}
// It's C# 8.0 but for earlier versions of C# use the following:
// _searchCommand ?? (_searchCommand = new ...
public ICommand SearchCommand => _searchCommand ??= new RelayCommand(parameter =>
{
if (parameter is string searchText)
{
foreach(Person person in Persons)
{
person.Highlighted = searchText.Length > 0 && person.Name.Contains(searchText, StringComparison.InvariantCultureIgnoreCase);
}
}
});
// }));
public MainViewModel()
{
// example data
Persons = new ObservableCollection<Person>
{
new Person { Name = "Alex" },
new Person { Name = "Jane" },
new Person { Name = "Nick" },
new Person { Name = "John" },
new Person { Name = "Brett" },
new Person { Name = "Peter" },
new Person { Name = "Mike" },
new Person { Name = "George" },
new Person { Name = "Anthony" }
};
}
}
第三步:查看
我提供完整的标记以使一切变得清晰。这是DataContext
设置和所有控件。
主窗口.xaml
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="SearchTextBox" Width="300" Margin="5"/>
<Button Content="Search" Margin="5" Command="{Binding SearchCommand}" CommandParameter="{Binding Text,ElementName=SearchTextBox}"/>
</StackPanel>
<ListBox Margin="5" Grid.Row="1" ItemsSource="{Binding Persons}">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Highlighted}" Value="True">
<Setter Property="Background" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
就是这样。
附:代码隐藏类:)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
Updated
如果我对问题的理解错误并且您需要自动选择而不是突出显示,则可以按以下方式更改代码:
人物.cs
public class Person : NotifyPropertyChanged
{
private bool _selected;
public string Name { get; set; }
public bool Selected
{
get => _selected;
set
{
_selected = value;
OnPropertyChanged();
}
}
}
MainViewModel.cs
public ICommand SearchCommand => _searchCommand ??= new RelayCommand(parameter =>
{
if (parameter is string searchText)
{
foreach(Person person in Persons)
{
person.Selected = searchText.Length > 0 && person.Name.Contains(searchText, StringComparison.InvariantCultureIgnoreCase);
}
}
});
主窗口.xaml
<ListBox Margin="5" Grid.Row="1" ItemsSource="{Binding Persons}" SelectionMode="Extended">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Selected}"/>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>