none
ListBox formata da Template contentente dei Button, come gestire l'evento Click RRS feed

  • 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)


    giovedì 17 ottobre 2019 15:00

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
    venerdì 18 ottobre 2019 09:36
  • 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
    venerdì 18 ottobre 2019 13:28

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
    venerdì 18 ottobre 2019 09:36
  • 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

    venerdì 18 ottobre 2019 11:42
  • 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
    venerdì 18 ottobre 2019 13:28
  • Grazie per l'aiuto...ora mi studio bene il codice e approfondisco il pattern MVVM grazei ancora
    sabato 19 ottobre 2019 10:13
  • Di niente :).
    lunedì 21 ottobre 2019 13:43