WPF 数据绑定混乱
WPF Data Binding confusion
我刚刚开始学习有关 WPF 的课程,我对与数据绑定相关的某些领域有些困惑。我没有语法问题,但很可能犯了一些新手错误,我有几个问题。
我已经完成了一个带有 2 个文本框的简单屏幕,当我单击一个按钮时,这两个项目被添加到一个列表框中。
在 XAML
的 Window 标签内引用 class
xmlns:classes="clr-namespace:WPF_Course.Classes"
添加了 Window 资源
<Window.Resources>
<classes:People x:Key="people"/>
</Window.Resources>
这是我声明列表框的方式
<ListBox DataContext="{Binding Source={StaticResource people}}"
ItemsSource="{Binding Persons}"
x:Name="PersonListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel>
<TextBlock Text="{Binding FullName}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
所以,我在我的 ListBox 中添加了一个 DataContext
,我将它绑定到我的人员资源,我还添加了一个 ItemSource
,它在我的 People
.
这是我的class
public class People : ObservableCollection<Person>
{
public ObservableCollection<Person> Persons { get { return persons; } set { persons = value; } }
private ObservableCollection<Person> persons = new ObservableCollection<Person>();
public People()
{
for (int i = 0; i < 1; i++)
{
// implicitly I add one item just for messing around with the constructor
Persons.Add(new Person()
{
Name = "Dummy",
LastName = "Dummy",
Age = 15
});
}
}
}
根据我目前所做的,我有以下问题:
1) 两者有什么区别(效果一样,但是背后有更多的道理?)
ItemsSource = "{Binding Persons}"
和
ItemsSource = "{Binding Path = Persons }"
此外,通过离开 ItemSource = "{Binding}"
我实际上只是实例化了一个 People
实例,因此我的所有逻辑都从 class 的构造函数中处理了吗?我弄乱了它,它似乎这样做了,但我不确定。
2) 在我的 Peoples
class 上,我实现了 ObservableCollection<Person>
(其中 Person 也是 class)。最初我从构造函数本身对我的列表进行静态添加,并且我没有在 class(属性的 ObservableCollection<person> type
)中定义任何属性,因此需要它(接口的实现)但现在使用属性 我真的需要它吗? ,所以我的问题是:
如果我的 class 的唯一目的是仅从构造函数加载其集合中的内容(而不是从外部 class,因此需要某种 属性 ), 是用 ObservableCollection<myClass>
实现我的 class 还是定义我已经完成的相同类型的属性是最佳实践? (用于从外部访问 class)
对于这些奇怪的问题,我深表歉意,因为我知道它们听起来有些愚蠢,我正在查看验证,因为我最近才开始使用 wpf。
谢谢
编辑2:谢谢大家的回答,我现在明白了。另外,我忘了向您展示我是如何在我的集合中插入数据的。 (添加这个编辑是为了让我在忘记它时记住它,也为了其他可能偶然发现这个线程有类似困惑的人)
ObservableCollection<Person> ppl;
public MainWindow()
{
InitializeComponent();
person = new Person();
stackPanelPerson.DataContext = person;
people = new People();
ppl = people.Persons;
PersonListBox.ItemsSource = ppl;
}
最初我是这样做的
ppl.Add(new Person() { Name = boxFirstName.Text, LastName = boxLastName.Text, Age = Int32.Parse(boxAge.Text) });
然后我意识到我正在我的 Person Class(INotifyPropertyChanged) 上使用数据绑定和属性,所以我将其更改为:
ppl.Add(new Person() { Name = person.Name, LastName = person.LastName, Age = person.Age});
再次感谢大家的回复!!
祝你有美好的一天!
问题 1:
None,没有区别。 {Binding xyz}
和 {Binding Path=xyz}
一样,几乎就像一个快捷方式。但是它只能用于你在绑定中写的第一件事,例如,你不能这样做:
{Binding ElementName=myElement, xyz}
相反,你会这样做:
{Binding ElementName=myElement, Path=xyz}
甚至更好:
{Binding xyz, ElementName=myElement}
Here's一个相关问题。
问题 2:
你做的是对的,你的collection人应该暴露为Property
,为什么?因为这样你就可以绑定它了。
在这种情况下不需要静态 属性。
我强烈建议研究 MVVM 设计模式。你可以找教程here
迈克涵盖了我想说的...
除了绑定之外,您还可以在绑定中显示不同的内容。这是我为代码项目编写的教程:Understanding SelectedValue, SelectedValuePath, SelectedItem & DisplayMemberPath + Demo
您可以使用虚拟数据制作 class 模型,这样您就可以在 VS 中的 XAML 设计器中看到预览。 MVVM 轻型框架对此有所帮助,并且还具有一些很酷的功能。还有其他框架,您实际上并不需要一个框架来执行 MVVM,但它们会有所帮助。
除此之外,祝您一路顺风……:)一旦掌握了它,就会很有趣……
1) 许多标记扩展理解缩短的语法,{Binding Persons}
和 {Binding Path=Persons}
之间没有区别。但是,有时您必须使用完整语法。
一个例子是自己制作
public class ExceptionBinding : Binding
{
public ExceptionBinding()
{
ValidationRules.Add(new ExceptionValidationRule());
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
}
}
那么你必须使用完整语法 {l:ExceptionBinding Path=Persons}
。
2) 这取决于。如果集合在绑定后 不会更改,则不必使用 ObservableCollection<>
。创建 List<>
、填充它并 然后 绑定到它会工作得很好。
MVVM
你一定要看一下,因为使用它会简化使用场景,让很多事情更加清晰。
None,没有区别。 {Binding propertyName}
和 {Binding Path=propertyName}
一样,几乎就像一个快捷方式,但是构造函数被调用是因为 DataContext="{Binding Source={StaticResource people}}"
.
视情况而定。如果集合在绑定后不会更改,则不必使用 ObservableCollection<>
。创建 List<>
、填充它然后绑定到它会很有效 well.But 如果你想从屏幕上更改集合并更新列表那么你需要去 ObservableCollection<>
我刚刚开始学习有关 WPF 的课程,我对与数据绑定相关的某些领域有些困惑。我没有语法问题,但很可能犯了一些新手错误,我有几个问题。
我已经完成了一个带有 2 个文本框的简单屏幕,当我单击一个按钮时,这两个项目被添加到一个列表框中。
在 XAML
的 Window 标签内引用 class
xmlns:classes="clr-namespace:WPF_Course.Classes"
添加了 Window 资源
<Window.Resources>
<classes:People x:Key="people"/>
</Window.Resources>
这是我声明列表框的方式
<ListBox DataContext="{Binding Source={StaticResource people}}"
ItemsSource="{Binding Persons}"
x:Name="PersonListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel>
<TextBlock Text="{Binding FullName}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
所以,我在我的 ListBox 中添加了一个 DataContext
,我将它绑定到我的人员资源,我还添加了一个 ItemSource
,它在我的 People
.
这是我的class
public class People : ObservableCollection<Person>
{
public ObservableCollection<Person> Persons { get { return persons; } set { persons = value; } }
private ObservableCollection<Person> persons = new ObservableCollection<Person>();
public People()
{
for (int i = 0; i < 1; i++)
{
// implicitly I add one item just for messing around with the constructor
Persons.Add(new Person()
{
Name = "Dummy",
LastName = "Dummy",
Age = 15
});
}
}
}
根据我目前所做的,我有以下问题:
1) 两者有什么区别(效果一样,但是背后有更多的道理?)
ItemsSource = "{Binding Persons}"
和
ItemsSource = "{Binding Path = Persons }"
此外,通过离开 ItemSource = "{Binding}"
我实际上只是实例化了一个 People
实例,因此我的所有逻辑都从 class 的构造函数中处理了吗?我弄乱了它,它似乎这样做了,但我不确定。
2) 在我的 Peoples
class 上,我实现了 ObservableCollection<Person>
(其中 Person 也是 class)。最初我从构造函数本身对我的列表进行静态添加,并且我没有在 class(属性的 ObservableCollection<person> type
)中定义任何属性,因此需要它(接口的实现)但现在使用属性 我真的需要它吗? ,所以我的问题是:
如果我的 class 的唯一目的是仅从构造函数加载其集合中的内容(而不是从外部 class,因此需要某种 属性 ), 是用 ObservableCollection<myClass>
实现我的 class 还是定义我已经完成的相同类型的属性是最佳实践? (用于从外部访问 class)
对于这些奇怪的问题,我深表歉意,因为我知道它们听起来有些愚蠢,我正在查看验证,因为我最近才开始使用 wpf。
谢谢
编辑2:谢谢大家的回答,我现在明白了。另外,我忘了向您展示我是如何在我的集合中插入数据的。 (添加这个编辑是为了让我在忘记它时记住它,也为了其他可能偶然发现这个线程有类似困惑的人)
ObservableCollection<Person> ppl;
public MainWindow()
{
InitializeComponent();
person = new Person();
stackPanelPerson.DataContext = person;
people = new People();
ppl = people.Persons;
PersonListBox.ItemsSource = ppl;
}
最初我是这样做的
ppl.Add(new Person() { Name = boxFirstName.Text, LastName = boxLastName.Text, Age = Int32.Parse(boxAge.Text) });
然后我意识到我正在我的 Person Class(INotifyPropertyChanged) 上使用数据绑定和属性,所以我将其更改为:
ppl.Add(new Person() { Name = person.Name, LastName = person.LastName, Age = person.Age});
再次感谢大家的回复!! 祝你有美好的一天!
问题 1:
None,没有区别。 {Binding xyz}
和 {Binding Path=xyz}
一样,几乎就像一个快捷方式。但是它只能用于你在绑定中写的第一件事,例如,你不能这样做:
{Binding ElementName=myElement, xyz}
相反,你会这样做:
{Binding ElementName=myElement, Path=xyz}
甚至更好:
{Binding xyz, ElementName=myElement}
Here's一个相关问题。
问题 2:
你做的是对的,你的collection人应该暴露为Property
,为什么?因为这样你就可以绑定它了。
在这种情况下不需要静态 属性。
我强烈建议研究 MVVM 设计模式。你可以找教程here
迈克涵盖了我想说的...
除了绑定之外,您还可以在绑定中显示不同的内容。这是我为代码项目编写的教程:Understanding SelectedValue, SelectedValuePath, SelectedItem & DisplayMemberPath + Demo
您可以使用虚拟数据制作 class 模型,这样您就可以在 VS 中的 XAML 设计器中看到预览。 MVVM 轻型框架对此有所帮助,并且还具有一些很酷的功能。还有其他框架,您实际上并不需要一个框架来执行 MVVM,但它们会有所帮助。
除此之外,祝您一路顺风……:)一旦掌握了它,就会很有趣……
1) 许多标记扩展理解缩短的语法,{Binding Persons}
和 {Binding Path=Persons}
之间没有区别。但是,有时您必须使用完整语法。
一个例子是自己制作
public class ExceptionBinding : Binding
{
public ExceptionBinding()
{
ValidationRules.Add(new ExceptionValidationRule());
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
}
}
那么你必须使用完整语法 {l:ExceptionBinding Path=Persons}
。
2) 这取决于。如果集合在绑定后 不会更改,则不必使用 ObservableCollection<>
。创建 List<>
、填充它并 然后 绑定到它会工作得很好。
MVVM
你一定要看一下,因为使用它会简化使用场景,让很多事情更加清晰。
None,没有区别。
{Binding propertyName}
和{Binding Path=propertyName}
一样,几乎就像一个快捷方式,但是构造函数被调用是因为DataContext="{Binding Source={StaticResource people}}"
.视情况而定。如果集合在绑定后不会更改,则不必使用
ObservableCollection<>
。创建List<>
、填充它然后绑定到它会很有效 well.But 如果你想从屏幕上更改集合并更新列表那么你需要去ObservableCollection<>