具有多个源的wpf交互EventTrigger

mum43rcc  于 2022-11-18  发布在  其他
关注(0)|答案(2)|浏览(131)

我试图捕获从UserControl的多个示例中触发的RountedEvent。通过捕获Window级别的路由事件(local:MyControl.MyEvent=“Window_CodeBehindHandler”),这在非MVVM环境中很容易实现。但是我需要将该事件转发到视图模型,并且我正在努力使Interaction.Triggers设置具有相同的行为。如果我传入特定的SourceNameSourceObject,或者将Interaction.Triggers放置在XAML中的UserControl内,EventTrigger的行为将与预期的一样,但这并不起作用。
我已经尝试了各种版本的设置SourceNameSourceObject的控制类型或名称没有运气。
我在这里做了一个MRE:WpfInteractionEventTriggerMRE。“真实的的”实现有一个ItemsView绑定到这些控件对象在运行时创建的集合,其中发生的事情比单个“Select”事件多得多,因此“只使用已实现Click的{x}控件并重新设置其样式”的建议没有帮助。

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp5"
        xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
        mc:Ignorable="d"
        
        Title="MainWindow" Height="450" Width="800"
        
        local:ElipseControl.Select="Window_Select"> <!-- This works as expected -->

    <b:Interaction.Triggers> <!-- This does not -->
        <b:EventTrigger EventName="Select">
            <b:InvokeCommandAction Command="{Binding ElipseSelectedCommand}" />
        </b:EventTrigger>
    </b:Interaction.Triggers>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <local:ElipseControl Grid.Row="0" ElipseName="One" />
        <local:ElipseControl Grid.Row="1" ElipseName="Two" />
    </Grid>
</Window>

我希望这里有我忽略的东西。

lqfhib0f

lqfhib0f1#

您正在使用的EventTrigger不支持附加事件。您必须实现自己的custom event trigger,或者您可以简单地从窗口中的Window_Select事件处理程序调用该命令:

var viewModel = DataContext as YourViewModel;
if (viewModel != null)
    viewModel.ElipseSelectedCommand.Execute(null);

这不会以任何方式破坏MVVM模式,因为与使用交互触发器相比,您是从相同的视图调用相同的命令。MVVM不是要从视图中删除代码-而是要分离关注点。

3qpi33ja

3qpi33ja2#

自定义事件触发器起作用了。原问题中的MRE被更新了。下面是相关的更新代码。

<Window x:Class="WpfApp5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp5"
        xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
        mc:Ignorable="d"
        
        Title="MainWindow" Height="450" Width="800">
    
    <b:Interaction.Triggers>
        <local:RoutedEventTrigger RoutedEvent="local:ElipseControl.Select" >
            <b:InvokeCommandAction Command="{Binding ElipseSelectedCommand}" PassEventArgsToCommand="True" />
        </local:RoutedEventTrigger>
    </b:Interaction.Triggers>
    
    <Grid>
        <ItemsControl ItemsSource="{Binding Elipses}" />
    </Grid>
</Window>

根据custom event trigger,略有更新的版本:

public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
    {
        private RoutedEventHandler _eventHandler;

        public RoutedEvent RoutedEvent { get; set; }

        public RoutedEventTrigger()
        {

        }

        protected override void OnAttached()
        {
            var associatedElement = GetAssociatedElement();

            if (associatedElement != null && RoutedEvent != null)
            {
                _eventHandler = new RoutedEventHandler(OnRoutedEvent);

                associatedElement.AddHandler(RoutedEvent, _eventHandler);
            }
        }

        protected override void OnDetaching()
        {
            var associatedElement = GetAssociatedElement();

            if (associatedElement != null && RoutedEvent != null && _eventHandler != null)
            {
                associatedElement.RemoveHandler(RoutedEvent, _eventHandler);
            }

            base.OnDetaching();
        }

        private FrameworkElement GetAssociatedElement()
        {
            FrameworkElement associatedElement = null;

            if (AssociatedObject is Behavior behavior)
            {
                associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
            }
            else if (AssociatedObject is FrameworkElement frameworkElement)
            {
                associatedElement = frameworkElement;
            }

            if (associatedElement == null)
            {
                throw new ArgumentException("Routed Event Trigger can only be associated to framework elements");
            }

            return associatedElement;
        }

        private void OnRoutedEvent(object sender, RoutedEventArgs e) => base.OnEvent(e);

        protected override string GetEventName() => RoutedEvent?.Name ?? string.Empty;
    }

相关问题