从自定义控件向表单传播事件

3

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

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并没有起作用。

2个回答

3
这部分内容没问题,
    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。引用自链接中的说法如下:

因为使用EventSetter来连接事件处理程序是一种编译时特性,它通过IStyleConnector接口进行了实现,还有另一个接口称为IComponentConnector,它由XAML编译器用于为独立的XAML元素连接事件处理程序。

您可以将EventSetter放在触发器之外,例如早期的Style / Template中。
<Style TargetType="{x:Type local:BorderEx}">
    <EventSetter Event="Button.Click" Handler="ReloadClickEvent" />

...

</Style>

代码后台

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);
}

谢谢,说这是不可行的,并提供所有细节和想法让我找到了自己的解决方案。 - Jakub Pawlinski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接