4 votes

Fonction équivalente UWP à FindAncestor en uwp

J'ai une liste de commandes et lorsque le statut de la commande est Annulée, je veux faire clignoter le texte. Jusqu'à présent, mon code fonctionne. Cependant, parfois il lance une exception :

Informations WinRT : Impossible de résoudre le nom de la cible lblOrderStatus

Pour une raison quelconque, lblOrderStatus ne peut pas être trouvé. Donc, je veux utiliser "FindAncestor", mais FindAncestor n'existe pas dans UWP. Y a-t-il une fonction équivalente à FindAncestor dans uwp ?

Voici mon code :

    ...
    ...
    ...

                ...
                ...
                ...

5voto

BCA Points 369

En considérant toutes les solutions que j'ai vues, je pense que l'utilisation de la liaison ElementName est la solution la plus simple au problème de UWP de ne pas avoir une option de liaison RelativeSource AncestorType.

En supposant que vous ayez une Page avec son DataContext défini sur un viewmodel avec une commande MyCommand, et que vous voulez que chaque élément de votre liste l'exécute lorsque son bouton est cliqué :

    ...

Mon problème initial avec cette solution est que vous ne pouvez pas extraire le DataTemplate en tant que ressource pour l'utiliser sur plusieurs écrans (ou même des boîtes de dialogue) ; thisPage pourrait ne pas exister dans chacun de ces endroits, ou il pourrait ne pas être approprié de nommer l'élément racine "thisPage".

Mais si vous utilisez une convention où vous incluez un élément d'interface utilisateur jeton dans chaque écran qui utilise ce DataTemplate, et que vous le référez par un nom cohérent, cela fonctionnera. Par défaut, le DataContext de cet élément sera votre ViewModel (en supposant que votre élément racine le soit aussi).

... puis dans votre fichier XAML de ressources autonome, vous pouvez écrire votre DataTemplate de cette manière :

Ensuite, sur chaque page/écran/dialogue que vous utilisez cette ressource de modèle, il vous suffit d'y déposer une copie de ce Rectangle (ou autre) et tout se liera correctement à l'exécution

Il s'agit clairement d'une solution de contournement, mais après y avoir réfléchi davantage, cela ne semble pas être plus une solution de contournement que d'utiliser AncestorType de WPF en premier lieu (en veillant à ce que votre type d'ancêtre soit toujours cohérent dans tous les endroits où vous utilisez votre DataTemplate).

0voto

Ramie Points 1319

En XAML Vous pouvez essayer d'utiliser RelativeSource, il fournit un moyen de spécifier la source d'une liaison en termes de relation relative dans le graphe d'objets en temps d'exécution. Par exemple en utilisant TemplatedParent:

Height="{Binding RelativeSource={RelativeSource TemplatedParent}, 
          Path=Parent.ActualHeight}

ou

En code vous pouvez essayer d'utiliser la méthode VisualTreeHelper.GetParent. https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.visualtreehelper.getparent

quelque chose comme ce qui suit, voici un exemple de fonction utilitaire

internal static void FindChildren(List results, DependencyObject startNode)
  where T : DependencyObject
{
    int count = VisualTreeHelper.GetChildrenCount(startNode);
    for (int i = 0; i < count; i++)
    {
        DependencyObject current = VisualTreeHelper.GetChild(startNode, i);
        if ((current.GetType()).Equals(typeof(T)) || (current.GetType().GetTypeInfo().IsSubclassOf(typeof(T))))
        {
            T asType = (T)current;
            results.Add(asType);
        }
        FindChildren(results, current);
    }
}

L'exemple suivant montre du code qui vérifie le parent d'un élément

((StackPanel)LinePane.Parent).ActualWidth;

Aussi, voici un bon article de blog montrant cette classe en action. http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html

0voto

Dr. ABT Points 8119

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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X