C# 在DataTrigger中未一致调用Setter

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"

注:重写为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"
        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值是