WPF用户控制父级

don*_*tz2 180 .net c# wpf

我有一个用户控件,我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);
}
Run Code Online (Sandbox Code Playgroud)

Ian*_*kes 341

尝试使用以下内容

Window parentWindow = Window.GetWindow(userControlReference);
Run Code Online (Sandbox Code Playgroud)

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

您应该在加载控件后运行此代码,以防止GetWindow方法返回null.EG发布一个事件:

this.Loaded += new RoutedEventHandler(UserControl_Loaded); 
Run Code Online (Sandbox Code Playgroud)

  • 我发现它返回null的原因.我将此代码放入我的用户控件的构造函数中.您应该在加载控件后运行此代码.EG连接一个事件:this.Loaded + = new RoutedEventHandler(UserControl_Loaded); (105认同)
  • 仍然返回null.这就像控件没有父级一样. (6认同)
  • 我使用上面的代码并获取parentWindow也为我返回null. (2认同)
  • 在查看 Paul 的响应后,使用 OnInitialized 方法而不是 Loaded 可能更有意义。 (2认同)

小智 33

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

  • +1表示正确.了解使用哪种技术有时会很微妙,特别是当你有混合事件和覆盖(加载事件,OnLoaded覆盖,初始化事件,OnInitialized覆盖,etcetcetc)时.在这种情况下,OnInitialized是有意义的,因为您要查找父级,并且必须初始化控件以使父级"存在".加载意味着不同的东西. (8认同)
  • `Window.GetWindow`仍然在`OnInitialized`中返回`null`.似乎只在`Loaded`事件中工作. (3认同)

Job*_*Joy 14

尝试使用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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 我发现它返回null的原因.我将此代码放入我的用户控件的构造函数中.您应该在加载控件后运行此代码.EG连接一个事件:this.Loaded + = new RoutedEventHandler(UserControl_Loaded) (2认同)

Ala*_* Le 13

我需要在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);

    ...
}
Run Code Online (Sandbox Code Playgroud)


小智 6

这个怎么样:

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));
        }
    } 
}
Run Code Online (Sandbox Code Playgroud)


Ant*_*ain 6

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

App.Current.MainWindow
Run Code Online (Sandbox Code Playgroud)


小智 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);
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*lex 5

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

对于示例结帐,此问题WPF用户控件的DataContext为空


Pnc*_*nct 5

其它的办法:

var main = App.Current.MainWindow as MainWindow;
Run Code Online (Sandbox Code Playgroud)