wpf - 关于 DataContext、硬编码值、绑定(bind)表达式、模板和嵌套控件的操作顺序

标签 wpf wpf-controls binding datacontext

这困扰了我一段时间,我厌倦了解决这个问题。在 WPF 中,什么是“操作顺序”:

  • 设置数据上下文
  • 继承数据上下文
  • 评估“硬编码”属性值
  • 评估 {Binding} 属性值

  • 所有这些都考虑了嵌套控件和模板(应用模板时)。

    我遇到了许多有问题的场景,但这只是一个例子:

    自定义用户控件
    <UserControl x:Class="UserControls.TestUserControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 >
        <StackPanel>
            <Label Content="{Binding Label1}" />
            <Label Content="{Binding Label2}" />
        </StackPanel>
    </UserControl>
    

    用户控制代码隐藏
    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace UserControls
    {
        public partial class TestUserControl : UserControl
        {
            public static readonly DependencyProperty Label1Property = DependencyProperty.Register("Label1", typeof(String), typeof(TestUserControl), new FrameworkPropertyMetadata(OnLabel1PropertyChanged));
            public String Label1
            {
                get { return (String)GetValue(Label1Property); }
                set { SetValue(Label1Property, value); }
            }
    
            public static readonly DependencyProperty Label2Property = DependencyProperty.Register("Label2", typeof(String), typeof(TestUserControl), new FrameworkPropertyMetadata(OnLabel2PropertyChanged));
            public String Label2
            {
                get { return (String)GetValue(Label2Property); }
                set { SetValue(Label2Property, value); }
            }
    
            public TestUserControl()
            {
                DataContext = this;
    
                InitializeComponent();
            }
    
            private static void OnLabel1PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
            {
                //used for breakpoint
            }
    
            private static void OnLabel2PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
            {
                //used for breakpoint
            }
        }
    }
    

    使用用户控件的窗口
    <Window x:Class="Windows.TestWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:UC="clr-namespace:UserControls"
            >
        <StackPanel>
            <Label Content="Non user control label" />
    
            <UC:TestUserControl x:Name="uc" Label1="User control label 1" Label2="{Binding Label2FromWindow}" />
        </StackPanel>
    </Window>
    

    以及窗口的代码隐藏
    using System;
    using System.Windows;
    
    namespace Windows
    {
        public partial class TestWindow : Window
        {
            public String Label2FromWindow
            {
                get { return "User control label 2"; }
            }
    
            public TestWindow()
            {
                DataContext = this;
    
                InitializeComponent();
            }
        }
    }
    

    那么在这种情况下,为什么用户控件中的“Label2”没有从窗口中获取“Label2FromWindow”的值呢?我觉得这是一个时间问题,用户控件首先评估其所有表达式,然后窗口稍后评估其表达式,并且用户控件永远不会“通知”窗口的评估值。

    该示例希望有助于说明一个问题,但我真正的问题是:

    关于 DataContext、属性上的硬编码值、绑定(bind)表达式、模板和嵌套控件的操作顺序是什么?

    编辑:

    H.B.帮助我认识到这一点。当窗口的 DataContext 设置为自身时,用户控件将“继承”该 DataContext。这让 Binding 在用户控件的属性上工作,但在用户控件内绑定(bind)到其本地属性将不起作用。当直接在用户控件上设置 DataContext 时,窗口对用户控件属性的绑定(bind)不再起作用,但用户控件随后可以绑定(bind)到自己的本地属性。以下是有效的更新代码示例。

    用户控制:
    <UserControl x:Class="UserControls.TestUserControl"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    Name="uc">
        <StackPanel>
            <Label Content="{Binding ElementName=uc, Path=Label1}" />
            <Label Content="{Binding ElementName=uc, Path=Label2}" />
        </StackPanel>
    </UserControl>
    

    用户控制代码隐藏:
    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace UserControls
    {
        public partial class TestUserControl : UserControl
        {
            public static readonly DependencyProperty Label1Property = DependencyProperty.Register("Label1", typeof(String), typeof(TestUserControl));
            public String Label1
            {
                get { return (String)GetValue(Label1Property); }
                set { SetValue(Label1Property, value); }
            }
    
            public static readonly DependencyProperty Label2Property = DependencyProperty.Register("Label2", typeof(String), typeof(TestUserControl));
            public String Label2
            {
                get { return (String)GetValue(Label2Property); }
                set { SetValue(Label2Property, value); }
            }
    
            public TestUserControl()
            {
                InitializeComponent();
            }
        }
    }
    

    测试窗口:
    <Window x:Class="Windows.TestWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:UC="clr-namespace:UserControls"
            >
        <StackPanel>
            <Label Content="Non user control label" />
    
            <UC:TestUserControl Label1="User control label 1" Label2="{Binding Label2FromWindow}" />
        </StackPanel>
    </Window>
    

    测试窗口代码隐藏:
    using System;
    using System.Windows;
    
    namespace Windows
    {
        public partial class TestWindow : Window
        {
            public String Label2FromWindow
            {
                get { return "User control label 2"; }
            }
    
            public TestWindow()
            {
                DataContext = this;
                InitializeComponent();
            }
        }
    }
    

    最佳答案

    我认为这不是关于顺序,而是优先级(也许我在这里 split 头发)。您明确设置了 DataContextUserControl -- 这意味着它 不会被继承 ,因此您的绑定(bind)查找属性 Label2FromWindow在用户控件内。显然,它没有找到它。

    只是永远不要设置DataContextUserControl实例,你不应该遇到这样的问题。 (命名您的 UserControl 并使用 ElementName 进行内部绑定(bind))

    完整的优先级列表see MSDN .

    关于wpf - 关于 DataContext、硬编码值、绑定(bind)表达式、模板和嵌套控件的操作顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5783987/

    相关文章:

    wpf - 如何显示两个窗口之间的对齐线

    wpf - vb.net 无法删除处理程序

    wpf - 如何设置 WPF 窗口的位置?

    wpf - 关于WPF拖放库的建议

    wpf - 将 ObjectDataProvider 绑定(bind)到属性而不是方法

    programming-languages - 静态/动态类型与静态/动态绑定(bind)

    wpf - 覆盖没有主题的组合框模板

    c# - 在 WPF ControlTemplate 中查找控件

    c# - 如何使用 CodedUI 自动化知道光标在 WpfEdit 字段中的位置?

    c# - ListView 不刷新其项目