C# 在DataTrigger中未一致调用Setter
注:重写为MCVE 我有一个这样的UI,它的目的是隐藏一个C# 在DataTrigger中未一致调用Setter,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,注:重写为MCVE 我有一个这样的UI,它的目的是隐藏一个列表视图,如果它是空的,或者显示它,如果它不是空的,则选择第一个项目 <Window x:Class="BrokenSelection.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
列表视图,如果它是空的,或者显示它,如果它不是空的,则选择第一个项目
<Window x:Class="BrokenSelection.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:BrokenSelection"
mc:Ignorable="d"
SizeToContent="WidthAndHeight"
Title="MainWindow">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel>
<ListView x:Name="MyListView" ItemsSource="{Binding Items}">
<ListView.Style>
<Style TargetType="ListView">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding HasItems, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
<Setter Property="SelectedIndex" Value="0"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Style>
</ListView>
<Button Content="Set" Click="Button_Set"/>
<Button Content="Clear" Click="Button_Clear"/>
<Button Content="Step" Click="Button_Step"/>
</StackPanel>
</Window>
我有这样一个VM实现
class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private List<string> items = new List<string>();
public List<string> Items
{
get
{
return items;
}
set
{
items = value;
PropertyChanged?.DynamicInvoke(this, new PropertyChangedEventArgs("Items"));
}
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Set(object sender, RoutedEventArgs e)
{
var l = new List<string>();
l.Add("Item1");
l.Add("Item2");
l.Add("Item3");
l.Add("Item4");
l.Add("Item5");
var vm = DataContext as ViewModel;
vm.Items = l;
}
private void Button_Clear(object sender, RoutedEventArgs e)
{
var vm = DataContext as ViewModel;
vm.Items = new List<string>();
}
private void Button_Step(object sender, RoutedEventArgs e)
{
MyListView.SelectedIndex++;
}
}
类视图模型:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
私有列表项=新列表();
公共清单项目
{
得到
{
退货项目;
}
设置
{
项目=价值;
PropertyChanged?.DynamicInvoke(这是新的PropertyChangedEventArgs(“项目”);
}
}
}
我有这样的代码
class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private List<string> items = new List<string>();
public List<string> Items
{
get
{
return items;
}
set
{
items = value;
PropertyChanged?.DynamicInvoke(this, new PropertyChangedEventArgs("Items"));
}
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Set(object sender, RoutedEventArgs e)
{
var l = new List<string>();
l.Add("Item1");
l.Add("Item2");
l.Add("Item3");
l.Add("Item4");
l.Add("Item5");
var vm = DataContext as ViewModel;
vm.Items = l;
}
private void Button_Clear(object sender, RoutedEventArgs e)
{
var vm = DataContext as ViewModel;
vm.Items = new List<string>();
}
private void Button_Step(object sender, RoutedEventArgs e)
{
MyListView.SelectedIndex++;
}
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
}
专用无效按钮集(对象发送器,路由目标e)
{
var l=新列表();
l、 添加(“第1项”);
l、 添加(“第2项”);
l、 添加(“第3项”);
l、 添加(“第4项”);
l、 添加(“第5项”);
var vm=DataContext作为ViewModel;
vm.Items=l;
}
专用无效按钮\u清除(对象发送器,路由目标e)
{
var vm=DataContext作为ViewModel;
vm.Items=新列表();
}
私有无效按钮\u步骤(对象发送器,路由目标e)
{
MyListView.SelectedIndex++;
}
}
我的问题是,只要单击“设置”、“清除”、“设置”、“清除”等,所选索引的Setter
就会成功
但是,如果我单击“设置”、“步骤”、“清除”、“设置”,则在第二个“设置”中所选的索引最终将为-1,而不是0。另一个Setter
会在列表消失并正确重新出现时执行。为什么手动更改所选索引会破坏触发器中的设置程序?对我来说效果很好。请参阅以下我的发言:
类视图模型:INotifyPropertyChanged
{
私人物品;
公共物品
{
获取{return\u hasItems;}
set{u UpdateValue(ref{u haseItems,value);}
}
公共ObservableCollection项{get;}=new ObservableCollection();
公共事件属性更改事件处理程序属性更改;
private void\u UpdateValue(ref T field,T newValue,[CallerMemberName]string propertyName=null)
{
如果(!object.Equals(字段,newValue))
{
字段=新值;
PropertyChanged?.DynamicInvoke(这是新的PropertyChangedEventArgs(propertyName));
if(propertyName==nameof(HasItems))
{
如果(项目)
{
项目。添加(“测试项目”);
}
其他的
{
Items.Clear();
}
}
}
}
}
我将您提供的代码直接复制到这个示例中。我所做的只是添加了足够多的其他代码,这样我就有了一个工作示例,可以演示SelectedIndex
属性是否确实发生了更改
您可以查看上面的内容,看看是否可以找到代码的不同之处。如果您仍然无法找出自己犯了什么错误,请修复您的问题,使其包括一个良好的MCVE,如上述,但它可靠地再现了问题。它对我来说很好。请参阅以下我的发言:
类视图模型:INotifyPropertyChanged
{
私人物品;
公共物品
{
获取{return\u hasItems;}
set{u UpdateValue(ref{u haseItems,value);}
}
公共ObservableCollection项{get;}=new ObservableCollection();
公共事件属性更改事件处理程序属性更改;
private void\u UpdateValue(ref T field,T newValue,[CallerMemberName]string propertyName=null)
{
如果(!object.Equals(字段,newValue))
{
字段=新值;
PropertyChanged?.DynamicInvoke(这是新的PropertyChangedEventArgs(propertyName));
if(propertyName==nameof(HasItems))
{
如果(项目)
{
项目。添加(“测试项目”);
}
其他的
{
Items.Clear();
}
}
}
}
}
我将您提供的代码直接复制到这个示例中。我所做的只是添加了足够多的其他代码,这样我就有了一个工作示例,可以演示SelectedIndex
属性是否确实发生了更改
您可以查看上面的内容,看看是否可以找到代码的不同之处。如果您仍然无法找出自己犯了什么错误,请修复您的问题,使其包含一个良好的MCVE(如上所述),但可以可靠地再现问题。在Peter的回答之前,他不会在每次集合更改时分配新的ObservableCollection
实例,他只是从中添加/删除项,这可能会使他的示例起作用(通常使用ObservableCollection
,对集合本身进行更改,而不是实例化新集合并分配它是正确的方法)
根据您在问题中提供的信息,我怀疑您在SelectedIndex
属性中看到的-1值是