绑定到 WPF 中的依赖项和常规属性
本文关键字:常规 属性 依赖 WPF 绑定 | 更新日期: 2023-09-27 18:11:37
我几天前开始学习 WPF,并一直在创建一些测试项目来评估我在学习材料时对材料的理解。根据这篇文章,"一个属性只有在它是依赖属性时才能被绑定。为了测试这一点,我使用了两种不同的模式:
1. 使用 MVVM 模式(某种(
我创建了Movie
模型:
public class MovieModel
{
private string _movieTitle;
private string _rating;
public string MovieTitle
{
get { return _movieTitle; }
set { _movieTitle = value; }
}
public string Rating
{
get { return _rating; }
set { _rating = value; }
}
}
和MovieViewModel
视图模型:
public class MovieViewModel
{
MovieModel _movie;
public MovieViewModel()
{
_movie = new MovieModel { MovieTitle = "Inception (Default)" };
}
public MovieModel Movie
{
get { return _movie; }
set { _movie = value; }
}
public string MovieTitle
{
get { return Movie.MovieTitle; }
set { Movie.MovieTitle = value; }
}
}
最后在我的主View
中,我将 DataContext 设置为 MovieViewModel
类的一个实例:
<Window x:Class="MVVMTestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMTestProject.ViewModels"
Name="MainWindowElement"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MovieViewModel/>
</Window.DataContext>
<Grid>
<StackPanel Orientation="Vertical">
<TextBox Width="150" Text="{Binding Path=MovieTitle}"></TextBox>
</StackPanel>
</Grid>
这工作正常,当我运行应用程序时,我在文本框中看到Inception (Default)
,即使Model
或ViewModel
中的任何属性都没有DependencyProperties
。现在第二次尝试是:
2. 在 MainView
的代码隐藏中使用属性
在我的主视图的代码后面,我把:
private string _myText;
public MainWindow()
{
InitializeComponent();
MyText = "Some Text";
}
public string MyText
{
get { return _myText; }
set { set _myText = value; }
}
然后我把我的观点改为:
<Window x:Class="MVVMTestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMTestProject.ViewModels"
Name="MainWindowElement"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MovieViewModel/>
</Window.DataContext>
<Grid>
<StackPanel Orientation="Vertical">
<TextBox Width="150" Text="{Binding ElementName=MainWindowElement, Path=MyText}"></TextBox>
</StackPanel>
</Grid>
但这没有用。当我运行应用程序时,文本框为空。所以我将属性更改为依赖属性,奇怪的是,它起作用了。所以我不明白为什么模型和 ViewModel 上的属性可以是常规属性,但代码隐藏属性必须是依赖项属性才能绑定到?是因为视图模型设置为视图的 DataContext,并且解析器足够聪明以实现这一点,还是有其他原因?
还有一个不太相关的问题:我注意到在几乎每篇关于 WPF 的文章中,人们都使用局部变量,然后为其定义一个 getter 和 setter,即使我们都知道在 .NET 2.5(我相信?(及更高版本中,我们可以只使用 get; set;
语法而不必定义局部成员变量。那么这有什么具体的原因吗?
提前谢谢。
-
仅在将用作绑定目标的
FrameworkElement
(依赖项对象(上需要DependencyProperty
,这意味着您将通过 XAML 应用 {Binding} 扩展或通过代码设置绑定的属性。在您的示例中,只需要DependencyProperty
TextBox.Text
。在第二个示例中,绑定不起作用,因为您没有适当的机制来发送从绑定源发送属性值已更改的通知。通常,这是通过实现INotifyPropertyChanged
接口并在属性setter中引发PropertyChanged事件来完成的。将属性更改为DependencyProperty
时,还会获得通知机制,以便将属性更改传播到目标 (TextBox(。因此,您可以通过引发PropertyChanged
事件来使其工作,而无需DependencyProperty
。请注意,除了绑定之外,还有其他用途需要DependencyProperty
(样式、动画... -
PropertyChanged
事件可能是使用支持字段(而不是作为自动属性(实现属性的主要原因。因为您需要在属性设置器中PropertyChanged
事件。
拿起帖子末尾的第二个问题:
还有一个不太相关的问题:我注意到在几乎每篇关于 WPF 的文章中,人们都使用局部变量,然后为它定义一个 getter 和 setter,即使我们都知道在 .NET 2.5(我相信?(及更高版本中,我们可以只使用
get; set;
语法而不必定义局部成员变量。那么这有什么具体的原因吗?
在您的代码中,您给出了如下示例:
private string _movieTitle;
public string MovieTitle
{
get { return _movieTitle; }
set { _movieTitle = value; }
}
该代码正是编译器在您编写此代码时生成的代码:
public string MovieTitle { get; set; }
您在 WPF 中看到类似第一个窗体的原因是,我们希望 WPF 绑定在属性值更改时做出反应,为了实现这一点,我们需要通过 INotifyPropertyChanged
添加更改通知。
有很多方法可以做到这一点,但在现代 C# 中,你可以编写如下内容:
public class MovieViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _movieTitle;
public string MovieTitle
{
get { return _movieTitle; }
set
{
if (_movieTitle == value)
return;
_movieTitle = value;
OnPropertyChanged();
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
在 setter 中,我们使用属性的字符串名称引发 PropertyChanged
事件, MovieTitle
,编译器为我们传递该属性,因为 [CallerMemberName]
属性和默认值 null
因此我们在调用它时不必传递任何东西。
使用 mvvm 光,您可以绑定属性并引发事件。
/// <summary>
/// The <see cref="SelectedPriority" /> property's name.
/// </summary>
public const string SelectedPriorityPropertyName = "SelectedPriority";
private string _selectedPriority = "normalny";
/// <summary>
/// Sets and gets the SelectedPriority property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public string SelectedPriority
{
get
{
return _selectedPriority;
}
set
{
if (_selectedPriority == value)
{
return;
}
RaisePropertyChanging(SelectedPriorityPropertyName);
_selectedPriority = value;
RaisePropertyChanged(SelectedPriorityPropertyName);
}
}
这个类扩展了ViewModelBase,它有方法RaisePropertyChanged,RaisePropertyChange。您可以从本网站 http://www.galasoft.ch/mvvm/下载框架。安装后,您可以使用代码片段到 mvvminpc 来创建可以绑定的属性。
您的另一个问题已得到解答 为什么在 WPF 中使用 INotifyPropertyChanged 与绑定?
最后,您需要实现 RaisePropertyChanged(( 方法并在 set 中使用此方法;get 以通知视图有关更改属性的信息。
实现 INotifyPropertyChanged - 是否存在更好的方法?