在WPF中,我有一个窗口和一个框架,它将显示一些页面。我想从Page。
绑定到Window(它的属性和/或它的DataContext)这是我尝试过的一个例子:
<TextBox Text="{Binding Path=Title,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" />
这在Window的XAML中成功,但在Page的XAML中失败。如何让它在页面中工作?
答案 0 :(得分:1)
在这种情况下,我们似乎无法成功设置Binding。 ElementName
,RelativeSource
,Source
的所有用途均无效。我们知道可以像Application.Current.MainWindow
一样访问主窗口。但是,只有当主窗口是应用程序中的唯一窗口时,才能使用该方法。否则它不安全。我认为最好的解决方案是实现自己的附加属性,帮助将Page(或任何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
)。上面实现的类不支持该速记转换。