Pai de Controle de Usuário do WPF

Eu tenho um controle de usuário que eu carrego em uma MainWindow em tempo de execução. Eu não consigo obter uma alça na janela de UserControl do UserControl .

Eu tentei this.Parent , mas é sempre nulo. Alguém sabe como obter um identificador para a janela de contenção de um controle de usuário no WPF?

Aqui está como o controle é carregado:

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

Tente usar o seguinte

 Window parentWindow = Window.GetWindow(userControlRefernce); 

O método GetWindow percorrerá o VisualTree e localizará a janela que está hospedando o seu controle.

Você deve executar este código depois que o controle foi carregado para impedir que o método GetWindow retorne null. EG arame acima de um evento:

 this.Loaded += new RoutedEventHandler(UserControl_Loaded); 

Eu adicionarei minha experiência. Embora o uso do evento Loaded possa fazer o trabalho, acho que pode ser mais adequado replace o método OnInitialized. Carregado ocorre depois que a janela é exibida pela primeira vez. OnInitialized permite que você faça alterações, por exemplo, adicione controles à janela antes que ela seja renderizada.

Tente usar VisualTreeHelper.GetParent ou use a function recursiva abaixo para localizar a janela pai.

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

Eu precisava usar o método Window.GetWindow (this) dentro do manipulador de events Loaded. Em outras palavras, usei a resposta de Ian Oakes em combinação com a resposta de Alex para obter o pai de um controle de usuário.

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

Essa abordagem funcionou para mim, mas não é tão específica quanto a sua pergunta:

 App.Current.MainWindow 

Que tal agora:

 DependencyObject parent = ExVisualTreeHelper.FindVisualParent(this); public static class ExVisualTreeHelper { ///  /// Finds the visual parent. ///  ///  /// The sender. ///  public static T FindVisualParent(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(parent)); } } } 

Descobri que o pai de um UserControl é sempre nulo no construtor, mas em qualquer manipulador de evento o pai é definido corretamente. Eu acho que deve ter algo a ver com a maneira como a tree de controle é carregada. Então, para contornar isso, você pode simplesmente obter o pai no evento Loaded dos controles.

Para um exemplo de checkout esta questão DataContext do WPF User Control é Null

Se você está encontrando esta pergunta e o VisualTreeHelper não está funcionando para você ou trabalhando esporadicamente, você pode precisar include o LogicalTreeHelper em seu algoritmo.

Aqui está o que estou usando:

 public static T TryFindParent(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(parent); } 

Outra maneira:

 var main = App.Current.MainWindow as MainWindow; 

Está funcionando para mim:

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

Isso não funcionou para mim, pois foi muito longe na tree e ficou com a janela raiz absoluta para o aplicativo inteiro:

 Window parentWindow = Window.GetWindow(userControlReference); 

No entanto, isso funcionou para obter a janela imediata:

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

Edição banhada a ouro do acima (eu preciso de uma function genérica que pode inferir uma Window dentro do contexto de um MarkupExtension : –

 public sealed class MyExtension : MarkupExtension { public override object ProvideValue(IServiceProvider serviceProvider) => new MyWrapper(ResolveRootObject(serviceProvider)); object ResolveRootObject(IServiceProvider serviceProvider) => GetService(serviceProvider).RootObject; } class MyWrapper { object _rootObject; Window OwnerWindow() => WindowFromRootObject(_rootObject); static Window WindowFromRootObject(object root) => (root as Window) ?? VisualParent((DependencyObject)root); static T VisualParent(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(VisualTreeHelper.GetParent(node)); } } 

MyWrapper.Owner() corretamente uma janela na seguinte base:

  • a Window raiz percorrendo a tree visual (se usada no contexto de um UserControl )
  • a janela dentro da qual ele é usado (se for usado no contexto da marcação de uma Window )