WPF DataGrid 與 WinForms DataGridView 架構迥異:資料列為 DataGridRow,儲存格被封裝在 DataGridCellsPresenter 內,無法直接透過 Rows[i].Cells[j] 存取。本文示範如何透過 VisualTreeHelper 走訪視覺樹取得 DataGridCell,並詳解 IValueConverter 實現綁定資料格式化 (如路徑只顯示檔名)。
DataGridRow rowContainer = (DataGridRow)dataGrid1.ItemContainerGenerator.ContainerFromIndex(rowIndex); DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer); DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex); // 取得 cell.Content 或進一步操作
public static T GetVisualChild<T>(Visual parent) where T : Visual {
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++) {
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null) child = GetVisualChild<T>(v);
else break;
}
return child;
}
當資料來源屬性格式與顯示需求不符 (如完整路徑只想顯示檔名),實作 IValueConverter 在綁定管線中轉換。
using System;
using System.Globalization;
using System.IO;
using System.Windows.Data;
class GetFileName : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
FileInfo fi = new FileInfo((string)value);
return fi.Name; // 僅回傳檔名
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException(); // 單向綁定無需實作
}
}
xmlns:local="clr-namespace:YourNamespace"<local:GetFileName x:Key="GetFileName"/><TextBlock Text="{Binding Path=FileName, Converter={StaticResource GetFileName}}" />
<!-- 或完整語法 -->
<TextBlock>
<TextBlock.Text>
<Binding Path="FileName">
<Binding.Converter><local:GetFileName/></Binding.Converter>
</Binding>
</TextBlock.Text>
</TextBlock>
VisualTreeHelper 走訪有開銷,大量資料時勿頻繁呼叫。虛擬化面板 (VirtualizingPanel) 下未實體化的列無法取得 Container。掌握 VisualTreeHelper 走訪技巧可解決特殊需求 (如儲存格級別的焦點管理、自訂編輯器定位),但日常開發應優先使用 IValueConverter 在綁定層處理格式化,符合 WPF 宣告式程式設計精髓。