MVVM узнать, какая кнопка нажата?

206
21 октября 2021, 06:20

Я создаю ItemsControl, который содержит в себе структуру Grid. ItemTemplate у него - набор кнопок, которые генерируются на основе Dictionary<string, List<Exercise>> Exercises = new Dictionary<string, List<Exercise>>();-которая хранит тренировки по каких днях они проходят (так как количество этих кнопок динамически изменяется).

Я хочу узнать, какая кнопка нажата и потом ввести информацию про упражнение.

xml

 <ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
                        <ItemsControl  Name="ICTraining">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Grid >
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="25*"/>
                                            <RowDefinition Height="5*"/>
                                            <RowDefinition Height="57*"/>
                                            <RowDefinition Height="141*"/>
                                        </Grid.RowDefinitions>
                                        <TextBlock Grid.Row="0" FontWeight="Bold" Text="{Binding Key}"  FontSize="20" Margin="5" />
                                        <Separator Grid.Row="1"/>
                                        <ItemsControl  Grid.Row="2"    ItemsSource="{Binding Path=Value}" >
                                            <ItemsControl.ItemTemplate>
                                                <DataTemplate>
                                                    <Grid >
                                                        <Grid.ColumnDefinitions>
                                                            <ColumnDefinition Width="21*"/>
                                                            <ColumnDefinition Width="110*"/>
                                                        </Grid.ColumnDefinitions>
                                                        <Image Source="{Binding Image}" Grid.Column="0"  Margin="1"   Width="190" Height="150"/>
                                                        <Grid Grid.Column="1" >
                                                            <Grid.ColumnDefinitions>
                                                                <ColumnDefinition Width="554*"/>
                                                                <ColumnDefinition Width="111*"/>
                                                            </Grid.ColumnDefinitions>
                                                            <Grid.RowDefinitions>
                                                                <RowDefinition Height="217*"/>
                                                                <RowDefinition Height="64*"/>
                                                                <RowDefinition Height="217*"/>
                                                            </Grid.RowDefinitions>
                                                            <TextBlock Grid.Row="1" FontWeight="Bold" FontSize="13"  Grid.Column="0" Margin="15,0,0,0" Text="{Binding Name}"/>
                                                            <Button  Command="{Binding buttonClick}"   Content="Посмотреть" FontSize="15"   Grid.Column="1" Grid.Row="1"  MinHeight="44"  MaxHeight="100"  Margin="2" />
                                                        </Grid>
                                                    </Grid>
                                                </DataTemplate>
                                            </ItemsControl.ItemTemplate>
                                        </ItemsControl>
                                    </Grid>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </ScrollViewer
  • Тесты

RelayCommand-работа команд

public class RelayCommand : ICommand
    {
        #region Fields
        /// <summary>
        /// Encapsulated the execute action
        /// </summary>
        private Action<object> execute;
        /// <summary>
        /// Encapsulated the representation for the validation of the execute method
        /// </summary>
        private Predicate<object> canExecute;
        #endregion // Fields
        #region Constructors
        /// <summary>
        ///Инициализирует новый экземпляр класса RelayCommand
        /// Создает новую команду, которая всегда может быть выполнена.
        /// </summary>
        /// <param name="execute">Логика исполнения.</param>
        public RelayCommand(Action<object> execute): this(execute, DefaultCanExecute) {}
        /// <summary>
        /// Инициализирует новый экземпляр класса RelayCommand
        /// Создает новую команду.
        /// </summary>
        /// <param name="execute">Логика исполнения.</param>
        /// <param name="canExecute">Логика статуса выполнения.</param>
        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
            {
                throw new ArgumentNullException("execute");
            }
            if (canExecute == null)
            {
                throw new ArgumentNullException("canExecute");
            }
            this.execute = execute;
            this.canExecute = canExecute;
        }
        #endregion // Constructors
        #region ICommand Members
        /// <summary>
        /// An event to raise when the CanExecute value is changed
        /// </summary>
        /// <remarks>
        /// Любая подписка на это событие будет автоматически подписываться как на 
        /// локальный метод OnCanExecuteChanged И
        /// событие CommandManager.RequerySuggested
        /// </remarks>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
                this.CanExecuteChangedInternal += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
                this.CanExecuteChangedInternal -= value;
            }
        }
        /// <summary>
        /// Событие, которое позволяет событию CanExecuteChanged быть вызванным вручную
        /// </summary>
        private event EventHandler CanExecuteChangedInternal;
        /// <summary>
        /// Defines if command can be executed
        /// </summary>
        /// <param name="parameter">the parameter that represents the validation method</param>
        /// <returns>true if the command can be executed</returns>
        public bool CanExecute(object parameter)
        {
            return this.canExecute != null && this.canExecute(parameter);
        }
        /// <summary>
        /// Execute the encapsulated command
        /// </summary>
        /// <param name="parameter">the parameter that represents the execution method</param>
        public void Execute(object parameter)
        {
            this.execute(parameter);
        }
        #endregion // ICommand Members
        /// <summary>
        /// Raises the can execute changed.
        /// </summary>
        public void OnCanExecuteChanged()
        {
            EventHandler handler = this.CanExecuteChangedInternal;
            if (handler != null)
            {
                //DispatcherHelper.BeginInvokeOnUIThread(() => handler.Invoke(this, EventArgs.Empty));
                handler.Invoke(this, EventArgs.Empty);
            }
        }
        /// <summary>
        /// Уничтожает этот экземпляр.
        /// </summary>
        public void Destroy()
        {
            this.canExecute = _ => false;
            this.execute = _ => { return; };
        }
        /// <summary>
        /// Defines if command can be executed (default behaviour)
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        /// <returns>Always true</returns>
        private static bool DefaultCanExecute(object parameter)
        {
            return true;
        }
    }

ViewModel

class MainWindowViewModel
    {
        private bool canExecute = true;
        private ICommand buttonClickCommand;
        public bool CanExecute
        {
            get
            {
                return this.canExecute;
            }
            set
            {
                if (this.canExecute == value)
                {
                    return;
                }
                this.canExecute = value;
            }
        }

        public ICommand ButtonClickCommand
        {
            get
            {
                return buttonClickCommand;
            }
            set
            {
                buttonClickCommand = value;
            }
        }
        public MainWindowViewModel()
        {
            ButtonClickCommand = new RelayCommand(ShowMessage, param => this.canExecute);
        }
        public void ShowMessage(object obj)
        {
            MessageBox.Show(obj.ToString());
        }
    }

Wpf две кнопки пример

<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
        <ItemsControl  Name="ICTraining">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid >
                        <Grid.RowDefinitions>
                            <RowDefinition Height="82*" />
                            <RowDefinition Height="237*"/>
                        </Grid.RowDefinitions>

                        <TextBlock Visibility="Hidden" x:Name="ExerciseId" Text="{Binding Name }"/>
                        <Button Content="Click me" Command="{Binding ButtonClickCommand}" 
                CommandParameter="{Binding ElementName=ExerciseId, Path=Text}" Margin="189,8,228,0"   />
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>

Wpf одна кнопка пример(я тут не привязкой меняю свойство TextBlock а при нажатии на кнопку)

Window x:Class="WpfExample.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:local="clr-namespace:WpfExample">
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid Background="Black">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Visibility="Hidden" x:Name="ExerciseId" Text="1"/> 
        <Button Content="Click me"
               Grid.Row="0" Command="{Binding ButtonClickCommand}" 
                CommandParameter="{Binding ElementName=ExerciseId, Path=Text}" 
                Width="100"
                Height="100"  />
        <TextBox x:Name="textBox"  HorizontalAlignment="Left" Height="23" Margin="177,71,0,0" Grid.Row="1" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
        <Button x:Name="change" Content="Ghange vulue" Grid.Row="1" Margin="320,62,93,65" RenderTransformOrigin="1.437,0.74" Click="Change_Click"   />
    </Grid>
</Window>
Answer 1

Можно разместить в <DataTemplate> какой-нибудь скрытый лейбл, текстом которого будет айдишник упражнения

<Label Visibility="Hidden" x:Name="ExerciseId" Content="{Binding Id}"></Label>

Далее текст этого лейбла передать в параметр команды

<Button 
    Command="{Binding buttonClick}"
    CommandParameter="{Binding ElementName=ExerciseId, Path=Content}"   
    Content="Посмотреть" 
    ...
/>
READ ALSO
Загрузка AssetBundle с хостинга в Unity

Загрузка AssetBundle с хостинга в Unity

Необходимо загрузить AssetBundle с хостингаНаписал такой код для загрузки с сервера:

91
Управляемая 3D модель в C#.NET

Управляемая 3D модель в C#.NET

Прошу помочь в решении задачи: Есть некоторое количество 3-х мерных моделейТак же имеется несколько моделей управления, которые по начальным...

97
Изменение свойств обьекта

Изменение свойств обьекта

Я хочу изменить свойства обьекта

156