Распространение события из пользовательского элемента управления в форму

У меня есть пользовательский элемент управления, как:

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

и есть событие, повышенное на щелчке reloadButton в 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

Но я понятия не имею, как вызвать это внешнее событие из внутренней кнопки. Провели последние несколько часов, погуглив и ничего не закончив. выше EventSetter не работает.

2 ответа

Решение

Эта часть была в порядке,

    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>

Ваше мероприятие выглядит великолепно, но тот факт, что EventSetter не может быть установлен в триггере. Цитата из ссылки:

Поскольку использование EventSetter для подключения обработчика событий является функцией времени компиляции, которая устанавливается через интерфейс IStyleConnector, существует другой интерфейс, называемый IComponentConnector, который используется компилятором XAML для подключения обработчика событий для автономных элементов 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>

Использование с DataTriggerStyle/DataTemplate/etc):

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

Использование с TriggerStyle):

<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);
}
Другие вопросы по тегам