XAML WPF DataBinding、MVVM和路由事件

gmxoilav  于 2023-03-27  发布在  其他
关注(0)|答案(2)|浏览(113)

当我尝试在XAML中使用Command Delegate绑定调用我的UserControl的自定义RoutedEvent时,我会得到以下异常:

Exception thrown: 'System.Windows.Markup.XamlParseException' in PresentationFramework.dll 
Additional information: 'Provide value on 'System.Windows.Data.Binding' threw an exception.'

我的WPF应用程序使用MVVM和IOC,因此所有逻辑都在视图模型中。
视图的DataContext在资源字典中设置:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:vw="clr-namespace:MyApp.Order.View"
            xmlns:vm="clr-namespace:MyApp.Order.ViewModel">

<DataTemplate DataType="{x:Type vm:OrderViewModel}">
    <vw:OrderView />
</DataTemplate>

等等
我在这个解决方案中的另一个项目中有一个UserControl,它恰好是一个键盘,我已经像这样连接了一个路由事件:

public partial class MainKeyboard : UserControl
{
    public static DependencyProperty TextProperty;
    public static DependencyProperty FirstLetterToUpperProperty;

    // Create a custom routed event by first registering a RoutedEventID
    // This event uses the bubbling routing strategy
    public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
        "Tap", RoutingStrategy.Bubble, 
        typeof(RoutedEventHandler), 
        typeof(MainKeyboard));

    // Provide CLR accessors for the event
    public event RoutedEventHandler Tap
    {
        add { AddHandler(TapEvent, value); }
        remove { RemoveHandler(TapEvent, value); }
    }

    // This method raises the Tap event
    void RaiseTapEvent()
    {
        RoutedEventArgs newEventArgs = new RoutedEventArgs(MainKeyboard.TapEvent);
        RaiseEvent(newEventArgs);
    }

现在,当我使用我的XAML声明消费这个事件并像往常一样将Command绑定到视图模型的命令委托时:

<assets:MainKeyboard           Tap="{Binding DoTapCommandInViewModel}" />

我得到一个错误,但我可以在其他任何地方这样做,就像在下面代码上方的按钮中:

<Button Content="GetStarted" 
                            Command="{Binding DoTapCommandInViewModel}" 
                            Style="{StaticResource GetStartedButton}" />

对我有用的是在这个XAML文件后面的代码中调用一个方法:

<assets:MainKeyboard Tap="MainKeyboard_OnTap"/>

按钮和键盘用户控件的DataContext相同;他们生活在同一个观点。
那么为什么我不能将此事件直接绑定到命令?

ds97pgxw

ds97pgxw1#

Dytori是对的;我需要一个事件触发器上的控制声明。啊Wpf...

<assets:MainKeyboard>
                    <b:Interaction.Triggers>
                        <b:EventTrigger EventName="Tap">
                            <b:InvokeCommandAction Command="{Binding DoTapTapTap}"/>
                        </b:EventTrigger>
                    </b:Interaction.Triggers>
            </assets:MainKeyboard>
mlnl4t2r

mlnl4t2r2#

虽然有点晚了,但另一种解决方案是在MainKeyboard上创建一个ICommand类型的新依赖项属性,绑定要在该依赖项属性上调用的命令,并在代码隐藏中创建一个调用该命令的Execute()方法的方法。

  • MainKeyboard中创建ICommand类型的依赖项属性和调用command的代码隐藏方法:
public partial class MainKeyboard : UserControl
{
    //dependency property of ICommand
    public static DependencyProperty TapCmdProperty =
        DependencyProperty.Register("TapCmd",
        ICommand,
        MainKeyboard,
        new PropertyMetadata(null));

    public ICommand TapCmd
    {
        get => (ICommand)GetValue(TapCmdProperty);
        set { SetValue(TapCmdProperty, value); }
    }

    //method that calls Execute() on bound command
    private void MainKeyboard_OnTap(object sender, RoutedEventArgs e)
    {
        if (TapCmd != null) TapCmd.Execute();
    }
}
  • 将ViewModel中的命令绑定到TapCmd依赖项属性,并在代码隐藏方法上调用Tap路由事件:
<assets:MainKeyboard TapCmd="{Binding DoTapCommandInViewModel}"
                     Tap="MainKeyboard_OnTap"/>

相关问题