Родительский контроль пользователя WPF - PullRequest
176 голосов
/ 19 ноября 2008

У меня есть пользовательский элемент управления, который я загружаю в MainWindow во время выполнения. Я не могу получить дескриптор содержащего окна из UserControl.

Я пробовал this.Parent, но это всегда ноль. Кто-нибудь знает, как получить дескриптор содержащего окна из пользовательского элемента управления в WPF?

Вот как загружается элемент управления:

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);
}

Ответы [ 14 ]

332 голосов
/ 20 ноября 2008

Попробуйте использовать следующее:

Window parentWindow = Window.GetWindow(userControlReference);

Метод GetWindow проведет вас по VisualTree и найдет окно, в котором находится ваш элемент управления.

Этот код следует запускать после загрузки элемента управления (а не в конструкторе Window), чтобы метод GetWindow не возвращал null. Например. подключить событие:

this.Loaded += new RoutedEventHandler(UserControl_Loaded); 
33 голосов
/ 12 февраля 2010

Я добавлю свой опыт. Хотя использование события Loaded может сделать эту работу, я думаю, что может быть более подходящим переопределить метод OnInitialized. Загружается происходит после первого отображения окна. OnInitialized дает вам возможность вносить любые изменения, например, добавлять элементы управления в окно перед его визуализацией.

13 голосов
/ 09 февраля 2009

Мне нужно было использовать метод Window.GetWindow (this) в обработчике событий Loaded. Другими словами, я использовал ответ Иана Оукса в сочетании с ответом Алекса, чтобы получить родительский элемент управления пользователя.

public MainView()
{
    InitializeComponent();

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

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

    ...
}
13 голосов
/ 19 ноября 2008

Попробуйте использовать VisualTreeHelper.GetParent или используйте рекурсивную функцию ниже, чтобы найти родительское окно.

 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);
        }
    }
6 голосов
/ 06 августа 2014

Если вы нашли этот вопрос, а VisualTreeHelper не работает для вас или работает спорадически, вам может потребоваться включить LogicalTreeHelper в ваш алгоритм.

Вот что я использую:

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);
}
6 голосов
/ 05 марта 2012

Этот подход работал для меня, но он не так специфичен, как ваш вопрос:

App.Current.MainWindow
6 голосов
/ 18 мая 2011

Как насчет этого:

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));
        }
    } 
}
5 голосов
/ 24 января 2009

Я обнаружил, что родительский элемент UserControl всегда равен нулю в конструкторе, но в любых обработчиках событий родительский элемент установлен правильно. Я думаю, это как-то связано с тем, как загружается дерево управления. Таким образом, чтобы обойти это, вы можете просто получить родителя в элементе управления Loaded.

Для примера оформить заказ на этот вопрос Контент данных WPF User Control имеет значение Null

3 голосов
/ 11 марта 2016

Это не сработало для меня, так как оно зашло слишком далеко вверх и получило абсолютное корневое окно для всего приложения:

Window parentWindow = Window.GetWindow(userControlReference);

Однако, это сработало, чтобы получить немедленное окно:

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();
3 голосов
/ 18 июня 2013

у меня работает:

DependencyObject GetTopLevelControl(DependencyObject control)
{
    DependencyObject tmp = control;
    DependencyObject parent = null;
    while((tmp = VisualTreeHelper.GetParent(tmp)) != null)
    {
        parent = tmp;
    }
    return parent;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...