Привязать команду всплывающей кнопки к команде ViewModel в DataTemplate - PullRequest
1 голос
/ 13 февраля 2020

Я новичок в UWP. Я пытаюсь привязать событие в моей ViewModel из выпадающего меню кнопки в виде списка, который отображается на каждом элементе. Я посмотрел на многие решения онлайн и придумал следующий код, он прекрасно компилируется, но когда я нажимаю кнопку «Изменить», ничего не происходит.

Моя ViewModel доступна из контекста страницы, а не из контекста элемента

XAML

<ListView x:Name="MainListView"
                  ItemsSource="{x:Bind ViewModel.Devices, Mode=OneWay}"
                  SelectionMode="Multiple" 
                  SelectionChanged="MainListView_SelectionChanged">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid Width="Auto">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="0*"></ColumnDefinition>
                            <ColumnDefinition Width=".4*"></ColumnDefinition>
                            <ColumnDefinition Width="3*"></ColumnDefinition>
                            <ColumnDefinition Width="3*"></ColumnDefinition>
                            <ColumnDefinition Width="3*"></ColumnDefinition>
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="2" Text="{Binding AssetNumber}"/>
                        <TextBlock Grid.Column="3" Text="{Binding SerialNumber}"/>
                        <TextBlock Grid.Column="4" Text="{Binding Model}"/>
                        <Button Grid.Column="1" Height="30" Width="30">
                            <Button.Flyout>
                                <MenuFlyout>
                                    <MenuFlyoutItem Text="Edit" Icon="Edit"
                                                    Command="{Binding ElementName=MainListView,Path=DataContext.ViewModel.EditCommand}"
                                                    CommandParameter="{Binding}"/>
                                </MenuFlyout>
                            </Button.Flyout>
                        </Button>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

View Model Class

public class MainPageViewModel
{
    // Elements contained in the main listview 
    public ObservableCollection<Device> Devices = new ObservableCollection<Device>();

    public MainPageViewModel()
    {
        DeviceProvider.Fill(ref Devices, 100);
        EditCommand = new RelayCommand<Device>(EditDevice);
    }

    public RelayCommand<Device> EditCommand { get; set; }
    private async void EditDevice(Device device)
    {
        // Code here that creates a dialog
    }
}

Класс устройства

public class Device : INotifyPropertyChanged
{
    private string assetNumber;
    private string serialNumber;
    private string model;
    public string AssetNumber
    {
        get
        {
            return assetNumber;
        }
        set
        {
            assetNumber = value;
            OnPropertyChanged();
        }
    }
    public string SerialNumber
    {
        get
        {
            return serialNumber;
        }
        set
        {
            serialNumber = value;
            OnPropertyChanged();
        }
    }
    public string Model
    {
        get
        {
            return model;
        }

        set
        {
            model = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

Класс RelayCommand

public class RelayCommand<T> : ICommand
{
    private readonly Action<T> _execute;
    private readonly Func<bool> _canExecute;

    public event EventHandler CanExecuteChanged;

    public RelayCommand(Action<T> execute) : this(execute, null)
    {
    }

    public RelayCommand(Action<T> execute, Func<bool> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute();
    }

    public void Execute(object parameter)
    {
        _execute((T)parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        var handler = CanExecuteChanged;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

Ответы [ 2 ]

1 голос
/ 14 февраля 2020

Ваш код, похоже, не имеет проблем. Так что должно работать отлично. Но если нет, то я подозреваю, что член MainPage.ViewModel может быть определен неправильно. Свойство, которое будет использоваться в {Binding}, должно быть "publi c" и должно иметь метод доступа "get".

public sealed partial class MainPage : Page
{
    public MainPageViewModel ViewModel { get; set; } = new MainPageViewModel();

    public MainPage()
    {
        this.InitializeComponent();
        DataContext = this;
    }
}
0 голосов
/ 14 февраля 2020

он компилируется нормально, но когда я нажимаю указанную кнопку Изменить, ничего не происходит.

Проблема в том, что вы неправильно связываете Path (Path = DataContext.ViewModel.EditCommand) для MenuFlyoutItem, пожалуйста, удалите поле ViewModel. И я отредактировал ваш код, пожалуйста, обратитесь к следующему.

<Page.DataContext>
    <local:MainPageViewModel x:Name="ViewModel"/>
</Page.DataContext>
 ......
<Button
    Grid.Column="1"
    Width="30"
    Height="30"
    >
    <Button.Flyout>
        <MenuFlyout>
            <MenuFlyoutItem
                Command="{Binding ElementName=MainListView, Path=DataContext.EditCommand}"
                CommandParameter="{Binding}"
                Icon="Edit"
                Text="Edit"
                />
        </MenuFlyout>
    </Button.Flyout>
</Button>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...