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

时间:2009-09-14 17:39:24

标签: c# wpf events datatemplate eventtrigger

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

在我的ListBox中,我想基本上将每个BlinkingLight对象显示为一个自定义控件,它看起来像带有LED灯的盒子,其动画使得LED看起来只是闪烁一秒,然后恢复正常。 / p>

我的BlinkingLight类有第三方“LED”对象,它会引发一个名为“Flash”的事件。

我正在寻找想法或解决方案来实现这一目标!

我尝试失败:

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

我为ListBox创建了一个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放入datatemplate,而不是让它更容易控制。

现在我希望在我的BlinkingLightControl(或DataTemplate)中有一个EventTrigger,其中RoutedEvent是LED.Flash事件。不幸的是,我似乎无法弄清楚这一部分。我试图在我的BlinkingLight类中创建一个RoutedEvent,只要我处理LED.Flash事件就把它抬起来。但是,我的课程不是UIElement或ContentElement,而是根据MSDN:MSND Link

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

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

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

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

由于我的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);
    }
}

答案 2 :(得分:1)

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

类似的东西:

  <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>