首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WPF 數據綁定進階實戰:模板、分層數據、驗證與自訂顯示

     編輯:關於.NET

WPF 數據綁定:超越基礎的視覺化引擎

WPF 的數據綁定不只是屬性同步,更是一套完整的視覺化管線:資料源 → 綁定引擎 → 模板擴充 → 視覺樹 → 渲染。掌握模板、集合視圖、分層綁定、驗證機制,才能構建專業級企業應用介面。

一、程式碼綁定:動態 UI 的基石

雖然 XAML 聲明式綁定優雅,但動態構建 UI、執行時決定綁定源、條件式綁定等場景需程式碼介入:

// 綁定 TextBox.Text 至資料物件屬性
static void BindText(TextBox textBox, string propertyPath)
{
    var binding = new Binding(propertyPath);
    BindingOperations.SetBinding(textBox, TextBox.TextProperty, binding);
}

// 解除綁定
static void UnbindText(TextBox textBox)
{
    BindingOperations.ClearBinding(textBox, TextBox.TextProperty);
}

// 檢查驗證規則
static bool HasValidationRules(TextBox textBox)
{
    var expr = textBox.GetBindingExpression(TextBox.TextProperty);
    return expr?.ParentBinding.ValidationRules.Any() ?? false;
}

關鍵洞見:BindingExpression 維護源目標連結,Binding 僅為共享配置範本。

二、DataTemplate:賦予資料視覺形態

<ItemsControl ItemsSource="{Binding}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal">
        <TextBlock FontWeight="Bold" Text="{Binding LastName}"/>
        <TextBlock Text=", "/>
        <TextBlock Text="{Binding FirstName}"/>
        <TextBlock Text=" "/>
        <TextBlock Text="{Binding MiddleInitial}"/>
      </StackPanel>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

模板為每個資料項建構視覺樹,支援任意複雜 UI 組合(含 3D、動畫、互動控制項)。

三、DataContext 繼承:簡化巢狀綁定

  • 邏輯樹向下自動繼承 DataContext
  • 父容器設定集合,子控制項綁定 CurrentItem 即可實現主從聯動
  • 類似 WinForms 的 Ambient Properties 概念

四、集合視圖:排序、篩選、分組、同步選取

// 取得預設視圖
var view = CollectionViewSource.GetDefaultView(customers);

// 同步選取:ListBox 需設定 IsSynchronizedWithCurrentItem="True"
view.MoveCurrentTo(selectedCustomer); // 程式碼控制選取
var current = view.CurrentItem as Customer;

// 排序
view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));

// 篩選
view.Filter = obj => obj is Customer c && c.IsActive;

// 分組
view.GroupDescriptions.Add(new PropertyGroupDescription("City"));

五、分層數據綁定:三種實戰模式

模式 1:多控制項分層顯示(XML 數據)

<Grid DataContext="{Binding Source={StaticResource xmlData}, XPath=customers/customer}">
  <!-- 客戶下拉選單 -->
  <ComboBox IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}">
    <ComboBox.ItemTemplate>
      <DataTemplate><TextBlock Text="{Binding XPath=@name}"/></DataTemplate>
    </ComboBox.ItemTemplate>
  </ComboBox>

  <!-- 訂單列表:綁定至當前客戶 -->
  <ListBox x:Name="orders" DataContext="{Binding Path=CurrentItem}" 
           IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding XPath=order}">
    <ListBox.ItemTemplate><DataTemplate><TextBlock Text="{Binding XPath=@desc}"/></DataTemplate></ListBox.ItemTemplate>
  </ListBox>

  <!-- 訂單明細:綁定至當前訂單 -->
  <ItemsControl DataContext="{Binding ElementName=orders, Path=SelectedItem}" 
                ItemsSource="{Binding XPath=orderDetail}">
    ...
  </ItemsControl>
</Grid>

模式 2:多控制項分層顯示(業務物件)

利用 CurrentItem 巢狀路徑,無需 ElementName 綁定:

<ComboBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True"/>  <!-- 客戶 -->
<ListBox ItemsSource="{Binding CurrentItem.Orders}" IsSynchronizedWithCurrentItem="True"/> <!-- 訂單 -->
<ItemsControl ItemsSource="{Binding CurrentItem.Orders.CurrentItem.OrderDetails}"/> <!-- 明細 -->

業務物件覆寫 ToString() 可簡化顯示模板。

模式 3:單一 TreeView 顯示完整階層(HierarchicalDataTemplate)

<Grid.Resources>
  <!-- 明細模板(葉節點) -->
  <DataTemplate x:Key="DetailTemplate">
    <TextBlock><Run Text="Product:"/><TextBlock Text="{Binding Product}"/><Run Text="("/><TextBlock Text="{Binding Quantity}"/><Run Text=")"/></TextBlock>
  </DataTemplate>

  <!-- 訂單模板(中間節點) -->
  <HierarchicalDataTemplate x:Key="OrderTemplate" 
      ItemsSource="{Binding OrderDetails}" ItemTemplate="{StaticResource DetailTemplate}">
    <TextBlock Text="{Binding Desc}"/>
  </HierarchicalDataTemplate>

  <!-- 客戶模板(根節點) -->
  <HierarchicalDataTemplate x:Key="CustomerTemplate" 
      ItemsSource="{Binding Orders}" ItemTemplate="{StaticResource OrderTemplate}">
    <TextBlock Text="{Binding Name}"/>
  </HierarchicalDataTemplate>
</Grid.Resources>

<TreeView ItemsSource="{Binding}" ItemTemplate="{StaticResource CustomerTemplate}"/>

宣告順序重要:葉節點模板 → 中間節點 → 根節點,使用 StaticResource 避免運行時開銷。

六、輸入驗證:從 ExceptionValidationRule 到 IDataErrorInfo

.NET 3.0:ExceptionValidationRule(基礎)

<TextBox.Text>
  <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged">
    <Binding.ValidationRules>
      <ExceptionValidationRule/> <!-- 捕獲轉換例外 -->
    </Binding.ValidationRules>
  </Binding>
</TextBox.Text>

.NET 3.5+:IDataErrorInfo(業務規則驗證)

public class SmartEra : IDataErrorInfo
{
    public DateTime StartDate { get; set; }
    public TimeSpan Duration { get; set; }

    public string Error => null; // 整體錯誤,較少用

    public string this[string propertyName]
    {
        get
        {
            switch (propertyName)
            {
                case "StartDate":
                    if (StartDate > DateTime.Now) return "開始日期不能是未來";
                    break;
                case "Duration":
                    if (Duration == TimeSpan.Zero) return "持續時間必須大於零";
                    break;
            }
            return null; // 無錯誤
        }
    }
}

啟用 IDataErrorInfo 驗證

<TextBox Text="{Binding Path=StartDate, UpdateSourceTrigger=PropertyChanged, 
    ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"/>
<!-- 或明確加入 DataErrorValidationRule -->

自訂錯誤視覺回饋

<Style TargetType="TextBox">
  <Setter Property="Validation.ErrorTemplate">
    <Setter.Value>
      <ControlTemplate>
        <DockPanel>
          <Ellipse DockPanel.Dock="Right" Width="10" Height="10" Fill="Red" 
                   ToolTip="資料無效" Margin="2,0"/>
          <AdornedElementPlaceholder/> <!-- 佔位原控制項 -->
        </DockPanel>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
  <Style.Triggers>
    <Trigger Property="Validation.HasError" Value="True">
      <Setter Property="ToolTip">
        <Setter.Value>
          <Binding Path="(Validation.Errors)[0].ErrorContent" 
                 RelativeSource="{x:Static RelativeSource.Self}"/>
        </Setter.Value>
      </Setter>
    </Trigger>
  </Style.Triggers>
</Style>

七、最佳實務總結

  1. 優先 XAML 聲明式綁定,動態場景才用程式碼
  2. 善用 DataTemplate/HierarchicalDataTemplate 分離資料與視覺
  3. 集合視圖 實現排序/篩選/分組/同步選取,避免手工集合操作
  4. 分層綁定選擇:多控制項適合主從表單,TreeView 適合樹狀導航
  5. 驗譆邏輯歸屬業務物件 (IDataErrorInfo),UI 僅負責呈現錯誤
  6. ErrorTemplate + Style.Trigger 提供一致、友善的錯誤體驗

結語

WPF 數據綁定的強大在於其可組合性:綁定、模板、視圖、驗證、樣式各司其職,透過標準介面無縫協作。深入理解這些機制,能讓開發者用最少代碼表達最豐富的資料視覺化與交互邏輯,真正實現「關注點分離」與「聲明式 UI」的承諾。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved