WPF MVVM中的字符串属性是不可变的吗?
我的模型:
sealed class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
}
我的ViewModel:
// INotifyPropertyChanged notifies the View of property changes, so that Bindings are updated.
密封类MyViewModel:InotifyPropertychanged { 私人用户;
public string FirstName {
get {return user.FirstName;}
set {
if(user.FirstName != value) {
user.FirstName = value;
OnPropertyChange("FirstName");
// If the first name has changed, the FullName property needs to be udpated as well.
OnPropertyChange("FullName");
}
}
}
public string LastName {
get { return user.LastName; }
set {
if (user.LastName != value) {
user.LastName = value;
OnPropertyChange("LastName");
// If the first name has changed, the FullName property needs to be udpated as well.
OnPropertyChange("FullName");
}
}
}
// This property is an example of how model properties can be presented differently to the View.
// In this case, we transform the birth date to the user's age, which is read only.
public int Age {
get {
DateTime today = DateTime.Today;
int age = today.Year - user.BirthDate.Year;
if (user.BirthDate > today.AddYears(-age)) age--;
return age;
}
}
// This property is just for display purposes and is a composition of existing data.
public string FullName {
get { return FirstName + " " + LastName; }
}
public MyViewModel() {
user = new User {
FirstName = "John",
LastName = "Doe",
BirthDate = DateTime.Now.AddYears(-30)
};
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChange(string propertyName) {
if(PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
然后,在XAML中,我们使用绑定:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="4" Text="{Binding FullName}" HorizontalAlignment="Center" FontWeight="Bold"/>
<Label Grid.Column="0" Grid.Row="1" Margin="4" Content="First Name:" HorizontalAlignment="Right"/>
<!-- UpdateSourceTrigger=PropertyChanged makes sure that changes in the TextBoxes are immediately applied to the model. -->
<TextBox Grid.Column="1" Grid.Row="1" Margin="4" Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Width="200"/>
<Label Grid.Column="0" Grid.Row="2" Margin="4" Content="Last Name:" HorizontalAlignment="Right"/>
<TextBox Grid.Column="1" Grid.Row="2" Margin="4" Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Width="200"/>
<Label Grid.Column="0" Grid.Row="3" Margin="4" Content="Age:" HorizontalAlignment="Right"/>
<TextBlock Grid.Column="1" Grid.Row="3" Margin="4" Text="{Binding Age}" HorizontalAlignment="Left"/>
</Grid>
背后的代码:
public partial class MainWindow : Window
{
private readonly MyViewModel _viewModel;
public MainWindow() {
InitializeComponent();
_viewModel = new MyViewModel();
// The DataContext serves as the starting point of Binding Paths
DataContext = _viewModel;
}
}
我的问题是用于绑定。例如,如果更改 firstName
,则视图也会更改。我们知道C#中的字符串是不变的,当值更改时,创建了新对象。但是在WPF绑定中,如果更改了 firstName
是创建了一个新的名称对象吗?我认为这是没有的,因为我们使用绑定将值保存在一个对象中。那么 onPropertyChange
内部删除不变的?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,
firstName
未重新分配或突变。它是对被重新分配的Backing字符串
的引用。当您拥有:
It is compiled (roughly) into:
如您所见,将值分配给
firstName
将值作为参数传递给setter
forfirst> firstName
reassigns_firstName
代码>(私人备份字段)。FirstName
永远不会更改。这也是为什么需要
InotifyProperyChanged
。由于绑定是firstName
和firstName
永远不会更改的,因此框架需要一种方法来确定first> firstName
更改的值何时。No,
FirstName
is not reassigned or mutated. It is a reference to a backingstring
that is reassigned.When you have an auto-implemented property:
It is compiled (roughly) into:
As you can see, assigning a value to
FirstName
passes the value as an argument to thesetter
forFirstName
which reassigns_firstName
(the private backing field).FirstName
is never changed.This is also why
INotifyProperyChanged
is required. Because the binding is onFirstName
andFirstName
never changes, the framework needs a way to tell when the value referenced byFirstName
changes.在MVVM中,您可以绑定到属性(不与支持成员)。
当您更改属性(例如
String
)时,您可以从技术上将新对象放置在类成员的后面(即属性的背景实例)。onPropertychanged
告诉视图,因此它再次调用属性getter(不是字符串实例),获取新实例等...如果您不这样做,则视图将保持并显示参考对于您的ViewModel不再使用的旧字符串
,我们有
observableCollections
和可观察的
类型,可以自动执行此通知,因为它们是可突变的,这意味着他们意味着他们保持相同的实例,而只有其内容会改变。最常见的是,使用ObservableCollections来通知视图,其内容已更改(而集合实例保持不变)。 (添加了元素,删除..)
在这种情况下,您无需通知,因为该视图已注册到该事件。
如果您将新实例分配给ObservableCollection成员,则该视图也不会在没有属性汇总的情况下正确更新,因为该集合的原始实例将不再更改。
In MVVM, you bind to Properties (not to the backing members).
When you change a Property, like a
string
, then you technically place a new object behind the class member (i.e. the backing instance of a property).OnPropertyChanged
tells that to the View, so it calls the Property Getter (not the string instance) again, getting a the new instance etc...If you would not, the View would hold and display a reference to the old string, which is no longer used by your Viewmodel
Then, we have
ObservableCollections
andObservable
types, that can do this notification automatically, because they are mutable, meaning they stay the same instance, while only their content changes.Most commonly, ObservableCollections are used, to notify the View, that it contents has changed (while the collection instance stayed the same). (element added, removed..)
In that case, you dont need to Notify, because the View has registered to that event.
If you would assign a new instance to an observableCollection member, the view would also not update correctly without Propertychanged, because the original instance of the collection would no longer change.