Estoy tratando de entender por qué se invoca CanExecute en un origen de comando que se ha eliminado de la interfaz de usuario. Aquí es un programa simplificado para demostrar:¿Por qué se invoca CanExecute después de eliminar el origen del comando de la interfaz de usuario?
<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>
de código subyacente:
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");
}
}
Cuando pulso en el "Eliminar primer elemento" botón una vez, me sale esta salida:
Removed item marked 'Removed'
Item removed
Why is this happening?
Why is this happening?
"¿Por qué está pasando esto?" sigue imprimiéndose cada vez que hago clic en alguna parte vacía de la ventana.
¿Por qué sucede esto? ¿Y qué puedo hacer o debo hacer para evitar que CanExecute se invoque en los orígenes de comandos eliminados?
Nota: RelayCommand se puede encontrar here.
Las respuestas a las preguntas Michael Edenfield:
P1: pila de llamadas cuando CanExecute se invoca en el botón eliminado:
WpfApplication1.exe WpfApplication1.MainWindow.Foo.get_Act.AnonymousMethod__1 (parámetro de objeto) Línea 30 WpfApplication1.exe! WpfApplication1.RelayCommand.CanExecute (parámetro de objeto) Línea 41 + 0x1a bytes PresentationFramework.dll! MS.Internal.Commands.CommandHelpers.CanExecuteCommandSource (Syste m.Windows.Input.ICommandSource commandSource) + 0x8a bytes PresentationFramework.dll! System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute() + 0x18 bytes PresentationFramework.dll! System.Windows.Controls.Primitives.ButtonBase.OnCanExecuteChanged (object remitente, System.EventArgs e) + 0x5 bytes PresentationCore.dll! System.Windows.Input.CommandManager.CallWeakReferenceHandlers (System.Collections.Generic.List handlers) + 0xac bytes PresentationCore.dll! System.Windows.Input.CommandManager. RaiseRequerySuggested (objeto obj) + 0xf bytes
P2: (? no sólo el primero) Además, tiene esto siguen ocurriendo si elimina todos los botones de la lista
Sí.
Extraño RelayCommand. ¿Qué es esto? – Gqqnbig
Agregué un enlace a una implementación de RelayCommand. –
¿Ha intentado verificar la pila de llamadas durante el evento y ver qué lo activó? Además, ¿esto sigue sucediendo si elimina * todos * los botones de la lista (no solo el primero?) –