Files
2022-11-01 15:26:08 +00:00

94 lines
4.1 KiB
C#

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
using TheXamlGuy.UI.WPF;
namespace TheXamlGuy.Framework.WPF
{
[MarkupExtensionReturnType(typeof(Control))]
public class RouteExtension : MarkupExtension
{
private static readonly DependencyProperty RouteProperty =
DependencyProperty.RegisterAttached("Route",
typeof(IRoute), typeof(RouteExtension));
private readonly string name;
private readonly Binding routeBinding;
private PropertyChangedRevoker? dataContextPropertyChangedRevoker;
public RouteExtension(object route, string name)
{
routeBinding = route.ToBinding();
this.name = name;
}
private bool TryGetDataContext(DependencyObject target, out object dataContext)
{
dataContext = target.GetValue(FrameworkElement.DataContextProperty) ?? target.GetValue(FrameworkContentElement.DataContextProperty);
return dataContext is not null;
}
public override object? ProvideValue(IServiceProvider serviceProvider)
{
if (dataContextPropertyChangedRevoker is not null)
{
dataContextPropertyChangedRevoker.Dispose();
dataContextPropertyChangedRevoker = null;
}
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget target)
{
if (target.TargetObject is FrameworkElement frameworkElement)
{
if (!TryGetDataContext(frameworkElement, out object dataContext))
{
dataContextPropertyChangedRevoker = new PropertyChangedRevoker(frameworkElement, FrameworkElement.DataContextProperty, OnDataContextPropertyChangedChanged);
void OnDataContextPropertyChangedChanged(object sender, DependencyPropertyChangedEventArgs _)
{
if (TryGetDataContext(frameworkElement, out dataContext))
{
frameworkElement.Loaded -= HandleLoaded;
BindingOperations.SetBinding(frameworkElement, RouteProperty, routeBinding);
if (frameworkElement?.GetValue(RouteProperty) is IRoute route)
{
route.AddRoute(name, frameworkElement);
BindingOperations.ClearBinding(frameworkElement, RouteProperty);
}
}
}
void HandleLoaded(object sender, RoutedEventArgs args)
{
frameworkElement.Loaded -= HandleLoaded;
if (TryGetDataContext(frameworkElement, out dataContext))
{
BindingOperations.SetBinding(frameworkElement, RouteProperty, routeBinding);
if (frameworkElement?.GetValue(RouteProperty) is IRoute route)
{
route.AddRoute(name, frameworkElement);
BindingOperations.ClearBinding(frameworkElement, RouteProperty);
}
}
}
frameworkElement.Loaded += HandleLoaded;
}
else
{
BindingOperations.SetBinding(frameworkElement, RouteProperty, routeBinding);
if (frameworkElement?.GetValue(RouteProperty) is IRoute route)
{
route.AddRoute(name, frameworkElement);
BindingOperations.ClearBinding(frameworkElement, RouteProperty);
}
}
}
}
return null;
}
}
}