Je convertis une application de WPF en UWP et j'ai trouvé ce fil de discussion. Il semble qu'il n'y ait pas de bonnes solutions sur le web, alors voici ma tentative de 'résoudre' ce problème via une solution de contournement.
NOTE : Ce qui suit est NON TESTÉ en UWP (mais fonctionne en WPF) car je suis en train de faire un grand portage non compilant, mais théoriquement ça devrait fonctionner...
1 Créer une propriété attachée RelativeSourceBinding
Cette classe a deux propriétés : AncestorType et Ancestor. Lorsque AncestorType change, nous nous abonnons à FrameworkElement.Loaded (pour gérer les changements de parent) et trouvons le parent visuel du type et l'assignons à la propriété attachée Ancestor.
public class RelativeSourceBinding
{
public static readonly DependencyProperty AncestorTypeProperty = DependencyProperty.RegisterAttached("AncestorType", typeof(Type), typeof(RelativeSourceBinding), new PropertyMetadata(default(Type), OnAncestorTypeChanged));
public static void SetAncestorType(DependencyObject element, Type value)
{
element.SetValue(AncestorTypeProperty, value);
}
public static Type GetAncestorType(DependencyObject element)
{
return (Type)element.GetValue(AncestorTypeProperty);
}
private static void OnAncestorTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((FrameworkElement)d).Loaded -= OnFrameworkElementLoaded;
if (e.NewValue != null)
{
((FrameworkElement)d).Loaded += OnFrameworkElementLoaded;
OnFrameworkElementLoaded((FrameworkElement) d, null);
}
}
private static void OnFrameworkElementLoaded(object sender, RoutedEventArgs e)
{
var ancestorType = GetAncestorType((FrameworkElement) sender);
if (ancestorType != null)
{
var findAncestor = ((FrameworkElement) sender).FindVisualParent(ancestorType);
RelativeSourceBinding.SetAncestor(((FrameworkElement)sender), findAncestor);
}
else
{
RelativeSourceBinding.SetAncestor(((FrameworkElement)sender), null);
}
}
public static readonly DependencyProperty AncestorProperty = DependencyProperty.RegisterAttached("Ancestor", typeof(UIElement), typeof(RelativeSourceBinding), new PropertyMetadata(default(FrameworkElement)));
public static void SetAncestor(DependencyObject element, UIElement value)
{
element.SetValue(AncestorProperty, value);
}
public static UIElement GetAncestor(DependencyObject element)
{
return (UIElement)element.GetValue(AncestorProperty);
}
}
Où FindVisualParent est une méthode d'extension définie comme
public static UIElement FindVisualParent(this UIElement element, Type type)
{
UIElement parent = element;
while (parent != null)
{
if (type.IsAssignableFrom(parent.GetType()))
{
return parent;
}
parent = VisualTreeHelper.GetParent(parent) as UIElement;
}
return null;
}
2 Appliquer la propriété RelativeSourceBinding en XAML
du xaml AVANT ressemblerait à ceci en WPF
<Style.Setters>
<Setter Property="SomeProperty" Value="{Binding Foo, RelativeSource={RelativeSource AncestorType=local:AnotherClass}}" />
</Style.Setters>
et du xaml APRÈS
<Style.Setters>
<Setter Property="apc:RelativeSourceBinding.AncestorType" Value="local:AnotherClass"/>
<Setter Property="Foreground" Value="{Binding Path=(apc:RelativeSourceBinding.Ancestor).Foo, RelativeSource={RelativeSource Self}}" />
</Style.Setters>
C'est un peu désordonné mais dans le cas où vous n'avez qu'un seul type FindAncestor RelativeSource à trouver, ça devrait fonctionner.