首页 文章

WPF用户控制父级

提问于
浏览
174

我有一个用户控件,我在运行时加载到 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 回答

  • 5

    尝试使用以下内容

    Window parentWindow = Window.GetWindow(userControlRefernce);
    

    GetWindow方法将为您运行VisualTree并找到托管您控件的窗口 .

    您应该在加载控件后运行此代码,以防止GetWindow方法返回null . 例如 . 连线活动:

    this.Loaded += new RoutedEventHandler(UserControl_Loaded);
    
  • 2

    我会加上我的经验 . 尽管使用Loaded事件可以完成这项工作,但我认为覆盖OnInitialized方法可能更合适 . 首次显示窗口后出现加载 . OnInitialized使您有机会进行任何更改,例如,在窗口呈现之前向窗口添加控件 .

  • 13

    尝试使用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);
            }
        }
    
  • 0

    我需要在Loaded事件处理程序中使用Window.GetWindow(this)方法 . 换句话说,我使用Ian Oakes的答案和Alex的答案来获得用户控件的父级 .

    public MainView()
    {
        InitializeComponent();
    
        this.Loaded += new RoutedEventHandler(MainView_Loaded);
    }
    
    void MainView_Loaded(object sender, RoutedEventArgs e)
    {
        Window parentWindow = Window.GetWindow(this);
    
        ...
    }
    
  • 3

    这种方法对我有用,但它并不像你的问题那样具体:

    App.Current.MainWindow
    
  • 3

    这个怎么样:

    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

    如果您发现此问题并且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);
    }
    
  • 33

    我发现UserControl的父级在构造函数中始终为null,但在任何事件处理程序中父级都是正确设置的 . 我想它必须与控件树的加载方式有关 . 因此,为了解决这个问题,您可以在控件Loaded事件中获取父级 .

    例如,结帐这个问题WPF User Control's DataContext is Null

  • 6

    其他方式:

    var main = App.Current.MainWindow as MainWindow;
    
  • 1

    它对我有用:

    DependencyObject GetTopLevelControl(DependencyObject control)
    {
        DependencyObject tmp = control;
        DependencyObject parent = null;
        while((tmp = VisualTreeHelper.GetParent(tmp)) != null)
        {
            parent = tmp;
        }
        return parent;
    }
    
  • 327

    这对我来说不起作用,因为它在树上走得太远,并且获得了整个应用程序的绝对根窗口:

    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();
    
  • 6
    DependencyObject parent = ExVisualTreeHelper.FindVisualParent<UserControl>(this);
    
  • 1
    DependencyObject GetTopParent(DependencyObject current)
    {
        while (VisualTreeHelper.GetParent(current) != null)
        {
            current = VisualTreeHelper.GetParent(current);
        }
        return current;
    }
    
    DependencyObject parent = GetTopParent(thisUserControl);
    
  • 13

    以上的镀金版(我需要一个通用函数,可以在 MarkupExtension 的上下文中推断 Window : -

    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() 将在以下基础上正确推断窗口:

    • Window 通过走可视树(如果在 UserControl 的上下文中使用)

    • 使用它的窗口(如果它在 Window 标记的上下文中使用)

相关问题