我有带触发器的简单 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 事件只会针对可见的复选框引发。因此该命令仅针对可见的调用。
通过测试您提供的示例,属性由任务设置,并且还按 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/