Principale utente con più risposte
ListBox formata da Template contentente dei Button, come gestire l'evento Click

Domanda
-
Il titolo non è molto chiaro, provo ad essere più esaustivo. Ho creato una ListBox:
<ListBox Margin="0" ItemsSource="{Binding Source={StaticResource AddCategoria}}" ItemTemplate="{StaticResource CategoriaTemplate}" IsSynchronizedWithCurrentItem="True" Grid.RowSpan="2"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel HorizontalAlignment="Left" VerticalAlignment="Center" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox>
Che fa riferimento ad un data DataTemplate:
<DataTemplate x:Key="CategoriaTemplate"> <Border Name="border" BorderBrush="Gray" BorderThickness="1" Padding="5" Margin="5" > <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="8*" /> <ColumnDefinition Width="2*"/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center" Text="Prova ancora" Margin="5"/> <Button x:Name="B_CancellaCategoria" Grid.Row="0" Grid.Column="1" Style="{StaticResource ButtonRed}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2"> <Viewbox> <TextBlock Text="X"/> </Viewbox> </Button> </Grid> </Border> </DataTemplate>
Che contiere un Bottone (non riporto il codice per xaml dello stile).
Sostanzialmente io ho una lista di categorie con un pulsante, lo scopo di questi è eliminare la categoria se viene premuto.
Come faccio a gestire l'elemento Click del Button?(Grazie)
- Modificato StarSquare giovedì 17 ottobre 2019 15:03
- Spostato Evgin IsmailMicrosoft contingent staff, Moderator venerdì 18 ottobre 2019 09:08 WPF
Risposte
-
Buongiorno,
per fare quello che ti server puoi utilizzare i RoutedEvent nel tuo esempio specifico:
<ListBox Margin="0" ItemsSource="{Binding Source={StaticResource AddCategoria}}" ItemTemplate="{StaticResource CategoriaTemplate}" IsSynchronizedWithCurrentItem="True" ButtonBase.Click="DeleteButton_Click" Grid.RowSpan="2"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel HorizontalAlignment="Left" VerticalAlignment="Center" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox>
ed inserire nel code behind:
private void DeleteButton_Click(object sender, RoutedEventArgs e) { System.Diagnostics.Debug.WriteLine((e.OriginalSource as FrameworkElement).DataContext); }
Il DataContext conterrà il riferimento alla categoria su cui si è fatto il click.
Però se non sei in fase avanzata di progettazione realizzazione di consiglierei di cambiare approccio e di progettarlo secondo i paradigmi del pattern MVVM, questo pattern permette di disaccoppiare la presentazione dalla logica business rendendo più manutensibile ed estensibile.
In rete puoi trovare diversa e frameworks che ti aiutano nella scrittura di applicazioni con questo pattern. Secondo me una buona documentazione per iniziare è questo articolo su MSDN Magazine.
- Contrassegnato come risposta StarSquare venerdì 18 ottobre 2019 10:48
-
Il bello è il brutto di wpf e che per fare le medesime cose ci sono varie strategie metodi.
Per puoi sostituire cosi direttamente Click con Command. La soluzione che preferisco io è questa:
public class BindingProxy : Freezable { #region Overrides of Freezable protected override Freezable CreateInstanceCore() { return new BindingProxy(); } #endregion public object Data { get { return (object)GetValue(DataProperty); } set { SetValue(DataProperty, value); } } // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc... public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); }
/// <summary> /// This class allows delegating the commanding logic to methods passed as parameters, /// and enables a View to bind commands to objects that are not part of the element tree. /// </summary> public class DelegateCommand : ICommand { #region Constructors /// <summary> /// Constructor /// </summary> public DelegateCommand(Action executeMethod) : this(executeMethod, null, false) { } /// <summary> /// Constructor /// </summary> public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod) : this(executeMethod, canExecuteMethod, false) { } /// <summary> /// Constructor /// </summary> public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod, bool isAutomaticRequeryDisabled) { if (executeMethod == null) { throw new ArgumentNullException("executeMethod"); } _executeMethod = executeMethod; _canExecuteMethod = canExecuteMethod; _isAutomaticRequeryDisabled = isAutomaticRequeryDisabled; } #endregion #region Public Methods /// <summary> /// Method to determine if the command can be executed /// </summary> public bool CanExecute() { if (_canExecuteMethod != null) { return _canExecuteMethod(); } return true; } /// <summary> /// Execution of the command /// </summary> public void Execute() { if (_executeMethod != null) { _executeMethod(); } } /// <summary> /// Property to enable or disable CommandManager's automatic requery on this command /// </summary> public bool IsAutomaticRequeryDisabled { get { return _isAutomaticRequeryDisabled; } set { if (_isAutomaticRequeryDisabled != value) { if (value) { CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers); } else { CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers); } _isAutomaticRequeryDisabled = value; } } } /// <summary> /// Raises the CanExecuteChaged event /// </summary> public void RaiseCanExecuteChanged() { OnCanExecuteChanged(); } /// <summary> /// Protected virtual method to raise CanExecuteChanged event /// </summary> protected virtual void OnCanExecuteChanged() { CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers); } #endregion #region ICommand Members /// <summary> /// ICommand.CanExecuteChanged implementation /// </summary> public event EventHandler CanExecuteChanged { add { if (!_isAutomaticRequeryDisabled) { CommandManager.RequerySuggested += value; } CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2); } remove { if (!_isAutomaticRequeryDisabled) { CommandManager.RequerySuggested -= value; } CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value); } } bool ICommand.CanExecute(object parameter) { return CanExecute(); } void ICommand.Execute(object parameter) { Execute(); } #endregion #region Data private readonly Action _executeMethod = null; private readonly Func<bool> _canExecuteMethod = null; private bool _isAutomaticRequeryDisabled = false; private List<WeakReference> _canExecuteChangedHandlers; #endregion } /// <summary> /// This class allows delegating the commanding logic to methods passed as parameters, /// and enables a View to bind commands to objects that are not part of the element tree. /// </summary> /// <typeparam name="T">Type of the parameter passed to the delegates</typeparam> public class DelegateCommand<T> : ICommand { #region Constructors /// <summary> /// Constructor /// </summary> public DelegateCommand(Action<T> executeMethod) : this(executeMethod, null, false) { } /// <summary> /// Constructor /// </summary> public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod) : this(executeMethod, canExecuteMethod, false) { } /// <summary> /// Constructor /// </summary> public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod, bool isAutomaticRequeryDisabled) { if (executeMethod == null) { throw new ArgumentNullException("executeMethod"); } _executeMethod = executeMethod; _canExecuteMethod = canExecuteMethod; _isAutomaticRequeryDisabled = isAutomaticRequeryDisabled; } #endregion #region Public Methods /// <summary> /// Method to determine if the command can be executed /// </summary> public bool CanExecute(T parameter) { if (_canExecuteMethod != null) { return _canExecuteMethod(parameter); } return true; } /// <summary> /// Execution of the command /// </summary> public void Execute(T parameter) { if (_executeMethod != null) { _executeMethod(parameter); } } /// <summary> /// Raises the CanExecuteChaged event /// </summary> public void RaiseCanExecuteChanged() { OnCanExecuteChanged(); } /// <summary> /// Protected virtual method to raise CanExecuteChanged event /// </summary> protected virtual void OnCanExecuteChanged() { CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers); } /// <summary> /// Property to enable or disable CommandManager's automatic requery on this command /// </summary> public bool IsAutomaticRequeryDisabled { get { return _isAutomaticRequeryDisabled; } set { if (_isAutomaticRequeryDisabled != value) { if (value) { CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers); } else { CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers); } _isAutomaticRequeryDisabled = value; } } } #endregion #region ICommand Members /// <summary> /// ICommand.CanExecuteChanged implementation /// </summary> public event EventHandler CanExecuteChanged { add { if (!_isAutomaticRequeryDisabled) { CommandManager.RequerySuggested += value; } CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2); } remove { if (!_isAutomaticRequeryDisabled) { CommandManager.RequerySuggested -= value; } CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value); } } bool ICommand.CanExecute(object parameter) { // if T is of value type and the parameter is not // set yet, then return false if CanExecute delegate // exists, else return true if (parameter == null && typeof(T).IsValueType) { return (_canExecuteMethod == null); } return CanExecute((T)parameter); } void ICommand.Execute(object parameter) { Execute((T)parameter); } #endregion #region Data private readonly Action<T> _executeMethod = null; private readonly Func<T, bool> _canExecuteMethod = null; private bool _isAutomaticRequeryDisabled = false; private List<WeakReference> _canExecuteChangedHandlers; #endregion } /// <summary> /// This class contains methods for the CommandManager that help avoid memory leaks by /// using weak references. /// </summary> internal class CommandManagerHelper { internal static void CallWeakReferenceHandlers(List<WeakReference> handlers) { if (handlers != null) { // Take a snapshot of the handlers before we call out to them since the handlers // could cause the array to me modified while we are reading it. EventHandler[] callees = new EventHandler[handlers.Count]; int count = 0; for (int i = handlers.Count - 1; i >= 0; i--) { WeakReference reference = handlers[i]; EventHandler handler = reference.Target as EventHandler; if (handler == null) { // Clean up old handlers that have been collected handlers.RemoveAt(i); } else { callees[count] = handler; count++; } } // Call the handlers that we snapshotted for (int i = 0; i < count; i++) { EventHandler handler = callees[i]; handler(null, EventArgs.Empty); } } } internal static void AddHandlersToRequerySuggested(List<WeakReference> handlers) { if (handlers != null) { foreach (WeakReference handlerRef in handlers) { EventHandler handler = handlerRef.Target as EventHandler; if (handler != null) { CommandManager.RequerySuggested += handler; } } } } internal static void RemoveHandlersFromRequerySuggested(List<WeakReference> handlers) { if (handlers != null) { foreach (WeakReference handlerRef in handlers) { EventHandler handler = handlerRef.Target as EventHandler; if (handler != null) { CommandManager.RequerySuggested -= handler; } } } } internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler) { AddWeakReferenceHandler(ref handlers, handler, -1); } internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler, int defaultListSize) { if (handlers == null) { handlers = (defaultListSize > 0 ? new List<WeakReference>(defaultListSize) : new List<WeakReference>()); } handlers.Add(new WeakReference(handler)); } internal static void RemoveWeakReferenceHandler(List<WeakReference> handlers, EventHandler handler) { if (handlers != null) { for (int i = handlers.Count - 1; i >= 0; i--) { WeakReference reference = handlers[i]; EventHandler existingHandler = reference.Target as EventHandler; if ((existingHandler == null) || (existingHandler == handler)) { // Clean up old handlers that have been collected // in addition to the handler that is to be removed. handlers.RemoveAt(i); } } } } }
class CategoryItemViewModel :ViewModelBase { } class CategoriesViewModel:ViewModelBase { public CategoriesViewModel() { } public ObservableCollection<CategoryItemViewModel> Categories { get; } ICommand _AddCommand; public ICommand AddCommand { get { if (_AddCommand == null) { _AddCommand = new Commands.DelegateCommand(Add); } return _AddCommand; } } void Add() { } ICommand _RemoveCommand; public ICommand RemoveCommand { get { if (_RemoveCommand == null) { _RemoveCommand = new Commands.DelegateCommand<CategoryItemViewModel>(Remove); } return _RemoveCommand; } } void Remove(CategoryItemViewModel category) { } }
<Window ... xmlns:vm="clr-namespace:Test.ViewModels"> <Window.Resources> <l:BindingProxy Data="{Binding}" x:Key="vmProxy"/> ... <DataTemplate x:Key="CategoriaTemplate"> <Border Name="border" BorderBrush="Gray" BorderThickness="1" Padding="5" Margin="5" > <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="8*" /> <ColumnDefinition Width="2*"/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center" Text="Prova ancora" Margin="5"/> <Button Grid.Row="0" Grid.Column="1" Style="{StaticResource ButtonRed}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" Command="{Binding Data.RemoveCommand, Mode=OneTime, Source={StaticResource vmProxy}}" CommandParameter="{Binding}"> <Viewbox> <TextBlock Text="X"/> </Viewbox> </Button> </Grid> </Border> </DataTemplate> </Window.Resources> <Window.DataContext> <vm:CategoriesViewModel/> </Window.DataContext> ... <ListBox ItemsSource="{Binding Categories}" ItemTemplate="{StaticResource CategoriaTemplate}" IsSynchronizedWithCurrentItem="True" Grid.RowSpan="2"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel HorizontalAlignment="Left" VerticalAlignment="Center" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> ... </Window>
- Contrassegnato come risposta StarSquare sabato 19 ottobre 2019 10:12
Tutte le risposte
-
Buongiorno,
per fare quello che ti server puoi utilizzare i RoutedEvent nel tuo esempio specifico:
<ListBox Margin="0" ItemsSource="{Binding Source={StaticResource AddCategoria}}" ItemTemplate="{StaticResource CategoriaTemplate}" IsSynchronizedWithCurrentItem="True" ButtonBase.Click="DeleteButton_Click" Grid.RowSpan="2"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel HorizontalAlignment="Left" VerticalAlignment="Center" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox>
ed inserire nel code behind:
private void DeleteButton_Click(object sender, RoutedEventArgs e) { System.Diagnostics.Debug.WriteLine((e.OriginalSource as FrameworkElement).DataContext); }
Il DataContext conterrà il riferimento alla categoria su cui si è fatto il click.
Però se non sei in fase avanzata di progettazione realizzazione di consiglierei di cambiare approccio e di progettarlo secondo i paradigmi del pattern MVVM, questo pattern permette di disaccoppiare la presentazione dalla logica business rendendo più manutensibile ed estensibile.
In rete puoi trovare diversa e frameworks che ti aiutano nella scrittura di applicazioni con questo pattern. Secondo me una buona documentazione per iniziare è questo articolo su MSDN Magazine.
- Contrassegnato come risposta StarSquare venerdì 18 ottobre 2019 10:48
-
Grazie per la risposta e per l'articolo che leggero immediatamente, ho iniziato da poco ad addentrarmi nel pattern MVVM, nel mio codice ho inserito una classe RelayCommand
class RelayCommand : ICommand { public event EventHandler CanExecuteChanged; private Action<object> executeMethod; private Predicate<object> canExecuteMethod; public RelayCommand(Action<object> Execute, Predicate<object> CanExecute) { executeMethod = Execute; canExecuteMethod = CanExecute; } public RelayCommand(Action<object> Execute) : this(Execute, null) { } public bool CanExecute(object parameter) { return (canExecuteMethod == null) ? true : canExecuteMethod.Invoke(parameter); } public void Execute(object parameter) { executeMethod.Invoke(parameter); } public void RaiseCanExecuteChanged() { CanExecuteChanged?.Invoke(this, EventArgs.Empty); } }
In questo caso anzichè utilizzare il comando
ButtonBase.Click="DeleteButton_Click"
Utilizzo il Command?
Grazie
-
Il bello è il brutto di wpf e che per fare le medesime cose ci sono varie strategie metodi.
Per puoi sostituire cosi direttamente Click con Command. La soluzione che preferisco io è questa:
public class BindingProxy : Freezable { #region Overrides of Freezable protected override Freezable CreateInstanceCore() { return new BindingProxy(); } #endregion public object Data { get { return (object)GetValue(DataProperty); } set { SetValue(DataProperty, value); } } // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc... public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); }
/// <summary> /// This class allows delegating the commanding logic to methods passed as parameters, /// and enables a View to bind commands to objects that are not part of the element tree. /// </summary> public class DelegateCommand : ICommand { #region Constructors /// <summary> /// Constructor /// </summary> public DelegateCommand(Action executeMethod) : this(executeMethod, null, false) { } /// <summary> /// Constructor /// </summary> public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod) : this(executeMethod, canExecuteMethod, false) { } /// <summary> /// Constructor /// </summary> public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod, bool isAutomaticRequeryDisabled) { if (executeMethod == null) { throw new ArgumentNullException("executeMethod"); } _executeMethod = executeMethod; _canExecuteMethod = canExecuteMethod; _isAutomaticRequeryDisabled = isAutomaticRequeryDisabled; } #endregion #region Public Methods /// <summary> /// Method to determine if the command can be executed /// </summary> public bool CanExecute() { if (_canExecuteMethod != null) { return _canExecuteMethod(); } return true; } /// <summary> /// Execution of the command /// </summary> public void Execute() { if (_executeMethod != null) { _executeMethod(); } } /// <summary> /// Property to enable or disable CommandManager's automatic requery on this command /// </summary> public bool IsAutomaticRequeryDisabled { get { return _isAutomaticRequeryDisabled; } set { if (_isAutomaticRequeryDisabled != value) { if (value) { CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers); } else { CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers); } _isAutomaticRequeryDisabled = value; } } } /// <summary> /// Raises the CanExecuteChaged event /// </summary> public void RaiseCanExecuteChanged() { OnCanExecuteChanged(); } /// <summary> /// Protected virtual method to raise CanExecuteChanged event /// </summary> protected virtual void OnCanExecuteChanged() { CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers); } #endregion #region ICommand Members /// <summary> /// ICommand.CanExecuteChanged implementation /// </summary> public event EventHandler CanExecuteChanged { add { if (!_isAutomaticRequeryDisabled) { CommandManager.RequerySuggested += value; } CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2); } remove { if (!_isAutomaticRequeryDisabled) { CommandManager.RequerySuggested -= value; } CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value); } } bool ICommand.CanExecute(object parameter) { return CanExecute(); } void ICommand.Execute(object parameter) { Execute(); } #endregion #region Data private readonly Action _executeMethod = null; private readonly Func<bool> _canExecuteMethod = null; private bool _isAutomaticRequeryDisabled = false; private List<WeakReference> _canExecuteChangedHandlers; #endregion } /// <summary> /// This class allows delegating the commanding logic to methods passed as parameters, /// and enables a View to bind commands to objects that are not part of the element tree. /// </summary> /// <typeparam name="T">Type of the parameter passed to the delegates</typeparam> public class DelegateCommand<T> : ICommand { #region Constructors /// <summary> /// Constructor /// </summary> public DelegateCommand(Action<T> executeMethod) : this(executeMethod, null, false) { } /// <summary> /// Constructor /// </summary> public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod) : this(executeMethod, canExecuteMethod, false) { } /// <summary> /// Constructor /// </summary> public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod, bool isAutomaticRequeryDisabled) { if (executeMethod == null) { throw new ArgumentNullException("executeMethod"); } _executeMethod = executeMethod; _canExecuteMethod = canExecuteMethod; _isAutomaticRequeryDisabled = isAutomaticRequeryDisabled; } #endregion #region Public Methods /// <summary> /// Method to determine if the command can be executed /// </summary> public bool CanExecute(T parameter) { if (_canExecuteMethod != null) { return _canExecuteMethod(parameter); } return true; } /// <summary> /// Execution of the command /// </summary> public void Execute(T parameter) { if (_executeMethod != null) { _executeMethod(parameter); } } /// <summary> /// Raises the CanExecuteChaged event /// </summary> public void RaiseCanExecuteChanged() { OnCanExecuteChanged(); } /// <summary> /// Protected virtual method to raise CanExecuteChanged event /// </summary> protected virtual void OnCanExecuteChanged() { CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers); } /// <summary> /// Property to enable or disable CommandManager's automatic requery on this command /// </summary> public bool IsAutomaticRequeryDisabled { get { return _isAutomaticRequeryDisabled; } set { if (_isAutomaticRequeryDisabled != value) { if (value) { CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers); } else { CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers); } _isAutomaticRequeryDisabled = value; } } } #endregion #region ICommand Members /// <summary> /// ICommand.CanExecuteChanged implementation /// </summary> public event EventHandler CanExecuteChanged { add { if (!_isAutomaticRequeryDisabled) { CommandManager.RequerySuggested += value; } CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2); } remove { if (!_isAutomaticRequeryDisabled) { CommandManager.RequerySuggested -= value; } CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value); } } bool ICommand.CanExecute(object parameter) { // if T is of value type and the parameter is not // set yet, then return false if CanExecute delegate // exists, else return true if (parameter == null && typeof(T).IsValueType) { return (_canExecuteMethod == null); } return CanExecute((T)parameter); } void ICommand.Execute(object parameter) { Execute((T)parameter); } #endregion #region Data private readonly Action<T> _executeMethod = null; private readonly Func<T, bool> _canExecuteMethod = null; private bool _isAutomaticRequeryDisabled = false; private List<WeakReference> _canExecuteChangedHandlers; #endregion } /// <summary> /// This class contains methods for the CommandManager that help avoid memory leaks by /// using weak references. /// </summary> internal class CommandManagerHelper { internal static void CallWeakReferenceHandlers(List<WeakReference> handlers) { if (handlers != null) { // Take a snapshot of the handlers before we call out to them since the handlers // could cause the array to me modified while we are reading it. EventHandler[] callees = new EventHandler[handlers.Count]; int count = 0; for (int i = handlers.Count - 1; i >= 0; i--) { WeakReference reference = handlers[i]; EventHandler handler = reference.Target as EventHandler; if (handler == null) { // Clean up old handlers that have been collected handlers.RemoveAt(i); } else { callees[count] = handler; count++; } } // Call the handlers that we snapshotted for (int i = 0; i < count; i++) { EventHandler handler = callees[i]; handler(null, EventArgs.Empty); } } } internal static void AddHandlersToRequerySuggested(List<WeakReference> handlers) { if (handlers != null) { foreach (WeakReference handlerRef in handlers) { EventHandler handler = handlerRef.Target as EventHandler; if (handler != null) { CommandManager.RequerySuggested += handler; } } } } internal static void RemoveHandlersFromRequerySuggested(List<WeakReference> handlers) { if (handlers != null) { foreach (WeakReference handlerRef in handlers) { EventHandler handler = handlerRef.Target as EventHandler; if (handler != null) { CommandManager.RequerySuggested -= handler; } } } } internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler) { AddWeakReferenceHandler(ref handlers, handler, -1); } internal static void AddWeakReferenceHandler(ref List<WeakReference> handlers, EventHandler handler, int defaultListSize) { if (handlers == null) { handlers = (defaultListSize > 0 ? new List<WeakReference>(defaultListSize) : new List<WeakReference>()); } handlers.Add(new WeakReference(handler)); } internal static void RemoveWeakReferenceHandler(List<WeakReference> handlers, EventHandler handler) { if (handlers != null) { for (int i = handlers.Count - 1; i >= 0; i--) { WeakReference reference = handlers[i]; EventHandler existingHandler = reference.Target as EventHandler; if ((existingHandler == null) || (existingHandler == handler)) { // Clean up old handlers that have been collected // in addition to the handler that is to be removed. handlers.RemoveAt(i); } } } } }
class CategoryItemViewModel :ViewModelBase { } class CategoriesViewModel:ViewModelBase { public CategoriesViewModel() { } public ObservableCollection<CategoryItemViewModel> Categories { get; } ICommand _AddCommand; public ICommand AddCommand { get { if (_AddCommand == null) { _AddCommand = new Commands.DelegateCommand(Add); } return _AddCommand; } } void Add() { } ICommand _RemoveCommand; public ICommand RemoveCommand { get { if (_RemoveCommand == null) { _RemoveCommand = new Commands.DelegateCommand<CategoryItemViewModel>(Remove); } return _RemoveCommand; } } void Remove(CategoryItemViewModel category) { } }
<Window ... xmlns:vm="clr-namespace:Test.ViewModels"> <Window.Resources> <l:BindingProxy Data="{Binding}" x:Key="vmProxy"/> ... <DataTemplate x:Key="CategoriaTemplate"> <Border Name="border" BorderBrush="Gray" BorderThickness="1" Padding="5" Margin="5" > <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="8*" /> <ColumnDefinition Width="2*"/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center" Text="Prova ancora" Margin="5"/> <Button Grid.Row="0" Grid.Column="1" Style="{StaticResource ButtonRed}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2" Command="{Binding Data.RemoveCommand, Mode=OneTime, Source={StaticResource vmProxy}}" CommandParameter="{Binding}"> <Viewbox> <TextBlock Text="X"/> </Viewbox> </Button> </Grid> </Border> </DataTemplate> </Window.Resources> <Window.DataContext> <vm:CategoriesViewModel/> </Window.DataContext> ... <ListBox ItemsSource="{Binding Categories}" ItemTemplate="{StaticResource CategoriaTemplate}" IsSynchronizedWithCurrentItem="True" Grid.RowSpan="2"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel HorizontalAlignment="Left" VerticalAlignment="Center" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> ... </Window>
- Contrassegnato come risposta StarSquare sabato 19 ottobre 2019 10:12
-
-