簡體   English   中英

WinUI 3 使用 DataTemplate 時如何將命令綁定到 ViewModel 屬性?

[英]WinUI 3 How to Bind Command to ViewModel property when using a DataTemplate?

我正在使用一個名為MainGridGrid來 position 一個ItemsRepeater ,它的ItemsSource綁定到我的ViewModel中的ObservableCollection

<muxc:ItemsRepeater
    ItemsSource="{Binding Path=Molts}"
    Layout="{StaticResource VerticalStackLayout}"
    ItemTemplate="{StaticResource MoltTemplate}">
</muxc:ItemsRepeater>

我創建了一個DataTemplate

<DataTemplate x:Key="MoltTemplate">
    <StackPanel Orientation="Horizontal">
        <TextBlock x:Name="text" Text="{Binding ID}"></TextBlock>
        <Button Command="{Binding DisplayAvailAIsCommand}" CommandParameter="{Binding ElementName=text, Path=Text}">Add</Button>
    </StackPanel>
</DataTemplate>

其中有一個TextBoxButton 我希望Button在我的ViewModel中觸發命令,但ItemsRepeater中的項目將其DataContext設置為Model class 而不是ViewModel 我發現這篇文章指出我可以通過將ElementName設置為一個 UI 元素來更改我的ButtonCommand以將DataContext設置為我的ViewModel ,該 UI 元素的DataContextViewModel

<Button Command="{Binding DataContext.DisplayAvailAIsCommand, ElementName=MainGrid}" CommandParameter="{Binding ElementName=text, Path=Text}">Add</Button>

我的 window 的構造函數像這樣設置MainGridDataContext

public MainWindow()
{
    this.InitializeComponent();
    MainGrid.DataContext = new MoltViewModel();
}

但是,這不起作用,並且命令不會觸發。 我究竟做錯了什么?

您可以通過創建綁定到源屬性的附加屬性來解決此限制:

public abstract class BindingServices : DependencyObject
{
    public static readonly DependencyProperty ViewModelCommandProperty = DependencyProperty.RegisterAttached(
      "ViewModelCommand",
      typeof(string),
      typeof(BindingServices),
      new PropertyMetadata(null, new PropertyChangedCallback(OnSet))
    );

    public static void SetViewModelCommand(Button element, string value) =>
        element.SetValue(ViewModelCommandProperty, value);

    public static string GetViewModelCommand(Button element) =>
        (string)element.GetValue(ViewModelCommandProperty);

    private static void OnSet(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Button button = (Button)d;
        button.Loaded += OnButtonLoaded;
    }

    private static void OnButtonLoaded(object sender, RoutedEventArgs e)
    {
        Button button = (Button)sender;
        button.Loaded -= OnButtonLoaded;
        button.SetBinding(ButtonBase.CommandProperty, new Binding()
        {
            Path = new PropertyPath(GetViewModelCommand(button)),
            Source = FindParent<ItemsRepeater>(button)?.DataContext
        });
    }

    private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
    {
        DependencyObject parent = VisualTreeHelper.GetParent(dependencyObject);
        if (parent == null)
            return null;

        return (parent as T) ?? FindParent<T>(parent);
    }
}

上述實現查找父ItemsRepeaterDataContext的屬性。

示例用法:

<Button ... local:BindingServices.ViewModelCommand="DisplayAvailAIsCommand" />

或者,您可以處理Click事件並從視圖的代碼隱藏 class 調用命令:

private void Button_Click(object sender, RoutedEventArgs e) =>
    (MainGrid.DataContext as MoltViewModel)?.DisplayAvailAIsCommand?.Execute(null);

XAML:

<Button ... Click="Button_Click" />

這不會破壞 MVVM 模式,因為您從與使用{Binding DisplayAvailAIsCommand} XAML 標記連接命令時相同的視圖調用相同的視圖 model 命令。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM