wpf - 如何在 xaml 中通过 DataTrigger 切换控制?
问题描述
有一个窗口由两个控件组成。一个是TreeView,另一个是ListBox。
代码如下所示。
<Grid Grid.Row="1">
<TreeView x:Name="treeView" BorderThickness="0" Visibility="Visible"
ItemsSource="{Binding TotalCPUs}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<mvvm:EventToCommand Command="{Binding CPUSelectedCommand}"
PassEventArgsToCommand="True"
EventArgsConverter="{localConverters:SelectedItemConverter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
<ListBox x:Name="listBox" BorderThickness="0" Visibility="Collapsed"/>
</Grid>
现在,每当更改 ViewModel 的属性时,我想更改 Control 的 Visibility 属性的值。(FilterMode True = ListBox 可见,FilterMode False = TreeView = 可见)
为此,我修改了我的 XAML 代码,如下所示。
<Grid Grid.Row="1">
<TreeView x:Name="treeView" BorderThickness="0" Visibility="Visible"
ItemsSource="{Binding TotalCPUs}">
<TreeView.Style>
<Style TargetType="{x:Type TreeView}">
<Style.Triggers>
<DataTrigger Binding="{Binding FilterMode}" Value="true">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<mvvm:EventToCommand Command="{Binding CPUSelectedCommand}"
PassEventArgsToCommand="True"
EventArgsConverter="{localConverters:SelectedItemConverter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
<ListBox x:Name="listBox" BorderThickness="0" Visibility="Collapsed">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding FilterMode}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
</Grid>
下面是 ViewModel 代码。
public class NewProjectViewModel : DialogViewModel
{
private Generator projectGenerator = new Generator();
public ObservableCollection<ClassHierarchyData> TotalCPUs { get; private set; } = new ObservableCollection<ClassHierarchyData>();
public ObservableCollection<DetailType> FilterCPUs { get; private set; } = new ObservableCollection<DetailType>();
private bool filterMode;
public bool FilterMode
{
get => filterMode;
set
{
if (this.filterMode == value) return;
this.filterMode = value;
this.RaisePropertyChanged("FilterMode");
}
}
private string cpuSearch;
public string CPUSearch
{
get => this.cpuSearch;
set
{
if (this.cpuSearch == value) return;
this.cpuSearch = value;
this.FilterCPUs.Add(new DetailType(typeof(Target), "abc"));
}
}
private Type selectedTerminalItem;
public Type SelectedTerminalItem
{
get => this.selectedTerminalItem;
private set
{
if (this.selectedTerminalItem == value) return;
this.selectedTerminalItem = value;
this.RaisePropertyChanged("SelectedTerminalItem");
}
}
private Type selectedItem;
public Type SelectedItem
{
get => selectedItem;
set
{
if (this.selectedItem == value) return;
this.selectedItem = value;
this.RaisePropertyChanged("SelectedItem");
CreateCommand.RaiseCanExecuteChanged();
}
}
private string solutionName = string.Empty;
public string SolutionName
{
get => this.solutionName;
set
{
if (this.solutionName == value) return;
this.solutionName = value;
this.RaisePropertyChanged("SolutionName");
this.RaisePropertyChanged("SolutionFullPath");
CreateCommand.RaiseCanExecuteChanged();
}
}
private string solutionPath = string.Empty;
public string SolutionPath
{
get => this.solutionPath;
set
{
if (this.solutionPath == value) return;
this.solutionPath = value;
if(this.SolutionPath.Length > 0)
{
if (this.solutionPath.Last() != '\\')
this.solutionPath += "\\";
}
this.RaisePropertyChanged("SolutionPath");
this.RaisePropertyChanged("SolutionFullPath");
CreateCommand.RaiseCanExecuteChanged();
}
}
public bool CreateSolutionFolder { get; set; }
public string SolutionFullPath { get => this.SolutionPath + this.solutionName; }
private RelayCommand searchCommand;
public RelayCommand SearchCommand
{
get
{
if (this.searchCommand == null) this.searchCommand = new RelayCommand(this.OnSearch);
return this.searchCommand;
}
}
private void OnSearch()
{
CommonOpenFileDialog selectFolderDialog = new CommonOpenFileDialog();
selectFolderDialog.InitialDirectory = "C:\\Users";
selectFolderDialog.IsFolderPicker = true;
if (selectFolderDialog.ShowDialog() == CommonFileDialogResult.Ok)
{
this.SolutionPath = selectFolderDialog.FileName + "\\";
}
}
private RelayCommand<Action> _createCommand;
public RelayCommand<Action> CreateCommand
{
get
{
if (this._createCommand == null)
this._createCommand = new RelayCommand<Action>(this.OnCreate, this.CanExecuteCreate);
return this._createCommand;
}
}
private void OnCreate(Action action)
{
projectGenerator.GenerateSolution(this.SolutionPath, this.SolutionName, this.CreateSolutionFolder);
action?.Invoke();
}
private bool CanExecuteCreate(Action action)
{
if (this.SelectedTerminalItem == null) return false;
if (string.IsNullOrEmpty(this.solutionPath)) return false;
if (string.IsNullOrEmpty(this.solutionName)) return false;
return true;
}
private RelayCommand<ClassHierarchyData> cpuSelectedCommand;
public RelayCommand<ClassHierarchyData> CPUSelectedCommand
{
get
{
if (this.cpuSelectedCommand == null)
this.cpuSelectedCommand = new RelayCommand<ClassHierarchyData>(OnCPUSelected);
return this.cpuSelectedCommand;
}
}
private void OnCPUSelected(ClassHierarchyData selected)
{
this.SelectedItem = selected.Data;
this.SelectedTerminalItem = (selected.Items.Count == 0) ? selected.Data : null;
}
private RelayCommand<string> navigateCommand;
public RelayCommand<string> NavigateCommand
{
get
{
if (this.navigateCommand == null)
this.navigateCommand = new RelayCommand<string>((uri) =>
{
Process.Start(new ProcessStartInfo(uri));
});
return navigateCommand;
}
}
public NewProjectViewModel()
{
ClassHierarchyGenerator classHierarchyGenerator = new ClassHierarchyGenerator();
this.TotalCPUs.Add(classHierarchyGenerator.ToHierarchyData(typeof(Target)));
this.FilterCPUs.CollectionChanged += FilterCPUs_CollectionChanged;
}
private void FilterCPUs_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
this.FilterMode = (this.FilterCPUs.Count > 0) ? true : false;
}
}
public class DetailType
{
public Type Type { get; }
public string Path { get; }
public DetailType(Type type, string path)
{
Type = type;
Path = path;
}
}
如果用户将数据输入到 TextBox 进行过滤,则 CPUSearch 的值会更改。
如果 CPUSearch 的值发生更改,则将测试值添加到 FilterCPU 中。(注意 CPUSearch 属性)当向 FilterCPUs 添加值时,调用 FilterCPUs_CollectionChanged 并更改 FilterMode 的值。
但是上面的代码虽然改变了FilterMode的值,但不起作用。(除了与 FilterMode 相关的功能外效果很好)
为什么不切换控制?
谢谢阅读。
解决方案
我通过参考WPF Showing / Hiding a control with triggers解决了这个问题
我的 XAML 代码像这样更新并且运行良好。
感谢您的关注。
<Grid Grid.Row="1">
<TreeView x:Name="treeView" BorderThickness="0"
ItemsSource="{Binding TotalCPUs}">
<TreeView.Style>
<Style TargetType="{x:Type TreeView}">
<Style.Triggers>
<DataTrigger Binding="{Binding FilterMode}" Value="true">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding FilterMode}" Value="false">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TreeView.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<mvvm:EventToCommand Command="{Binding CPUSelectedCommand}"
PassEventArgsToCommand="True"
EventArgsConverter="{localConverters:SelectedItemConverter}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
<ListBox x:Name="listBox" BorderThickness="0"
ItemsSource="{Binding FilterCPUs}"
SelectedItem="{Binding SelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock FontSize="8" Text="{Binding Path=Path}" Margin="0 0 0 3"/>
<TextBlock Text="{Binding Type.Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{DynamicResource CommonEnableBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource CommonEnableBorderBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource CommonEnableTextBrush}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding FilterMode}" Value="true">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding FilterMode}" Value="false">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
</Grid>
推荐阅读
- java - 将字符串的一部分变成可点击的链接
- c# - 第一次单击异步按钮时,UI 冻结 5 秒
- c++ - 读取整数的二进制文件
- python - 基于多个事件的Django调用函数
- java - getresource() 空指针的问题
- arrays - 无法正确循环数组条件失败-reactjs
- java - 有没有办法在运行时访问和修改 Eclipse 插件的源代码?
- java - 无需遍历所有像素即可替换图像中的颜色
- java - java是否可以在数组中插入算术运算符(+ - / *)?
- laravel - 在新的 laravel 文件中执行“npm run”时出错 - 找不到模块 npm-cli.js