DataContext Binding
https://github.com/momo16542/WPFMVVMTutorial
上面連結為此篇的程式碼,版本為.net framework 4.7.1
在開始之前,可以下載範例,或是自己新增
- 新增一個WPF專案,會有一個預設的MainWindow
- 先新增兩個資料夾,Model跟ViewModel,此篇著重在ViewModel跟View的Binding。Model可以先忽略
- 在ViewModel中新增一個ViewModelBase
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
所有的ViewModel都要繼承ViewModelBase,或是實作INotifyPropertyChanged
Binding時,調用OnPropertyChanged
改變值才會更新View的介面
新增一個MainWindowViewModel
public class MainWindowViewModel : ViewModelBase
{
public BookViewModel Book
{
get => _book;
set
{
_book = value;
OnPropertyChanged();
}
}
private BookViewModel _book;
public ICommand ChangeBookCommand
{
get => _changeBookCommand;
set
{
_changeBookCommand = value;
OnPropertyChanged();
}
}
private ICommand _changeBookCommand;
public MainWindowViewModel()
{
ChangeBookCommand = new BaseCommand(ChangeBookExecute);
Book = new BookViewModel() { No = 0, Author = "A1000", Title = "A 100 Book" };
}
private void ChangeBookExecute()
{
var currentNo = Book.No + 1;
Book = new BookViewModel()
{ No = currentNo, Author = $"A{new Random().Next(100)}", Title = $"A {new Random().Next(100)} Book" };
}
}
然後在MainWindow程式碼中實例
private readonly MainWindowViewModel viewModel;
public MainWindow()
{
InitializeComponent();
viewModel = new MainWindowViewModel();
this.DataContext = viewModel;
}
DataContext是一個對Binding很重要的屬性,它會影響到控件如何在ViewModel中找尋對應的Binding。
DataContext是一個作用範圍,當有明確綁定時,控件會被限制在該範圍內
我們將MainWindow的DataContext設定成MainWindowViewModel
,所以在xaml中可以用MainWindowViewModel
的屬性名稱去Binding
<Grid DataContext="{Binding Book}" Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Grid.Row="0"
Grid.Column="0"
Margin="3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="No:" />
<TextBox
x:Name="noTextBox"
Grid.Row="0"
Grid.Column="1"
Width="120"
Height="23"
Margin="3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding No, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
<Label
Grid.Row="1"
Grid.Column="0"
Margin="3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="Author:" />
<TextBox
x:Name="authorTextBox"
Grid.Row="1"
Grid.Column="1"
Width="120"
Height="23"
Margin="3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding Author, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
<Label
Grid.Row="2"
Grid.Column="0"
Margin="3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="Title:" />
<TextBox
x:Name="titleTextBox"
Grid.Row="2"
Grid.Column="1"
Width="120"
Height="23"
Margin="3"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{Binding Title, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" />
</Grid>
<Button
Grid.Column="1"
Width="auto"
Height="30"
Margin="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Command="{Binding ChangeBookCommand}">
<TextBlock Margin="3" Text="Change Book" />
</Button>
在MainWindow中,左上角的Grid。Button的Command是直接用MainWindowViewModel
中的"ChangeBookCommand"
而裡面的Grid的DataContext是設定<Grid DataContext="{Binding Book}" Row="0">
,也就是會用MainWindowViewModel
中屬性名稱的"Book"去做Binding,而裡面的TextBox就可以使用BookViewModel
裡的屬性名稱去關聯
若是沒有將Grid的DataContext設定成<Grid DataContext="{Binding Book}" Row="0">
,那麼裡面的TextBox就要改成這樣Text="{Binding Book.Author "
有將Grid的DataContext屬性Binding到Book | 沒有將Grid的DataContext屬性Binding到Book |
Text="{Binding Author | Text="{Binding Book.Author |
Text="{Binding Title | Text="{Binding Book.Title, |
範例中的階層只有兩個
- MainWindowViewModel 透過程式碼綁定到MainWindow
- BookViewModel "Book" 綁定到Grid的DataContext,使得Grid裡面的所有控制項,只會在BookViewModel "Book"中找屬性
- ChangeBookCommand 綁定到Button上,由於Button是在Grid之外,所以會在MainWindowViewModel中尋找綁定屬性
DataContext的功能就是將該控件中的綁定範圍侷限在某一個屬性中,可以減少Binding時的階層輸入。
如果是更多階層的話,可以保持文件的簡潔,尤其是當程式裡可能會重複使用到同一個ViewModel時,可以避免用到預期外的屬性
若是程式執行時,發現不如預期的顯示,可以看visual studio的輸出視窗
有任何改進的意見及問題歡迎傳送到電子郵件
電子郵件:momo16542@gmail.com