我的模型:
sealed class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
}
我的視圖模型:
// 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改變了,是否會創建一個新的 FirstName 物件?我認為它不是,因為我們使用系結將值保存在一個物件中。那么是否OnPropertyChange在內部洗掉不可變物件?
uj5u.com熱心網友回復:
不,FirstName不會重新分配或變異。它是對string重新分配的支持的參考。
當你有一個自動實作的屬性時:
public string FirstName { get; set; }
它被編譯(大致)成:
private string _firstName;
public string FirstName
{
get => _firstName;
set => _firstName = value;
}
如您所見,將值分配給FirstName將值作為引數傳遞給setter重新FirstName分配_firstName的物件(私有支持欄位)。FirstName永遠不會改變。
這也是為什么INotifyProperyChanged需要。因為系結是打開的FirstName并且FirstName永遠不會改變,所以框架需要一種方法來判斷所參考的值何時FirstName改變。
uj5u.com熱心網友回復:
在 MVVM 中,您系結到屬性(而不是支持成員)。
當您更改屬性時,例如 a string,從技術上講,您在類成員后面放置一個新物件(即屬性的支持實體)。
OnPropertyChanged告訴視圖,所以它再次呼叫屬性獲取器(而不是字串實體),獲取新實體等......
如果您不這樣做,視圖將保存并顯示對舊字串的參考,您的 Viewmodel 不再使用該字串
那么,我們有
ObservableCollections和Observable型別,可以自動執行此通知,因為它們是可變的,這意味著它們保持相同的實體,而只有它們的內容發生變化。
最常見的是,使用 ObservableCollections 來通知 View 其內容已更改(而集合實體保持不變)。(元素添加,洗掉..)
在這種情況下,您不需要通知,因為視圖已注冊到該事件。
如果您將新實體分配給 observableCollection 成員,則視圖也不會在沒有 Propertychanged 的??情況下正確更新,因為集合的原始實體將不再更改。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/494717.html
