Reputation: 482
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.
Upvotes: 3
Views: 1567
Reputation: 482
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>
Upvotes: 3
Reputation: 22702
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);
}
Upvotes: 2