WPF用户控件父
我有一个用户控件,我在运行时加载到一个MainWindow
。 我无法从UserControl
获取包含窗口的句柄。
我已经试过this.Parent
,但它总是空。 有谁知道如何从WPF中的用户控件获取包含窗口句柄?
这里是如何加载控制:
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); }
尝试使用以下内容
Window parentWindow = Window.GetWindow(userControlRefernce);
GetWindow方法将为您提供VisualTree,并find托pipe您的控件的窗口。
我会添加我的经验。 尽pipe使用Loaded事件可以完成这项工作,但我认为可能更适合重写OnInitialized方法。 在第一次显示窗口之后发生加载。 OnInitialized让你有机会做出任何改变,例如,在渲染之前把控制添加到窗口中。
我需要在Loaded事件处理程序中使用Window.GetWindow(this)方法。 换句话说,我使用Ian Oakes的答案和Alex的答案来获得用户控件的父项。
public MainView() { InitializeComponent(); this.Loaded += new RoutedEventHandler(MainView_Loaded); } void MainView_Loaded(object sender, RoutedEventArgs e) { Window parentWindow = Window.GetWindow(this); ... }
尝试使用VisualTreeHelper.GetParent或使用下面的recursion函数来查找父窗口。
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); } }
这个怎么样:
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)); } } }
我发现一个UserControl的父节点在构造函数中总是为null,但是在任何情况下,父节点都是正确设置的。 我想它必须与控制树的加载方式有关。 所以要解决这个问题,你可以在控件Loaded事件中获得父对象。
举个例子,签出这个问题的WPF用户控件的DataContext是空的
这种方法对我来说很有效,但并不像你的问题那样具体:
App.Current.MainWindow
如果您发现这个问题并且VisualTreeHelper不适合您或者偶尔工作,您可能需要在algorithm中包含LogicalTreeHelper。
这是我正在使用的:
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); }
其他方式:
var main = App.Current.MainWindow as MainWindow;
它为我工作:
DependencyObject GetTopLevelControl(DependencyObject control) { DependencyObject tmp = control; DependencyObject parent = null; while((tmp = VisualTreeHelper.GetParent(tmp)) != null) { parent = tmp; } return parent; }
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);
上面镀金的版本(我需要一个通用的函数,可以推断一个Window
内的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()
将在以下基础上正确推断出一个Window:
- 根
Window
通过行走可视化树(如果在UserControl
的上下文中使用) - 它使用的窗口(如果它在
Window
的标记中使用)
这对我来说不起作用,因为它在树上走得太远,并且获得了整个应用程序的绝对根窗口:
Window parentWindow = Window.GetWindow(userControlReference);
然而,这工作得到了直接的窗口:
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();