Propagate event from custom control to form

旧城冷巷雨未停 提交于 2019-12-06 07:51:05

问题


I have a custom control like:

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

and there is event rised on reloadButton click at generic.xaml

<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

But I have no idea how to raise this external event from internal button. Spend last few hours googling and ended up with nothing. above EventSetter is not working.


回答1:


This part was ok,

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

I had to create dependency property, so I can change some value on click event

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

and I can handle it in additional method triggered on change

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

then it just changing value on click was needed

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


Your event looks great, but the fact that EventSetter can not be set in the trigger. Quote from link:

Because using EventSetter to wire up event handler is a compile-time feature which is plumbed through IStyleConnector interface, there is another interface called IComponentConnector which is used by the XAML compiler to wire up event handler for standalone XAML elements.

You can do this. Identify EventSetter outside trigger, such as in the early 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)));
    }
}      

Or alternatively, use the DependencyProperty (can also be attached). Example:

Property definition:

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

Calling in XAML.

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

Using with DataTrigger (in Style/DataTemplate/etc):

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

Using with Trigger (in Style):

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

Using behind code:

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


来源:https://stackoverflow.com/questions/17975556/propagate-event-from-custom-control-to-form

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!