如何在xaml中通过DataTrigger切换Control?
How to switch Control by DataTrigger in the xaml?
有一个window由两个控件组成。
一个是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 属性 发生变化时,我想更改控件的可见性 属性 的值。 (FilterMode True = ListBox Visible, FilterMode False = TreeView = Visible)
为此,我修改了我的 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 的值,则将测试值添加到 FilterCPUs 中。 (注意 CPUSearch 属性)
将值添加到 FilterCPU 时,调用 FilterCPUs_CollectionChanged 并更改 FilterMode 的值。
但是上面的代码虽然改变了 FilterMode 的值,但并没有起作用。 (除了与 FilterMode 相关的功能外,效果很好)
为什么 Control 没有切换?
感谢阅读。
我参考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>
有一个window由两个控件组成。 一个是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 属性 发生变化时,我想更改控件的可见性 属性 的值。 (FilterMode True = ListBox Visible, FilterMode False = TreeView = Visible)
为此,我修改了我的 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 的值,则将测试值添加到 FilterCPUs 中。 (注意 CPUSearch 属性) 将值添加到 FilterCPU 时,调用 FilterCPUs_CollectionChanged 并更改 FilterMode 的值。
但是上面的代码虽然改变了 FilterMode 的值,但并没有起作用。 (除了与 FilterMode 相关的功能外,效果很好)
为什么 Control 没有切换?
感谢阅读。
我参考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>