tags:

views:

16473

answers:

6

I have a user control that I load into a main window at runtime. I cannot get a handle on the containing window from the user control.

I have tried this.Parent, but it's always null. Does anyone know how to get a handle to the containing window from a user control in WPF?

Here is how the control is loaded:

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);
}
+2  A: 

Try using VisualTreeHelper.GetParent or use the bellow recursive function to find the parent window.

 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);
        }
    }
Jobi Joy
I tried passing using this code from within my user control. I passed this into this method but it returned null, indicating that it is the end of the tree (according to your comment). Do you know why this is? The user control has a parent which is the containing form. How do I get a handle to this form?
Peter Walke
I found out the reason it's returning null. I was putting this code into the constructor of my user control. You should run this code after the control has loaded. E.G. wire up an event: this.Loaded += new RoutedEventHandler(UserControl_Loaded)
Peter Walke
Another issue is in the debugger. VS will execute the code of Load event, but it won't find the Window parent.
modosansreves
+23  A: 

Try using the following

Window parentWindow = Window.GetWindow(userControlRefernce);

The GetWindow method will walk the VisualTree for you and locate the window that is hosting your control.

Ian Oakes
Still returns null. It's as if the control just has no parent.
donniefitz2
I used the code above and get the parentWindow also returns null for me.
Peter Walke
I found out the reason it's returning null. I was putting this code into the constructor of my user control. You should run this code after the control has loaded. E.G. wire up an event:this.Loaded += new RoutedEventHandler(UserControl_Loaded);
Peter Walke
Worked great in the load event. Thanks!
Jason Young
Sweet. was wondering why GetParent was returning null when i wanted a window but thinking about it, it only makes sense. cheers
Stimul8d
+3  A: 

I've found that the parent of a UserControl is always null in the constructor, but in any event handlers the parent is set correctly. I guess it must have something to do with the way the control tree is loaded. So to get around this you can just get the parent in the controls Loaded event.

For an example checkout this question http://stackoverflow.com/questions/296503/wpf-user-controls-datacontext-is-null

Alex
You kind of have to wait for it to be in the "tree" first. Pretty obnoxious at times.
sixlettervariables
+2  A: 

I needed to use the Window.GetWindow(this) method within Loaded event handler. In other words, I used both Ian Oakes' answer in combination with Alex's answer to get a user control's parent.

public MainView()
{
    InitializeComponent();

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

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

    ...
}
Alan Le
+1  A: 

To all who observe that no parent can be found in the c'tor: It makes sense since the control is not parented yet. IOW, it's not stored in a parent yet.

Serge - appTranslator
+4  A: 

I'll add my experience. Although using the Loaded event can do the job, I think it may be more suitable to override the OnInitialized method. Loaded occurs after the window is first displayed. OnInitialized gives you chance to make any changes, for example, add controls to the window before it is rendered.

paul
+1 for correct. Understanding which technique to use can be subtle at times, especially when you've got events and overrides thrown into the mix (Loaded event, OnLoaded override, Initialized event, OnInitialized override, etcetcetc). In this case, OnInitialized makes sense because you want to find the parent, and the control must be initialized for the parent to "exist". Loaded means something different.
Greg D