c# - tutorial - WPF User Control Parent
wpf vs winforms (14)
Añadiré mi experiencia. Aunque el uso del evento Loaded puede hacer el trabajo, creo que puede ser más adecuado anular el método OnInitialized. Cargado ocurre después de que la ventana se muestra por primera vez. OnInitialized le da la oportunidad de realizar cualquier cambio, por ejemplo, agregar controles a la ventana antes de que se represente.
Tengo un control de usuario que cargo en MainWindow
en tiempo de ejecución. No puedo obtener un control sobre la ventana que contiene el UserControl
.
Lo he intentado. this.Parent
, pero siempre es nulo. ¿Alguien sabe cómo manejar la ventana contenedora desde un control de usuario en WPF?
Aquí se muestra cómo se carga el control:
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);
}
De otra manera:
var main = App.Current.MainWindow as MainWindow;
Descubrí que el padre de un UserControl siempre es nulo en el constructor, pero en cualquier caso los controladores el padre está configurado correctamente. Supongo que debe tener algo que ver con la forma en que se carga el árbol de control. Para evitar esto, puede obtener al padre en el evento Controlado cargado.
Para ver un ejemplo, consulte esta pregunta . El DataContext del control de usuario de WPF es nulo.
Edición dorada de lo anterior (Necesito una función genérica que pueda inferir una Window
dentro del contexto de una MarkupExtension
de MarkupExtension
: -
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()
correctamente una ventana de la siguiente manera:
- la
Window
raíz al recorrer el árbol visual (si se usa en el contexto de unUserControl
) - la ventana dentro de la cual se usa (si se usa en el contexto del marcado de una
Window
)
Este enfoque funcionó para mí, pero no es tan específico como tu pregunta:
App.Current.MainWindow
Esto no funcionó para mí, ya que fue demasiado arriba en el árbol, y obtuve la ventana raíz absoluta para toda la aplicación:
Window parentWindow = Window.GetWindow(userControlReference);
Sin embargo, esto funcionó para obtener la ventana inmediata:
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();
Intente usar lo siguiente
Window parentWindow = Window.GetWindow(userControlRefernce);
El método GetWindow recorrerá VisualTree por usted y ubicará la ventana que aloja su control.
Me está funcionando:
DependencyObject GetTopLevelControl(DependencyObject control)
{
DependencyObject tmp = control;
DependencyObject parent = null;
while((tmp = VisualTreeHelper.GetParent(tmp)) != null)
{
parent = tmp;
}
return parent;
}
Necesitaba usar el método Window.GetWindow (this) dentro del controlador de eventos Loaded. En otras palabras, utilicé la respuesta de Ian Oakes en combinación con la respuesta de Alex para obtener el control del usuario.
public MainView()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainView_Loaded);
}
void MainView_Loaded(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
...
}
Pruebe usar VisualTreeHelper.GetParent o use la siguiente función recursiva para encontrar la ventana principal.
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);
}
}
Qué tal esto:
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));
}
}
}
Si encuentra esta pregunta y el VisualTreeHelper no funciona para usted o no trabaja de manera esporádica, es posible que deba incluir LogicalTreeHelper en su algoritmo.
Esto es lo que estoy usando:
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);
}
DependencyObject GetTopParent(DependencyObject current)
{
while (VisualTreeHelper.GetParent(current) != null)
{
current = VisualTreeHelper.GetParent(current);
}
return current;
}
DependencyObject parent = GetTopParent(thisUserControl);
DependencyObject parent = ExVisualTreeHelper.FindVisualParent<UserControl>(this);