Ich habe ein Benutzersteuerelement, das ich zur Laufzeit in ein MainWindow
lade. Ich kann das übergeordnete Fenster nicht über das UserControl
verwalten.
Ich habe versucht this.Parent
, aber es ist immer null. Weiß jemand, wie man ein Handle auf das enthaltende Fenster von einem Benutzersteuerelement in WPF bekommt?
So wird das Steuerelement geladen:
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);
}
Versuchen Sie Folgendes:
Window parentWindow = Window.GetWindow(userControlReference);
Die GetWindow
-Methode durchsucht den VisualTree für Sie und sucht das Fenster, in dem sich Ihr Steuerelement befindet.
Sie sollten diesen Code ausführen, nachdem das Steuerelement geladen wurde (und nicht im Window-Konstruktor), um zu verhindern, dass die GetWindow
-Methode null
zurückgibt. Z.B. eine Veranstaltung verkabeln:
this.Loaded += new RoutedEventHandler(UserControl_Loaded);
Ich werde meine Erfahrung hinzufügen. Obwohl die Verwendung des Loaded-Ereignisses die Aufgabe erledigen kann, ist es meines Erachtens geeigneter, die OnInitialized-Methode zu überschreiben. Wird geladen, nachdem das Fenster zum ersten Mal angezeigt wurde. Mit OnInitialized können Sie Änderungen vornehmen, z. B. dem Fenster Steuerelemente hinzufügen, bevor es gerendert wird.
Ich musste die Window.GetWindow (this) -Methode im Loaded-Ereignishandler verwenden. Mit anderen Worten, ich habe die Antwort von Ian Oakes in Kombination mit der Antwort von Alex verwendet, um das übergeordnete Element eines Benutzersteuerelements zu ermitteln.
public MainView()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainView_Loaded);
}
void MainView_Loaded(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
...
}
Versuchen Sie es mit VisualTreeHelper.GetParent oder verwenden Sie die unten stehende rekursive Funktion, um das übergeordnete Fenster zu finden.
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);
}
}
Dieser Ansatz hat bei mir funktioniert, ist aber nicht so spezifisch wie Ihre Frage:
App.Current.MainWindow
Wie wäre es damit:
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));
}
}
}
Wenn Sie diese Frage finden und der VisualTreeHelper nicht oder nur sporadisch funktioniert, müssen Sie möglicherweise LogicalTreeHelper in Ihren Algorithmus einbeziehen.
Folgendes verwende ich:
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);
}
Ich habe festgestellt, dass das übergeordnete Element eines UserControl im Konstruktor immer null ist, aber in jedem Fall ist das übergeordnete Element korrekt festgelegt. Ich denke, es muss etwas damit zu tun haben, wie der Kontrollbaum geladen wird. Um dies zu umgehen, können Sie einfach das übergeordnete Element im Loaded-Ereignis des Steuerelements abrufen.
Als Beispiel zur Prüfung dieser Frage Der Datenkontext des WPF-Benutzersteuerelements ist Null
Es funktioniert für mich:
DependencyObject GetTopLevelControl(DependencyObject control)
{
DependencyObject tmp = control;
DependencyObject parent = null;
while((tmp = VisualTreeHelper.GetParent(tmp)) != null)
{
parent = tmp;
}
return parent;
}
Ein anderer Weg:
var main = App.Current.MainWindow as MainWindow;
Dies hat bei mir nicht funktioniert, da es zu weit nach oben ging und das absolute Root-Fenster für die gesamte Anwendung bekam:
Window parentWindow = Window.GetWindow(userControlReference);
Dies funktionierte jedoch, um das unmittelbare Fenster zu erhalten:
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);
Unterschiedliche Ansätze und unterschiedliche Strategien. In meinem Fall konnte ich das Fenster meines Dialogs weder mit VisualTreeHelper noch mit Erweiterungsmethoden von Telerik finden, um Eltern eines bestimmten Typs zu finden. Stattdessen habe ich meine Dialogansicht gefunden, die das benutzerdefinierte Einfügen von Inhalten mithilfe von Application.Current.Windows akzeptiert.
public Window GetCurrentWindowOfType<TWindowType>(){
return Application.Current.Windows.OfType<TWindowType>().FirstOrDefault() as Window;
}
Vergoldete Ausgabe der oben genannten (Ich benötige eine generische Funktion, die auf ein Window
im Kontext eines MarkupExtension
schließen kann: -
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()
leitet ein Fenster auf folgender Basis korrekt ab:
Window
durch Durchlaufen des visuellen Baums (wenn im Kontext eines UserControl
verwendet)Window
verwendet wird)