从页面绑定到窗口

时间:2014-11-11 18:31:29

标签: c# wpf xaml data-binding

在WPF中,我有一个窗口和一个框架,它将显示一些页面。我想从Page。

绑定到Window(它的属性和/或它的DataContext)

这是我尝试过的一个例子:

<TextBox Text="{Binding Path=Title,
    RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" />

这在Window的XAML中成功,但在Page的XAML中失败。如何让它在页面中工作?

1 个答案:

答案 0 :(得分:1)

在这种情况下,我们似乎无法成功设置Binding。 ElementNameRelativeSourceSource的所有用途均无效。我们知道可以像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)。上面实现的类不支持该速记转换。