【问题标题】:Binding Button Click Event to a Method in ViewModel with Interaction.Triggers when Buttons are dynamically created at runtime在运行时动态创建按钮时,使用 Interaction.Triggers 将按钮单击事件绑定到 ViewModel 中的方法
【发布时间】:2020-12-10 08:33:20
【问题描述】:

在我的 C# WPF MVVM 模式应用程序中,我的视图中有一个 ItemsControl,它基于在 XAML 中定义的绑定 ItemsSource 在画布上绘制线条和按钮:

<Window.DataContext>
    <viewmodels:MainWindowViewModel />
</Window.DataContext>

.
.
.

<ItemsControl
    x:Name="DiagramViewCanvas"
    ItemsSource="{Binding DiagramObjects, UpdateSourceTrigger=PropertyChanged}">

    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type local:LineObject}">
            <Line
                X1="{Binding XStart}"
                Y1="{Binding YStart}"
                X2="{Binding XEnd}"
                Y2="{Binding YEnd}"
                Stroke="White"
                StrokeThickness="1"
                SnapsToDevicePixels="True"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:ButtonObject}">
            <Button
                Style="{DynamicResource MyDiagramButtonStyle}"
                Width="225"
                Height="30"
                Content="{Binding Content}"
                FontSize="13"
                SnapsToDevicePixels="True">
            </Button>
        </DataTemplate>
    </ItemsControl.Resources>
    
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Background="Black" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding XPosition, UpdateSourceTrigger=PropertyChanged}" />
            <Setter Property="Canvas.Top" Value="{Binding YPosition, UpdateSourceTrigger=PropertyChanged}" />
        </Style>
    </ItemsControl.ItemContainerStyle>

</ItemsControl>

这段代码运行良好。我的问题是如何将按钮的 Click 事件绑定到 ViewModel (MainWindowViewModel) 中的方法。

选项 1(由于 MVVM 模式,我不想使用它):如果我尝试如下简单的 Click 事件定义...

<Button
    Style="{DynamicResource MyDiagramButtonStyle}"
    Width="225"
    Height="30"
    Content="{Binding Content}"
    FontSize="13"
    SnapsToDevicePixels="True"
    Click="OnButtonClick"/>

...其中 OnButtonClick 在我的 XAML 代码隐藏中定义,OnButtonClick 方法被成功调用并为在运行时创建的每个 Button 执行。它工作正常

选项 2: 但是,如果我尝试使用 Interaction.Triggers 如下(这是我经常使用的方法,在我的代码中没有任何问题)以避免将代码放在后面的代码中......

<Button
    Style="{DynamicResource MyDiagramButtonStyle}"
    Width="225"
    Height="30"
    Content="{Binding Content}"
    FontSize="13"
    SnapsToDevicePixels="True">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <i:CallMethodAction TargetObject="{Binding}" MethodName="OnButtonClick"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

...在我的 MainWindowViewModel 中定义 OnButtonClick ...

public void OnButtonClick(object sender, RoutedEventArgs e)
{
    if (sender is Button btn)
    {
        // do something
    }
}

... 我收到以下错误:

System.ArgumentException: 'Could not find method named 'OnButtonClick' on object of type 'ButtonObject' that matches the expected signature.'

问题 1: 我在实现交互触发器时是否犯了一个基本错误(我的代码中有许多其他交互触发器完全可以正常工作)?还是在运行时动态创建 Button 的情况下 Interaction.Triggers 不起作用?

问题 2:我是否应该改用 ICommand(例如 Binding Commands to Events? 中提到的)?

感谢您对我做错的任何指导。

【问题讨论】:

  • “我希望 OnButtonClick 方法驻留在我的 ViewModel 中”,因此您基本上想丢弃 mvvm 的所有原则。 wpf 每一步都会为你加油,祝你好运
  • 忘记点击事件处理程序和触发器。只需在您的 ButtonObject 类中包含一个 ICommand 项目并直接绑定到该项目。

标签: c# wpf mvvm binding


【解决方案1】:

使用 Interaction.Triggers 找到了解决方案:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
        <i:CallMethodAction TargetObject="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=DataContext}" MethodName="OnButtonClick"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 2018-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多