iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0

在 WinForms 的世界裡,常常需要寫程式碼去「手動更新畫面」,例如:

textBox1.Text = stock.Price.ToString();

但在 WPF,我們可以用 Binding (資料綁定),讓 UI 自動跟 ViewModel 的資料保持同步。
這不只讓程式碼更乾淨,也是 MVVM 架構的核心。


Binding 是什麼?

簡單來說:
Binding = View 與 ViewModel 的資料連線

在 XAML 中,我們可以把控制項屬性綁定到 ViewModel 的屬性:

<TextBlock Text="{Binding StockName}" />

這表示:

  • TextBlock.Text 會顯示 ViewModel 裡的 StockName 屬性值。
  • 如果 StockName 改變,UI 也會跟著更新(前提是 ViewModel 有實作通知機制,稍後會介紹)。

Binding 的模式

Binding 定義了資料同步的方向,主要有 4 種模式:

1) OneTime

只在第一次載入時綁定,之後不會再更新。

<TextBlock Text="{Binding StockName, Mode=OneTime}" />

2) OneWay

ViewModel → View(單向)。資料來源改變,UI 會更新;UI 改變不會回傳。

<TextBlock Text="{Binding Price, Mode=OneWay}" />

3) TwoWay

ViewModel ↔ View(雙向)。

  • ViewModel 改變 → UI 更新
  • UI 改變 → ViewModel 更新
<TextBox Text="{Binding TargetPrice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

4) OneWayToSource

View → ViewModel(單向)。很少用,但可以監聽 UI 狀態。

<TextBox Text="{Binding UserInput, Mode=OneWayToSource}" />

如何讓 ViewModel 的屬性改變時,View 自動更新?

關鍵在於:INotifyPropertyChanged

假設我們有一個 ViewModel:

using System.ComponentModel;

public class StockViewModel : INotifyPropertyChanged
{
    private string _stockName;
    private decimal _price;

    public string StockName
    {
        get { return _stockName; }
        set
        {
            _stockName = value;
            OnPropertyChanged(nameof(StockName));
        }
    }

    public decimal Price
    {
        get { return _price; }
        set
        {
            _price = value;
            OnPropertyChanged(nameof(Price));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

這樣當 ViewModel 的屬性變更時,會觸發通知,WPF UI 就會自動刷新。


如何讓 View 的改變影響到 ViewModel?

這時候就要用 TwoWay Binding

<TextBox Text="{Binding Price, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

這表示:

  • 如果 StockViewModel.Price 改變,TextBox 顯示會更新。
  • 如果使用者在 TextBox 輸入新的數字,StockViewModel.Price 也會同步更新。

綜合範例

XAML:

<StackPanel>
    <TextBox Text="{Binding StockName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    <TextBox Text="{Binding Price, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    <TextBlock Text="{Binding StockName}" FontSize="16"/>
    <TextBlock Text="{Binding Price}" FontSize="16"/>
</StackPanel>

ViewModel:

public class StockViewModel : INotifyPropertyChanged
{
    private string _stockName = "2330 台積電";
    private decimal _price = 1265m;

    public string StockName
    {
        get { return _stockName; }
        set
        {
            _stockName = value;
            OnPropertyChanged(nameof(StockName));
        }
    }

    public decimal Price
    {
        get { return _price; }
        set
        {
            _price = value;
            OnPropertyChanged(nameof(Price));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

結果:

  1. 啟動程式時,TextBox 會顯示「2330 台積電」與「1265」。
  2. 改變 ViewModel 的 Price,TextBox 與 TextBlock 會自動更新。
  3. 使用者輸入新的數值,ViewModel 的屬性也會改變。

小結

今天我們學會了:

  • WPF Binding 的 4 種模式
  • ViewModel → View 更新,需要實作 INotifyPropertyChanged
  • View → ViewModel 更新,需要 TwoWay Binding
  • Binding 可以讓 UI 與程式邏輯解耦,避免手動更新畫面


上一篇
Day 15 - WPF 專案架構簡介
下一篇
Day 17 - WPF Data Binding 進階
系列文
30天快速上手製作WPF選股工具 — 從C#基礎到LiteDB與Web API整合21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言