it-swarm.com.de

Übergeordnetes WPF-Benutzersteuerelement

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

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); 
337
Ian Oakes

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.

33
paul

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

    ...
}
13
Alan Le

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);
        }
    }
13
Jobi Joy

Dieser Ansatz hat bei mir funktioniert, ist aber nicht so spezifisch wie Ihre Frage:

App.Current.MainWindow
6
Anthony Main

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));
        }
    } 
}
6
Eric Coulson

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

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

5
Alex

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

Ein anderer Weg:

var main = App.Current.MainWindow as MainWindow;
3
Pnct

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

DependencyObject parent = GetTopParent(thisUserControl);
1
Agus Syahputra

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;
}
0
Tore Aurstad

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:

  • die Wurzel Window durch Durchlaufen des visuellen Baums (wenn im Kontext eines UserControl verwendet)
  • das Fenster, in dem es verwendet wird (wenn es im Kontext des Markups eines Window verwendet wird)
0
Ruben Bartelink