【问题标题】:Propagate event from custom control to form将事件从自定义控件传播到表单
【发布时间】:2013-07-31 16:12:32
【问题描述】:

我有一个自定义控件,例如:

public sealed class BorderEx : Control
{
    public static readonly RoutedEvent ReloadClickEvent = EventManager.RegisterRoutedEvent("ReloadClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BorderEx));

    public event RoutedEventHandler ReloadClick
    {
        add { AddHandler(ReloadClickEvent, value); }
        remove { RemoveHandler(ReloadClickEvent, value); }
    }

    void RaiseReloadClickEvent()
    {
        var newEventArgs = new RoutedEventArgs(ReloadClickEvent);
        RaiseEvent(newEventArgs);
    }

    static BorderEx()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(BorderEx), new FrameworkPropertyMetadata(typeof(BorderEx)));
    }
}        

在 generic.xaml 上单击 reloadButton 时会引发事件

<ControlTemplate TargetType="{x:Type cbr:BorderEx}">

<ControlTemplate.Triggers>

    <Trigger SourceName="reloadButton" Property="IsPressed" Value="True">
        <Setter TargetName="reloadButton" Property="Background" Value="Green"/>
        <EventSetter Event="ReloadClick" Handler="RaiseReloadClickEvent"></EventSetter>
    </Trigger>
</ControlTemplate.Triggers>

</ControlTemplate

但我不知道如何从内部按钮引发这个外部事件。花最后几个小时谷歌搜索,结果一无所获。以上 EventSetter 不工作。

【问题讨论】:

    标签: c# wpf events custom-controls


    【解决方案1】:

    这部分没问题,

        public static readonly RoutedEvent ReloadClickEvent = EventManager.RegisterRoutedEvent("ReloadClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BorderEx));
    
        public event RoutedEventHandler ReloadClick
        {
            add { AddHandler(ReloadClickEvent, value); }
            remove { RemoveHandler(ReloadClickEvent, value); }
        }
    
        static BorderEx()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BorderEx), new FrameworkPropertyMetadata(typeof(BorderEx)));
        }
    

    我必须创建依赖属性,所以我可以更改点击事件的一些值

        public static readonly DependencyProperty ReloadProperty = DependencyProperty.Register("Reload", typeof (bool), typeof (BorderEx), new PropertyMetadata(default(bool), ReloadClicked));
        public bool Reload
        {
            get { return (bool) GetValue(ReloadProperty); }
            set { SetValue(ReloadProperty, value); }
        }
    

    我可以通过更改触发的其他方法来处理它

        private static void ReloadClicked(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            if (!((bool) e.NewValue)) return;
            var sender = (BorderEx) o;
            sender.RaiseEvent(new RoutedEventArgs(ReloadClickEvent));
        }
    

    那么它只需要在点击时改变值

    <ControlTemplate.Triggers>
        <Trigger SourceName="reloadButton" Property="IsPressed" Value="True">
            <Setter TargetName="reloadButton" Property="Background" Value="Green"/>
            <Setter Property="Reload" Value="True"/>
        </Trigger>
    </ControlTemplate.Triggers>
    

    【讨论】:

      【解决方案2】:

      您的事件看起来不错,但无法在触发器中设置 EventSetter。引用link:

      因为使用 EventSetter 连接事件处理程序是一个通过 IStyleConnector 接口检测的编译时功能,所以 XAML 编译器使用另一个名为 IComponentConnector 的接口来连接独立 XAML 元素的事件处理程序。

      你可以这样做。识别EventSetter外部触发,比如早期的Style/Template

      <Style TargetType="{x:Type local:BorderEx}">
          <EventSetter Event="Button.Click" Handler="ReloadClickEvent" />
      
      ...
      
      </Style>
      

      Code behind

      public partial class MainWindow : Window
      {
          public MainWindow()
          {
              InitializeComponent();
          }        
      
          private void ReloadClickEvent(object sender, RoutedEventArgs e)
          {
              RaiseEvent(new DemoEventArgs(BorderEx.ReloadClickEvent, sender));
          }
      }
      
      public class DemoEventArgs : RoutedEventArgs
      {
          public DemoEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source)
          {
              MessageBox.Show("Raise!");
          }
      }
      
      public sealed class BorderEx : Control
      {
          public static readonly RoutedEvent ReloadClickEvent = EventManager.RegisterRoutedEvent("ReloadClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BorderEx));
      
          public event RoutedEventHandler ReloadClick
          {
              add { AddHandler(ReloadClickEvent, value); }
              remove { RemoveHandler(ReloadClickEvent, value); }
          }
      
          private void RaiseReloadClickEvent()
          {
              var newEventArgs = new RoutedEventArgs(ReloadClickEvent);
              RaiseEvent(newEventArgs);
          }
      
          static BorderEx()
          {
              DefaultStyleKeyProperty.OverrideMetadata(typeof(BorderEx), new FrameworkPropertyMetadata(typeof(BorderEx)));
          }
      }      
      

      或者,使用DependencyProperty(也可以附加)。示例:

      属性定义:

      public static readonly DependencyProperty SampleProperty =
                                                DependencyProperty.RegisterAttached("Sample",
                                                typeof(bool),
                                                typeof(SampleClass),
                                                new UIPropertyMetadata(false, OnSample));
      
      private static void OnSample(DependencyObject sender, DependencyPropertyChangedEventArgs e)
      {
          if (e.NewValue is bool && ((bool)e.NewValue) == true)
          {
              // do something...
          }
      }
      

      在 XAML 中调用。

      EventTrigger:

      <EventTrigger SourceName="MyButton" RoutedEvent="Button.Click">
          <BeginStoryboard>
              <Storyboard>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MyBox" Storyboard.TargetProperty="(local:SampleClass.Sample)">
                      <DiscreteObjectKeyFrame KeyTime="0:0:0">
                          <DiscreteObjectKeyFrame.Value>
                              <sys:Boolean>True</sys:Boolean>
                          </DiscreteObjectKeyFrame.Value>
                      </DiscreteObjectKeyFrame>
                  </ObjectAnimationUsingKeyFrames>
              </Storyboard>
          </BeginStoryboard>
      </EventTrigger>
      

      DataTrigger 一起使用(在Style/DataTemplate/etc):

      <DataTrigger Binding="{Binding ElementName=MyBox, Path=Status), Mode=OneWay}" Value="True">
          <Setter Property="(local:SampleClass.Sample)" Value="True" />
      </DataTrigger>
      

      Trigger 一起使用(在Style 中):

      <Trigger Property="MyCheckBox.IsChecked" Value="True">
          <Setter Property="(local:SampleClass.Sample)" Value="True" />
      </Trigger>
      

      使用后面的代码:

      private void Clear_Click(object sender, RoutedEventArgs e)
      {
          SampleClass.SetSampleClass(MyBox, true);
      }
      

      【讨论】:

      • 谢谢,说这不可行,并提供上面的所有细节和想法让我找到自己的解决方案。
      猜你喜欢
      • 2012-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多