昨天我們學了 Binding 的基本模式,今天要更深入:
在 WPF 中,Binding
必須知道資料來源是哪個物件,而這個來源就是 DataContext。
有幾種設定方式:
最常見的方式是在 MainWindow.xaml.cs
設定:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new StockViewModel
{
StockName = "2330 台積電",
Price = 1265m
};
}
}
這樣 MainWindow
底下的所有控制項就能直接綁定到 StockViewModel
的屬性。
有時候我們希望直接在 XAML 中設定 DataContext
:
<Window x:Class="MyStockApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:MyStockApp.ViewModels"
Title="股票工具" Height="300" Width="400">
<Window.DataContext>
<vm:StockViewModel StockName="2303 聯電" Price="45.7" />
</Window.DataContext>
<StackPanel>
<TextBlock Text="{Binding StockName}" FontSize="16"/>
<TextBlock Text="{Binding Price}" FontSize="16"/>
</StackPanel>
</Window>
你也可以只針對某個控制項單獨設定 DataContext
:
<StackPanel>
<TextBlock Text="{Binding StockName}" />
<StackPanel.DataContext>
<vm:StockViewModel StockName="2317 鴻海" Price="103" />
</StackPanel.DataContext>
<TextBlock Text="{Binding Price}" />
</StackPanel>
這種方式只會影響 StackPanel
裡的元素,不會影響整個 Window
。
在 MVVM 架構中,會有兩種設計流程:
DataContext
var window = new MainWindow();
window.DataContext = new StockViewModel();
window.Show();
優點:直覺、快速,適合小專案。
缺點:View 會依賴程式碼建立 ViewModel,耦合度稍高。
var vm = new StockViewModel();
var window = new MainWindow { DataContext = vm };
window.Show();
優點:更符合「View 與 ViewModel 分離」的精神,可以搭配 DI 容器(如 DryIoc、Autofac)。
缺點:初學時需要額外理解 IoC/DI。
在前面介紹 Binding 時,我們都是處理單一屬性。
但是在選股工具裡,股票清單會有很多筆資料,這時就要用 集合 (Collection)。
如果我們用 List,問題是:
加入或刪除元素時,UI 不會自動更新
解決方案是 ObservableCollection。
例子:使用 ObservableCollection
假設我們有一個 ViewModel 管理多檔股票:
using System.Collections.ObjectModel;
public class StockListViewModel
{
public ObservableCollection<StockViewModel> Stocks { get; set; }
public StockListViewModel()
{
Stocks = new ObservableCollection<StockViewModel>
{
new StockViewModel { StockName = "2330 台積電", Price = 1265m },
new StockViewModel { StockName = "2303 聯電", Price = 45.7m },
new StockViewModel { StockName = "2317 鴻海", Price = 103m }
};
}
}
XAML:
<ListBox ItemsSource="{Binding Stocks}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding StockName}" Width="120"/>
<TextBlock Text="{Binding Price}" Width="80"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
後端:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new StockListViewModel();
}
}
效果:
初始時會顯示三檔股票
如果在程式中 Stocks.Add(new StockViewModel { StockName = "2881 富邦金", Price = 63.2m });
→ UI 會自動多一筆「2881 富邦金」
如果用 Stocks.RemoveAt(0);
→ UI 會自動移除第一筆資料
為什麼不是用 List?
因為 ObservableCollection 會在元素增刪時發出通知,WPF UI 會自動刷新。使用List要自行處理UI更新的通知,雖然也是可行但稍微麻煩。
今天我們學會了: