WPF User Control Parent

j'ai un contrôle d'utilisateur que je charge dans un MainWindow à l'exécution. Je ne peux pas obtenir une poignée sur la fenêtre contenant du UserControl .

j'ai essayé this.Parent , mais c'est toujours nul. Est-ce que quelqu'un sait comment obtenir une poignée vers la fenêtre contenant à partir d'un contrôle d'utilisateur dans WPF?

Voici comment la commande est chargée:

private void XMLLogViewer_MenuItem_Click(object sender, RoutedEventArgs e)
{
    MenuItem application = sender as MenuItem;
    string parameter = application.CommandParameter as string;
    string controlName = parameter;
    if (uxPanel.Children.Count == 0)
    {
        System.Runtime.Remoting.ObjectHandle instance = Activator.CreateInstance(Assembly.GetExecutingAssembly().FullName, controlName);
        UserControl control = instance.Unwrap() as UserControl;
        this.LoadControl(control);
    }
}

private void LoadControl(UserControl control)
{
    if (uxPanel.Children.Count > 0)
    {
        foreach (UIElement ctrl in uxPanel.Children)
        {
            if (ctrl.GetType() != control.GetType())
            {
                this.SetControl(control);
            }
        }
    }
    else
    {
        this.SetControl(control);
    }
}

private void SetControl(UserControl control)
{
    control.Width = uxPanel.Width;
    control.Height = uxPanel.Height;
    uxPanel.Children.Add(control);
}
174
demandé sur lokusking 2008-11-19 21:13:47

14 réponses

essayez d'utiliser ce qui suit

Window parentWindow = Window.GetWindow(userControlRefernce);

la méthode GetWindow parcourra VisualTree pour vous et localisera la fenêtre qui héberge votre contrôle.

vous devez exécuter ce code après que la commande a été chargée pour empêcher la méthode GetWindow de retourner null. E. G. fil d'un événement:

this.Loaded += new RoutedEventHandler(UserControl_Loaded); 
324
répondu Ian Oakes 2018-05-25 15:01:31

j'ajouterai mon expérience. Bien que L'utilisation de L'événement chargé puisse faire le travail, je pense qu'il pourrait être plus approprié de passer outre la méthode Oninitialisée. Chargé se produit après que la fenêtre est affichée pour la première fois. OnInitialized vous donne la chance d'effectuer des changements, par exemple, ajouter des contrôles à la fenêtre avant qu'elle ne soit rendue.

33
répondu paul 2010-02-12 14:49:37

essayez D'utiliser VisualTreeHelper.GetParent ou utilisez la fonction recursive de bellow pour trouver la fenêtre parent.

 public static Window FindParentWindow(DependencyObject child)
    {
        DependencyObject parent= VisualTreeHelper.GetParent(child);

        //CHeck if this is the end of the tree
        if (parent == null) return null;

        Window parentWindow = parent as Window;
        if (parentWindow != null)
        {
            return parentWindow;
        }
        else
        {
            //use recursion until it reaches a Window
            return FindParentWindow(parent);
        }
    }
13
répondu Jobi Joy 2008-11-19 18:56:37

j'avais besoin d'utiliser la Fenêtre.Méthode GetWindow(this) dans le gestionnaire D'événements chargé. En d'autres termes, J'ai utilisé la réponse de Ian Oakes en combinaison avec la réponse D'Alex pour obtenir le parent du contrôle de l'utilisateur.

public MainView()
{
    InitializeComponent();

    this.Loaded += new RoutedEventHandler(MainView_Loaded);
}

void MainView_Loaded(object sender, RoutedEventArgs e)
{
    Window parentWindow = Window.GetWindow(this);

    ...
}
13
répondu Alan Le 2009-02-09 05:17:20

cette approche a fonctionné pour moi, mais elle n'est pas aussi précise que votre question:

App.Current.MainWindow
6
répondu Anthony Main 2012-03-05 11:38:33

Que pensez-vous de ceci:

DependencyObject parent = ExVisualTreeHelper.FindVisualParent<UserControl>(this);

public static class ExVisualTreeHelper
{
    /// <summary>
    /// Finds the visual parent.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="sender">The sender.</param>
    /// <returns></returns>
    public static T FindVisualParent<T>(DependencyObject sender) where T : DependencyObject
    {
        if (sender == null)
        {
            return (null);
        }
        else if (VisualTreeHelper.GetParent(sender) is T)
        {
            return (VisualTreeHelper.GetParent(sender) as T);
        }
        else
        {
            DependencyObject parent = VisualTreeHelper.GetParent(sender);
            return (FindVisualParent<T>(parent));
        }
    } 
}
6
répondu Eric Coulson 2013-01-31 15:22:39

j'ai trouvé que le parent D'un UserControl est toujours null dans le constructeur, mais en tout cas les handlers le parent est positionné correctement. Je suppose que ça a quelque chose à voir avec la façon dont l'arbre de contrôle est chargé. Donc, pour contourner cela, vous pouvez simplement obtenir le parent dans l'événement controls Loaded.

pour un exemple de commande cette question le texte de données de WPF User Control est Null

5
répondu Alex 2017-05-23 12:26:17

si vous trouvez cette question et que VisualTreeHelper ne fonctionne pas pour vous ou ne fonctionne pas sporadiquement, vous pouvez avoir besoin d'inclure LogicalTreeHelper dans votre algorithme.

Voici ce que j'utilise:

public static T TryFindParent<T>(DependencyObject current) where T : class
{
    DependencyObject parent = VisualTreeHelper.GetParent(current);
    if( parent == null )
        parent = LogicalTreeHelper.GetParent(current);
    if( parent == null )
        return null;

    if( parent is T )
        return parent as T;
    else
        return TryFindParent<T>(parent);
}
5
répondu GordoFabulous 2017-07-18 19:07:22

une autre voie:

var main = App.Current.MainWindow as MainWindow;
3
répondu Pnct 2013-06-06 14:17:24

ça marche pour moi:

DependencyObject GetTopLevelControl(DependencyObject control)
{
    DependencyObject tmp = control;
    DependencyObject parent = null;
    while((tmp = VisualTreeHelper.GetParent(tmp)) != null)
    {
        parent = tmp;
    }
    return parent;
}
3
répondu Nalan Madheswaran 2013-06-18 13:39:45

cela n'a pas fonctionné pour moi, car il est allé trop loin dans l'arbre, et a obtenu la fenêtre racine absolue pour l'ensemble de l'application:

Window parentWindow = Window.GetWindow(userControlReference);

cependant, cela a fonctionné pour obtenir la fenêtre immédiate:

DependencyObject parent = uiElement;
int avoidInfiniteLoop = 0;
while ((parent is Window)==false)
{
    parent = VisualTreeHelper.GetParent(parent);
    avoidInfiniteLoop++;
    if (avoidInfiniteLoop == 1000)
    {
        // Something is wrong - we could not find the parent window.
        break;
    }
}
Window window = parent as Window;
window.DragMove();
2
répondu Contango 2017-02-12 20:26:19
DependencyObject parent = ExVisualTreeHelper.FindVisualParent<UserControl>(this);
1
répondu Eric Coulson 2011-12-19 07:25:08
DependencyObject GetTopParent(DependencyObject current)
{
    while (VisualTreeHelper.GetParent(current) != null)
    {
        current = VisualTreeHelper.GetParent(current);
    }
    return current;
}

DependencyObject parent = GetTopParent(thisUserControl);
1
répondu Agus Syahputra 2012-08-23 14:17:38

en Or plaqué édition de la ci-dessus (j'ai besoin d'une fonction générique qui peut déduire une Window dans le contexte d'une MarkupExtension :-

public sealed class MyExtension : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider) =>
        new MyWrapper(ResolveRootObject(serviceProvider));
    object ResolveRootObject(IServiceProvider serviceProvider) => 
         GetService<IRootObjectProvider>(serviceProvider).RootObject;
}

class MyWrapper
{
    object _rootObject;

    Window OwnerWindow() => WindowFromRootObject(_rootObject);

    static Window WindowFromRootObject(object root) =>
        (root as Window) ?? VisualParent<Window>((DependencyObject)root);
    static T VisualParent<T>(DependencyObject node) where T : class
    {
        if (node == null)
            throw new InvalidOperationException("Could not locate a parent " + typeof(T).Name);
        var target = node as T;
        if (target != null)
            return target;
        return VisualParent<T>(VisualTreeHelper.GetParent(node));
    }
}

MyWrapper.Owner() déduira correctement une fenêtre sur la base suivante:

  • à la racine Window par la marche de l'arborescence visuelle (si elle est utilisée dans le contexte d'une UserControl )
  • la fenêtre dans laquelle il est utilisé (s'il est utilisé dans le contexte d'une Window 's de la majoration),
0
répondu Ruben Bartelink 2016-06-02 16:31:15