WPF User Control Parent
j'ai un contrôle d'utilisateur que je charge dans un MainWindow
à l'exécution. Je ne peux pas obtenir une poignée sur la fenêtre contenant du UserControl
.
j'ai essayé this.Parent
, mais c'est toujours nul. Est-ce que quelqu'un sait comment obtenir une poignée vers la fenêtre contenant à partir d'un contrôle d'utilisateur dans WPF?
Voici comment la commande est chargée:
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 réponses
essayez d'utiliser ce qui suit
Window parentWindow = Window.GetWindow(userControlRefernce);
la méthode GetWindow parcourra VisualTree pour vous et localisera la fenêtre qui héberge votre contrôle.
vous devez exécuter ce code après que la commande a été chargée pour empêcher la méthode GetWindow de retourner null. E. G. fil d'un événement:
this.Loaded += new RoutedEventHandler(UserControl_Loaded);
j'ajouterai mon expérience. Bien que L'utilisation de L'événement chargé puisse faire le travail, je pense qu'il pourrait être plus approprié de passer outre la méthode Oninitialisée. Chargé se produit après que la fenêtre est affichée pour la première fois. OnInitialized vous donne la chance d'effectuer des changements, par exemple, ajouter des contrôles à la fenêtre avant qu'elle ne soit rendue.
essayez D'utiliser VisualTreeHelper.GetParent ou utilisez la fonction recursive de bellow pour trouver la fenêtre parent.
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);
}
}
j'avais besoin d'utiliser la Fenêtre.Méthode GetWindow(this) dans le gestionnaire D'événements chargé. En d'autres termes, J'ai utilisé la réponse de Ian Oakes en combinaison avec la réponse D'Alex pour obtenir le parent du contrôle de l'utilisateur.
public MainView()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainView_Loaded);
}
void MainView_Loaded(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
...
}
cette approche a fonctionné pour moi, mais elle n'est pas aussi précise que votre question:
App.Current.MainWindow
Que pensez-vous de ceci:
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));
}
}
}
j'ai trouvé que le parent D'un UserControl est toujours null dans le constructeur, mais en tout cas les handlers le parent est positionné correctement. Je suppose que ça a quelque chose à voir avec la façon dont l'arbre de contrôle est chargé. Donc, pour contourner cela, vous pouvez simplement obtenir le parent dans l'événement controls Loaded.
pour un exemple de commande cette question le texte de données de WPF User Control est Null
si vous trouvez cette question et que VisualTreeHelper ne fonctionne pas pour vous ou ne fonctionne pas sporadiquement, vous pouvez avoir besoin d'inclure LogicalTreeHelper dans votre algorithme.
Voici ce que j'utilise:
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);
}
ça marche pour moi:
DependencyObject GetTopLevelControl(DependencyObject control)
{
DependencyObject tmp = control;
DependencyObject parent = null;
while((tmp = VisualTreeHelper.GetParent(tmp)) != null)
{
parent = tmp;
}
return parent;
}
cela n'a pas fonctionné pour moi, car il est allé trop loin dans l'arbre, et a obtenu la fenêtre racine absolue pour l'ensemble de l'application:
Window parentWindow = Window.GetWindow(userControlReference);
cependant, cela a fonctionné pour obtenir la fenêtre immédiate:
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<UserControl>(this);
DependencyObject GetTopParent(DependencyObject current)
{
while (VisualTreeHelper.GetParent(current) != null)
{
current = VisualTreeHelper.GetParent(current);
}
return current;
}
DependencyObject parent = GetTopParent(thisUserControl);
en Or plaqué édition de la ci-dessus (j'ai besoin d'une fonction générique qui peut déduire une Window
dans le contexte d'une 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()
déduira correctement une fenêtre sur la base suivante:
- à la racine
Window
par la marche de l'arborescence visuelle (si elle est utilisée dans le contexte d'uneUserControl
) - la fenêtre dans laquelle il est utilisé (s'il est utilisé dans le contexte d'une
Window
's de la majoration),