试图将我的旧大脑包裹在WPF数据绑定上。从我能想到的最简单的场景开始:一个有效的在线示例,然后我简化了它
我将一个简单的string
属性绑定到一个TextBlock
。没用。当我把string
封装在自己的类中时,它运行得很好!
问题:为什么我的string
属性不起作用,而我的类起作用?
<Window x:Class = "DataBindingOneWay.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Height = "350" Width = "600">
<Grid>
<StackPanel Orientation = "Vertical" HorizontalAlignment="Center" Margin="0,100,0,0">
<TextBlock Text="{Binding Name1}" />
</StackPanel>
</Grid>
</Window>
using System.Windows;
namespace DataBindingOneWay
{
public partial class MainWindow : Window
{
public class Employee
{
public string? Name1 { get; set; } = "Paul";
}
public string? Name1 { get; set; } = "Peter";
public MainWindow()
{
InitializeComponent();
DataContext = new Employee();
// DataContext = Name1;
}
}
}
绑定操作在通过DataContext
属性从FrameworkElement
派生的元素上设置的数据上下文上。数据上下文是在元素树中继承的。
在XAML元素上声明数据绑定时,它们通过查看其直接DataContext属性来解析数据绑定。数据上下文通常是绑定源值路径求值的绑定源对象。您可以在绑定中覆盖此行为,并设置特定的绑定源对象值。如果未设置承载绑定的对象的DataContext属性,则会检查父元素的DataContext特性,依此类推,直到XAML对象树的根。简而言之,用于解析绑定的数据上下文是从父对象继承的,除非在对象上显式设置。
如果没有数据上下文集,或者需要将其他元素引用为绑定源,则需要使用Source
、ElementName
或RelativeSource
参数化Binding
。
绑定可以配置为使用特定对象进行解析,而不是使用数据上下文进行绑定解析。
让我们回顾一下如何绑定MainWindow
中定义的属性。最初没有分配任何数据上下文。因此,到Name1
的所有绑定都将失败。我们能做什么?以下是一些选项(还有更多)。
-
在代码隐藏中将
MainWindow
的DataContext
设置为this
。public MainWindow() { InitializeComponent(); DataContext = this; }
这意味着所有控件都继承
MainWindow
作为绑定源。因此,我们可以像这样绑定Name1
属性:<TextBlock Text="{Binding Name1}"/>
这里
Name1
是要在绑定源上绑定的属性的名称(或属性路径)。因此,如果我们简单地将Name1
直接指定为窗口的DataContext
,那么我们将需要引用绑定源本身,这就是没有属性路径的{Binding}
所做的。public MainWindow() { InitializeComponent(); DataContext = Name1; }
<TextBlock Text="{Binding}"/>
-
如果未设置
DataContext
,则仍然可以使用ElementName
(需要分配给目标控件的x:Name
)或RelativeSource
引用元素,CCD_25指代从当前元素遍历父元素到根元素的元素树中的元素。<TextBlock Text="{Binding Name1, RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"/>
此示例转换为:在元素树上搜索类型为
MainWindow
的绑定源,如果找到它,则绑定到它的Name1
属性。正如您所看到的,如果像您的示例中那样在控件本身上定义属性,则不一定需要数据上下文。尽管如此,如果没有任何东西可以阻止DataContext
属性,通常您会使用它,因为它是方便地继承的。
我希望你看到它没有什么真正神奇的地方。关于具有约束力的sytax(可能会令人困惑),有一个很好的文档应该会消除你的很多问号:
- 绑定路径语法
- 数据绑定概述(WPF.NET)
我开始思考:字符串类中的哪个字段,或者更确切地说,属性实际上包含字符串的"值"?
奖励回合:您根本不需要担心。您绑定到string
属性,WPF知道如何显示它,不需要使用内部结构,但出于教育目的,文档指出:
字符串是用于表示文本的字符的顺序集合。CCD_ 30对象是表示字符串的CCD_ 31对象的顺序集合;32对象对应于UTF-16代码单元。
String
对象的值是System.Char
对象的顺序集合的内容,并且该值是不可变的(即,它是只读的)。
string
类型使用其索引器属性Chars
公开此字符数组。
因为在绑定到字符串时,要绑定到的对象内部没有Name1
。也就是说,在Name1
内部没有Name1
(Name1.Name1
的结果是什么?)。然而,在Employee
对象内有一个Name1
(Employee.Name1
的结果是什么?)
如果要访问MainWindow
的Name1
属性,应将DataContext
设置为this
(它是MainWindow实例),而不是Name1
。
using System.Windows;
namespace DataBindingOneWay
{
public partial class MainWindow : Window
{
public class Employee
{
public string? Name1 { get; set; } = "Paul";
}
public string? Name1 { get; set; } = "Peter";
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}
}
或者从另一方面-当您希望Name1
属性设置为MainWindow
的DataContext
时,您的绑定应该如下所示:
<Window x:Class = "DataBindingOneWay.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
Height = "350" Width = "600">
<Grid>
<StackPanel Orientation = "Vertical" HorizontalAlignment="Center" Margin="0,100,0,0">
<TextBlock Text="{Binding}" />
</StackPanel>
</Grid>
</Window>
多亏了Jonathan鼓舞人心的回应,我开始思考:字符串类中的哪个字段,或者更确切地说,属性实际上保存了字符串的"值"?
我玩了所有的东西,但似乎没有什么能控制住真正的弦!(奇怪)。这就是为什么我有了一个疯狂的想法,并尝试了简单的
<TextBlock Text="{Binding}" />
和
DataContext = Name1;
而且。。。成功了!