如何将事件触发器添加到业务对象的数据模板?

发布于 2024-08-04 21:53:45 字数 1406 浏览 3 评论 0原文

我有一个名为 BlinkingLight 的自定义类。 我还有一个静态 ObservableCollection BlinkingLightCollection。 在 UI 中,我有一个绑定到 BlinkingLightCollection 的 ListBox。

在我的 ListBox 中,我希望将每个 BlinkingLight 对象基本上显示为自定义控件,该控件看起来像带有 LED 灯的盒子,该控件具有动画,使 LED 看起来就像只闪烁了一秒钟然后恢复正常。

我的 BlinkingLight 类具有第三方“LED”对象,该对象引发名为“Flash”的事件。

我正在寻找想法或解决方案来使其发挥作用!

我失败的尝试

我创建了一个自定义控件 (BlinkingLightControl),当 BlinkingLight 是我的自定义控件的 DataContext 时,它可以绑定到我的 BlinkingLight 类的数据。

我为列表框创建了一个 DataTemplate:

<Window.Resources>
  <DataTemplate x:Key="blinkingLightItemTemplate" >
    <local:BlinkingLightControl />
  </DataTemplate>
</Window.Resources>

<ListBox ItemsSource={Binding Source={x:Static local:Data.BlinkingLightCollection}}
         ItemTemplate="{StaticResource blinkingLightItemTemplate}" />

注意:我可以将自定义控件的 xaml 放入数据模板中,而不是使用完全不同的控件(如果这样可以让事情变得更容易)。

现在我想在我的 BlinkingLightControl(或 DataTemplate)中有一个 EventTrigger,其 RoutedEvent 是 LED.Flash 事件。不幸的是我似乎无法弄清楚这部分。我尝试在 BlinkingLight 类中创建一个 RoutedEvent,并在处理 LED.Flash 事件时引发它。但是,我的类不是 UIElement 或 ContentElement,并且根据 MSDN:MSND 链接

“路由事件所有者可以是任何类,但路由事件必须由 UIElement 或 ContentElement 派生类引发并处理才能发挥作用。有关自定义事件的详细信息,请参阅如何:创建自定义路由事件。 ”

任何帮助将不胜感激! 谢谢, 斯科特

I have a custom class named BlinkingLight.
I also have a static ObservableCollection BlinkingLightCollection.
In the UI, I have a ListBox that is bound to BlinkingLightCollection.

In my ListBox I want to essentially display each BlinkingLight object as a custom control that looks like box with an LED light that has an animation that makes the LED look like it just flashed on for a second then goes back to normal.

My BlinkingLight class has third party "LED" object that raises an event called 'Flash'.

I am looking for ideas or solutions to get this to work!

My failed attempt:

I created a custom control (BlinkingLightControl) that can bind to the data of my BlinkingLight class when a BlinkingLight is the DataContext of my custom control.

I created a DataTemplate for my ListBox:

<Window.Resources>
  <DataTemplate x:Key="blinkingLightItemTemplate" >
    <local:BlinkingLightControl />
  </DataTemplate>
</Window.Resources>

<ListBox ItemsSource={Binding Source={x:Static local:Data.BlinkingLightCollection}}
         ItemTemplate="{StaticResource blinkingLightItemTemplate}" />

Note: I can just put the xaml for my custom control into the datatemplate instead having a completely different control if that makes things easier.

Now I want to have an EventTrigger in my BlinkingLightControl (or DataTemplate) who's RoutedEvent is the LED.Flash event. Unfortunately I can't seem to figure this part out. I've tried to create a RoutedEvent in my BlinkingLight class and just raise it whenever I handle the LED.Flash event. However my class is not a UIElement or ContentElement, and per MSDN: MSND Link

"The routed event owner can be any class, but routed events must be raised by and handled by UIElement or ContentElement derived classes in order to be useful. For more information about custom events, see How to: Create a Custom Routed Event."

Any help would be greatly appreciated!!
Thanks,
Scott

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浮世清欢 2024-08-11 21:53:45

在这种情况下,最好的方法是使用 WPF Commanding 并创建一个“BlinkTheLights”RouteCommand - 您的 BlinkingLightControl 将处理 BlinkTheLights 命令,并通过启动使灯闪烁的 StoryBoard 进行响应。

In this case, the best way is to use WPF Commanding and create a "BlinkTheLights" RoutedCommand - your BlinkingLightControl will handle the BlinkTheLights command, and respond by starting a StoryBoard which does the light blink.

木有鱼丸 2024-08-11 21:53:45

我能够想出一个效果很好的解决方案:

由于我的 DataTemplate 仅包含一个自定义 UserControl(它绑定到 DataContext 以从业务对象获取其数据)...我将自定义 RoutedEvent 放置在 UserControl 中。然后,在 UserControl 的已加载事件中,我将 DataContext 强制转换为我的业务对象,以访问具有该事件的业务对象的属性,并将其连接到事件处理程序。 (在我的示例中,我将 DataContext 转换为 BlinkingLight 对象,然后我可以访问其 Led 属性的 Flash 事件并将其连接到自定义事件处理程序)。
注意:LED 对象必须是一个属性,而不仅仅是 BlinkingLight 对象中的一个字段才能工作。

然后,事件处理程序可以引发 UserControl 的自定义路由事件 (FlashGreenEvent)。下面是后端代码,现在补充了OP中的代码(我已经删除了任何其他不相关的代码)。

public partial class BlinkingLightControl : UserControl
{
    public static readonly RoutedEvent FlashGreenEvent = EventManager.RegisterRoutedEvent("FlashGreen", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(BlinkingLightControl));
    public event RoutedEventHandler FlashGreen
    {
        add { AddHandler(FlashGreenEvent, value); }
        remove { RemoveHandler(FlashGreenEvent, value); }
    }

    private void BlinkingLightControl_Loaded(object sender, RoutedEventArgs e)
    {
        BlinkingLight blinkingLight = (BlinkingLight)this.DataContext;

        blinkingLight.Led.Flash += LED_Flash;
    }

    protected delegate void LED_FlashCallback(ThirdParty.LED sender);
    public void LED_Flash(ThirdParty.LED sender)
    {
        if (this.Dispatcher.CheckAccess())
        {
            // Raise the Flash Green Event;
            RaiseEvent(new RoutedEventArgs(BlinkingLightControl.FlashGreenEvent));
        }
        else
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new LED_FlashCallback(LED_Flash), sender);
    }
}

I was able to come up with a solution that has worked quite well:

Since my DataTemplate simply contains a custom UserControl (which binds to the DataContext to get its data from the business object)... I placed my custom RoutedEvent in the UserControl. Then in my UserControl's loaded event, I cast the DataContext as my business object to get access to the business object's property that has the event and hook it up to an event handler. (in my example I cast the DataContext as a BlinkingLight object, then I can get access to its Led property's Flash event and hook it up to a custom event handler).
Note: The LED object must be a property, not just a field in the BlinkingLight object for it to work.

Then the event handler can raise the UserControl's custom Routed Event (FlashGreenEvent). Below is the back end code that now supplements the code in the OP (I've stripped out any other irrelevant code).

public partial class BlinkingLightControl : UserControl
{
    public static readonly RoutedEvent FlashGreenEvent = EventManager.RegisterRoutedEvent("FlashGreen", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(BlinkingLightControl));
    public event RoutedEventHandler FlashGreen
    {
        add { AddHandler(FlashGreenEvent, value); }
        remove { RemoveHandler(FlashGreenEvent, value); }
    }

    private void BlinkingLightControl_Loaded(object sender, RoutedEventArgs e)
    {
        BlinkingLight blinkingLight = (BlinkingLight)this.DataContext;

        blinkingLight.Led.Flash += LED_Flash;
    }

    protected delegate void LED_FlashCallback(ThirdParty.LED sender);
    public void LED_Flash(ThirdParty.LED sender)
    {
        if (this.Dispatcher.CheckAccess())
        {
            // Raise the Flash Green Event;
            RaiseEvent(new RoutedEventArgs(BlinkingLightControl.FlashGreenEvent));
        }
        else
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new LED_FlashCallback(LED_Flash), sender);
    }
}
挥剑断情 2024-08-11 21:53:45

如果您正在制作自定义控件,则始终可以在控件模板之外设置触发器。

像这样的东西:

  <Style TargetType="{x:Type local:MyControl}">

  <!-- fade in the control with an animation -->
  <Style.Triggers>
    <EventTrigger RoutedEvent="Control.Loaded">
      <BeginStoryboard>
        <Storyboard>
         <DoubleAnimation To="1" Duration="0:0:1" Storyboard.TargetProperty="Opacity"/>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Style.Triggers>

  <!-- Make sure the opacity starts at 0 -->
  <Setter Property="Opacity" Value="0"/>
  <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type local:MyControl}">
         </ControlTemplate>
      </Setter.Value>
  </Setter>
</Style>

If you're making a custom control you could always set the trigger outside of the control template.

something like:

  <Style TargetType="{x:Type local:MyControl}">

  <!-- fade in the control with an animation -->
  <Style.Triggers>
    <EventTrigger RoutedEvent="Control.Loaded">
      <BeginStoryboard>
        <Storyboard>
         <DoubleAnimation To="1" Duration="0:0:1" Storyboard.TargetProperty="Opacity"/>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Style.Triggers>

  <!-- Make sure the opacity starts at 0 -->
  <Setter Property="Opacity" Value="0"/>
  <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type local:MyControl}">
         </ControlTemplate>
      </Setter.Value>
  </Setter>
</Style>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文