我正在尝试理解为什么已从UI中删除的命令源上会调用CanExecute。这里是一个简化的程序示例:
当我点击“删除第一个项目”按钮一次时,输出如下:
每次我点击窗口的某个空白部分,都会打印出“为什么会发生这种情况?”。
为什么会发生这种情况?我应该怎么做才能防止在已删除的命令源上调用CanExecute?
注意:RelayCommand可以在此处找到。
Michael Edenfield问题的答案:
Q1:当从按钮中删除时调用CanExecute的调用堆栈:
WpfApplication1.exe!WpfApplication1.MainWindow.Foo.get_Act.AnonymousMethod__1(object param) 第30行 WpfApplication1.exe!WpfApplication1.RelayCommand.CanExecute(object parameter) 第41行 + 0x1a 字节 PresentationFramework.dll!MS.Internal.Commands.CommandHelpers.CanExecuteCommandSource(System.Windows.Input.ICommandSource commandSource) + 0x8a 字节 PresentationFramework.dll!System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute() + 0x18 字节 PresentationFramework.dll!System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(object sender, System.EventArgs e) + 0x5 字节 PresentationCore.dll!System.Windows.Input.CommandManager.CallWeakReferenceHandlers(System.Collections.Generic.List handlers) + 0xac 字节 PresentationCore.dll!System.Windows.Input.CommandManager.RaiseRequerySuggested(object obj) + 0xf 字节 Q2: 另外,如果您从列表中删除所有按钮(而不仅仅是第一个),这是否会继续发生?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350" Width="525">
<StackPanel>
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Content="{Binding Txt}"
Command="{Binding Act}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Remove first item" Click="Button_Click" />
</StackPanel>
</Window>
后台代码:
public partial class MainWindow : Window
{
public class Foo
{
static int _seq = 0;
int _txt = _seq++;
RelayCommand _act;
public bool Removed = false;
public string Txt { get { return _txt.ToString(); } }
public ICommand Act
{
get
{
if (_act == null) {
_act = new RelayCommand(
param => { },
param => {
if (Removed)
Console.WriteLine("Why is this happening?");
return true;
});
}
return _act;
}
}
}
public ObservableCollection<Foo> Items { get; set; }
public MainWindow()
{
Items = new ObservableCollection<Foo>();
Items.Add(new Foo());
Items.Add(new Foo());
Items.CollectionChanged +=
new NotifyCollectionChangedEventHandler(Items_CollectionChanged);
DataContext = this;
InitializeComponent();
}
void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove)
foreach (Foo foo in e.OldItems) {
foo.Removed = true;
Console.WriteLine("Removed item marked 'Removed'");
}
}
void Button_Click(object sender, RoutedEventArgs e)
{
Items.RemoveAt(0);
Console.WriteLine("Item removed");
}
}
当我点击“删除第一个项目”按钮一次时,输出如下:
Removed item marked 'Removed'
Item removed
Why is this happening?
Why is this happening?
每次我点击窗口的某个空白部分,都会打印出“为什么会发生这种情况?”。
为什么会发生这种情况?我应该怎么做才能防止在已删除的命令源上调用CanExecute?
注意:RelayCommand可以在此处找到。
Michael Edenfield问题的答案:
Q1:当从按钮中删除时调用CanExecute的调用堆栈:
WpfApplication1.exe!WpfApplication1.MainWindow.Foo.get_Act.AnonymousMethod__1(object param) 第30行 WpfApplication1.exe!WpfApplication1.RelayCommand.CanExecute(object parameter) 第41行 + 0x1a 字节 PresentationFramework.dll!MS.Internal.Commands.CommandHelpers.CanExecuteCommandSource(System.Windows.Input.ICommandSource commandSource) + 0x8a 字节 PresentationFramework.dll!System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute() + 0x18 字节 PresentationFramework.dll!System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged(object sender, System.EventArgs e) + 0x5 字节 PresentationCore.dll!System.Windows.Input.CommandManager.CallWeakReferenceHandlers(System.Collections.Generic.List handlers) + 0xac 字节 PresentationCore.dll!System.Windows.Input.CommandManager.RaiseRequerySuggested(object obj) + 0xf 字节 Q2: 另外,如果您从列表中删除所有按钮(而不仅仅是第一个),这是否会继续发生?