我有带触发器的简单ListView,也正在使用mvvm light RelayCommand。
主要问题是,为什么在控制台中触发ChangeShowingMode(ObservableCollection<Employee> items)函数时,它仅显示Firing: 0。为什么它不同时显示Firing: 1Firing: 5Firing: 11Firing: 99。怎么做?


<Grid>
    <ListView ItemsSource="{Binding Items}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <CheckBox IsChecked="{Binding IsChecked}" VerticalAlignment="Center">
                        <ei:Interaction.Triggers>
                            <ei:EventTrigger EventName="Checked">
                                <ei:InvokeCommandAction Command="{Binding DataContext.IsCheckedTrueCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Views:MainWindow}}}" CommandParameter="{Binding .}"/>
                            </ei:EventTrigger>
                        </ei:Interaction.Triggers>
                    </CheckBox>
                    <Label Grid.Column="1" Content="{Binding Name}" VerticalAlignment="Center"/>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

代码如下:
namespace WpfApplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ListViewModel();
    }
}
public class Employee : ViewModelBase
{
    private bool isChecked;
    public bool IsChecked
    {
        get
        {
            return this.isChecked;
        }

        set
        {
            this.isChecked = value;
            this.RaisePropertyChanged("IsChecked");
        }
    }

    public string Name { get; set; }
}
public class ListViewModel : ViewModelBase
{
    private ObservableCollection<Employee> items;
    public ObservableCollection<Employee> Items
    {
        get
        {
            return this.items;
        }

        set
        {
            this.items = value;
            this.RaisePropertyChanged("Items");
        }
    }

    public ListViewModel()
    {
        Items = new ObservableCollection<Employee>();
        LoadAsync();
    }
    public void LoadAsync()
    {
        Task t = null;
        t = Task.Factory.StartNew(new Action(() =>
        {
            System.Threading.Thread.Sleep(5000);
            ObservableCollection<Employee> temporaryItems = new ObservableCollection<Employee>();
            for (int i = 0; i < 100; i++)
            {
                temporaryItems.Add(new Employee { IsChecked = false, Name = i.ToString() });
            }
            Items = temporaryItems;
        }));
        t.ContinueWith((key) => { ChangeShowingMode(Items); });
    }
    public void ChangeShowingMode(ObservableCollection<Employee> items)
    {
        Items[0].IsChecked = true;
        Items[1].IsChecked = true;
        Items[5].IsChecked = true;
        Items[11].IsChecked = true;
        Items[99].IsChecked = true;
    }

    public RelayCommand<Employee> IsCheckedTrueCommand
    {
        get
        {
            return new RelayCommand<Employee>((emp) => Command(emp));
        }
    }

    public void Command(Employee emp)
    {
        Console.WriteLine("Firing: {0}", emp.Name);
    }
}

}

最佳答案

“已检查事件”将仅针对可见的复选框引发。因此,仅针对可见命令调用该命令。

c# - ListView具有混合触发器的奇怪行为-LMLPHP

通过测试您提供的示例,属性由任务设置,也可以按UI预期反射(reflect)。但是,只有在我手动选中复选框时才调用Command,而不是通过初始化来调用。

改变中

t.ContinueWith((key) => { ChangeShowingMode(Items); });


t.ContinueWith((key) => { Syste.Threading.Thread.Sleep(5000); ChangeShowingMode(Items); });

结果是,为可见的复选框调用了Command。
如果在显示复选框时向下滑动,则会为Checkbox 99调用命令。

但是这种行为一点也不奇怪。我认为,当您的 View 模型是否连接到Datacontext时,这是一个时间问题。

您的问题“如何制作?”的答案取决于您当前解决方案的问题。

要观看属性更改,您可以
How to Listen to Property Changes of Items of an ObservableCollection
并在更改时调用命令。

但是我认为您根本不需要这个。您的IsChecked-Property通过双向绑定(bind)反射(reflect)了选中状态。
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" VerticalAlignment="Center">

这样您就可以轻松获得它们
var checkedItemsList = Items.Where(ele => ele.IsChecked).ToList();

而且,如果您按代码进行更改,则可以在 View 模型中手动调用Command。
Items[0].IsChecked = true;
if (IsCheckedTrueCommand.CanExecute(Items[0]))
    IsCheckedTrueCommand.Execute(Items[0]);

但是我不确定是否能把你送到这里。问题仍然是该命令在增强方案中应该做什么。

顺便说一句,您正在使用哪个版本的Framework?参见check box binding not working on .NET 3.5 SP1

并可以在用户互动中调用Comand,您可以使用:
<CheckBox CommandParameter="{Binding}"
                              Command="{Binding DataContext.CheckBoxCommand, RelativeSource={RelativeSource FindAncestor,  AncestorType={x:Type Window}}}"
                              IsChecked="{Binding IsChecked, Mode=TwoWay}" VerticalAlignment="Center">

10-06 10:19