Is there a way to attach a handler for the IsVisibleChanged event for a DataGridRow in a DataGridRow style definition? That is, is there a way to do something like the following:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<EventSetter Event="IsVisibleChanged" Handler="OnIsVisibleChanged"/>
</Style>
</DataGrid.RowStyle>
The above won't work because EventSetter can only be applied to RoutedEvents and not regular CLR events, like IsVisibleChanged.
CodePudding user response:
We'll have to make an attached property and an event.
using System;
using System.Windows;
namespace CommonCore.AttachedEvents
{
public static class UIElementHelper
{
public static readonly RoutedEvent IsVisibleChangedEvent = EventManager.RegisterRoutedEvent(
"IsVisibleChanged", RoutingStrategy.Bubble, typeof(IsVisibleChangedEventHandler), typeof(UIElementHelper));
public static void AddIsVisibleChangedHandler(DependencyObject dependencyObject, IsVisibleChangedEventHandler handler)
{
if (dependencyObject is not UIElement uiElement)
return;
uiElement.AddHandler(IsVisibleChangedEvent, handler);
}
private static void RaiseIsVisibleChangedEvent(object sender, DependencyPropertyChangedEventArgs e)
{
((UIElement)sender).RaiseEvent(new IsVisibleChangedEventHandlerArgs(IsVisibleChangedEvent, (bool)e.NewValue, (bool)e.OldValue));
}
public static void RemoveIsVisibleChangedHandler(DependencyObject dependencyObject, IsVisibleChangedEventHandler handler)
{
if (dependencyObject is not UIElement uiElement)
return;
uiElement.RemoveHandler(IsVisibleChangedEvent, handler);
}
public static bool GetRaiseIsVisibleChanged(UIElement uiElement)
{
return (bool)uiElement.GetValue(RaiseIsVisibleChangedProperty);
}
public static void SetRaiseIsVisibleChanged(UIElement uiElement, bool value)
{
uiElement.SetValue(RaiseIsVisibleChangedProperty, value);
}
// Using a DependencyProperty as the backing store for RaiseIsVisibleChanged. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RaiseIsVisibleChangedProperty =
DependencyProperty.RegisterAttached(
"RaiseIsVisibleChanged",
typeof(bool),
typeof(UIElementHelper),
new PropertyMetadata(false, OnRaiseIsVisibleChanged));
private static void OnRaiseIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not UIElement uiElement)
{
throw new InvalidOperationException("Implemented only for UIElement.");
}
if ((bool)e.NewValue)
{
uiElement.IsVisibleChanged = RaiseIsVisibleChangedEvent;
}
else
{
uiElement.IsVisibleChanged -= RaiseIsVisibleChangedEvent;
}
}
}
public class IsVisibleChangedEventHandlerArgs : RoutedEventArgs
{
public bool NewValue { get; }
public bool OldValue { get; }
public IsVisibleChangedEventHandlerArgs(RoutedEvent routedEvent, bool newValue, bool oldValue)
: base(routedEvent)
{
NewValue = newValue;
OldValue = oldValue;
}
}
public delegate void IsVisibleChangedEventHandler(object sender, IsVisibleChangedEventHandlerArgs args);
}
Their use:
<StackPanel>
<CheckBox x:Name="checkBox" Content="Видимость" IsChecked="False"/>
<Border Background="AliceBlue" Padding="10" Margin="10">
<Grid Height="20" Background="Aqua"
Visibility="{Binding IsChecked, ElementName=checkBox, Converter={commcnvs:BooleanToVisibility}}">
<FrameworkElement.Style>
<Style TargetType="Grid">
<Setter Property="aev:UIElementHelper.RaiseIsVisibleChanged" Value="True"/>
<EventSetter Event="aev:UIElementHelper.IsVisibleChanged" Handler="OnIsVisibleChanged"/>
</Style>
</FrameworkElement.Style>
</Grid>
</Border>
</StackPanel>
private void OnIsVisibleChanged(object sender, IsVisibleChangedEventHandlerArgs args)
{
MessageBox.Show($"OldValu = {args.OldValue}; NewValue = {args.NewValue};");
}