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

标签 c# wpf listview mvvm

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

xmlns:i="http://schemas.microsoft.com/expression/2010/interactions" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactivity"

<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);
    }
}

最佳答案

Checked 事件只会针对可见的复选框引发。因此该命令仅针对可见的调用。

sample UI

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

改变

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

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

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

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

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

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

但我认为您根本不需要这个。检查状态通过双向绑定(bind)由您的 IsChecked-Property 反射(reflect)。

<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" VerticalAlignment="Center">

所以你可以很容易地得到它们

var checkedItemsList = Items.Where(ele => ele.IsChecked).ToList();

如果您通过代码进行更改,您可以在 View 模型中手动调用命令。

Items[0].IsChecked = true;
if (IsCheckedTrueCommand.CanExecute(Items[0]))
    IsCheckedTrueCommand.Execute(Items[0]);

但我不确定我是否让你到这里。问题仍然是命令在增强场景中应该做什么。

顺便问一下,您使用的是哪个版本的框架?参见 check box binding not working on .NET 3.5 SP1

要在用户交互上调用命令,您可以使用:

<CheckBox CommandParameter="{Binding}"
                              Command="{Binding DataContext.CheckBoxCommand, RelativeSource={RelativeSource FindAncestor,  AncestorType={x:Type Window}}}"
                              IsChecked="{Binding IsChecked, Mode=TwoWay}" VerticalAlignment="Center">

关于c# - 带有混合触发器的 ListView 奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34525530/

相关文章:

c# - 使用 2 个不同的命令时出现错误 "There is already an open DataReader associated with this Command which must be closed first"

wpf - WPF DataGrid 中的 IsSelected 绑定(bind)

c# - 如何将网格拉伸(stretch)和延伸到父边距

C# 如何添加一个ListView ClickListener

c# - 事件顺序可以更改吗?

c# - 将资源中的图像添加到 XAML

c# - 将 BitmapImage 字节数组转换为 Image 字节数组 (WinRT -> WinForms)

c# - 设计一个多对一的移动应用程序 -> 数据库 -> 桌面应用程序项目

java - 在android中排序 ListView

java - 如何使日历根据优先级列出事件