从页面绑定到窗口
本文关键字:窗口 绑定 | 更新日期: 2023-09-27 18:30:06
在WPF中,我有一个窗口和一个框架,其中将显示一些页面。我想从页面绑定到Window(其属性和/或DataContext)。
这是我尝试的一个例子:
<TextBox Text="{Binding Path=Title,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" />
这在窗口的XAML中成功,但在页面的XAML中失败。我如何让它在页面中工作?
在这种情况下,我们似乎没有办法成功设置绑定。ElementName
、RelativeSource
、Source
的所有使用都没有帮助。我们知道主窗口可以像这样访问Application.Current.MainWindow
。但是,只有当主窗口是应用程序中唯一的窗口时,才能使用以下方法。否则就不安全了。我认为最好的解决方案是实现您自己的附加属性,帮助将页面(或任何FrameworkElement)的DataContext设置为Type指定的某个祖先。这意味着我们将几乎桥接DataContext流,就好像没有任何截断一样。以下是详细的实现:
//the main class used in your XAML code
public static class DataContextService {
public static readonly DependencyProperty DataContextFromAncestorProperty = DependencyProperty.RegisterAttached("DataContextFromAncestor", typeof(object), typeof(DataContextService), new UIPropertyMetadata(dataContextPropertyChanged));
public static object GetDataContextFromAncestor(DependencyObject o)
{
return o.GetValue(DataContextFromAncestorProperty);
}
public static void SetDataContextFromAncestor(DependencyObject o, object value)
{
o.SetValue(DataContextFromAncestorProperty, value);
}
private static void dataContextPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
var elem = target as FrameworkElement;
var type = e.NewValue as Type;
if (type == null || elem == null) return;
if (elem.IsLoaded) SetDataContextFromAncestorOfType(elem, type);
else {
elem.Loaded += loadedHandler;
}
}
private static void SetDataContextFromAncestorOfType(FrameworkElement elem, Type ancestorType)
{
elem.DataContext = elem.FindAncestorOfType(ancestorType);
}
private static void loadedHandler(object sender, EventArgs e)
{
var elem = sender as FrameworkElement;
SetDataContextFromAncestorOfType(elem, GetDataContextFromAncestor(elem) as Type);
elem.Loaded -= loadedHandler;
}
}
//a helper class to find the first ancestor of some Type
public static class ElementExtension
{
public static DependencyObject FindAncestorOfType(this DependencyObject o, Type ancestorType)
{
var parent = VisualTreeHelper.GetParent(o);
if (parent != null)
{
if (parent.GetType().IsSubclassOf(ancestorType) || parent.GetType() == ancestorType)
{
return parent;
}
return FindAncestorOfType(parent, ancestorType);
}
return null;
}
}
在XAML中的用法:
//suppose this TextBox is inside your Page
<TextBox Text="{Binding Title}"
local:DataContextService.DataContextFromAncestor="{x:Type Window}"/>
请使用{x:Type}
指定类型,不要使用简单字符串(例如应该使用{x:Type Window}
而不仅仅是Window
)。上面实现的类不支持这种简写转换。