補充範例及優化程式碼,進一步將XAML上關於欄位(DataGridTextColumn)的描述收攏到C#端的程式碼內

//將log加入AppLog動態資料集(_appLogCollection),顯示在DataGrid上
void AppendLog(LogLevel level, string msg, [CallerLineNumber] int lineNumber = 0, [CallerMemberName] string memberName = "")
{
AppLog log = new AppLog()
{
Level = level.Name.ToUpper(),
ThreadID = Thread.CurrentThread.ManagedThreadId,
Message = msg,
CallerLineNumber = lineNumber,
CallerMemberName = memberName,
};
_appLogCollection.Add(log);
}
另外,資料結構內有實作OnPropertyChanged/OnPropertiesChanged的欄位,當資料有變更時,UI顯示上也會跟著變更
程式碼端優化:
XAML優化前:
<TabItem Header="AppLog">
<Grid Background="#FFE5E5E5">
<DataGrid x:Name="DataGridAppLog" Margin="0" AutoGenerateColumns="False" CanUserAddRows="False" SelectionMode="Extended" SelectionUnit="Cell" IsSynchronizedWithCurrentItem="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding CreatedTime}"/>
<DataGridTextColumn Binding="{Binding Level}"/>
<DataGridTextColumn Binding="{Binding ThreadID}"/>
<DataGridTextColumn Binding="{Binding CallerLineNumber}"/>
<DataGridTextColumn Binding="{Binding CallerMemberName}"/>
<DataGridTextColumn Binding="{Binding Message}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</TabItem>
XAML優化後:
<TabItem Header="AppLog">
<Grid Background="#FFE5E5E5">
<DataGrid x:Name="DataGridAppLog" Margin="0" AutoGenerateColumns="False" CanUserAddRows="False" SelectionMode="Extended" SelectionUnit="Cell" IsSynchronizedWithCurrentItem="True"/>
</Grid>
</TabItem>
C#優化前:
//根據欄位特性(ColumnAttribute),為DataGrid的欄位(DataGridTextColumn)建立初始設定
static void SetHeadersByBindings<T>(this DataGrid obj, IDictionary<string, T> propertyNameMap) where T : ColumnAttribute
{
foreach (DataGridColumn column in obj.Columns)
{
if (column is DataGridBoundColumn bound && bound.Binding is Binding bind)
{
if (propertyNameMap.TryGetValue(bind.Path.Path, out T attr))
{
column.Header = attr.WPFName;
column.DisplayIndex = attr.WPFDisplayIndex;
bind.StringFormat = attr.WPFStringFormat;
column.IsReadOnly = attr.WPFIsReadOnly;
column.Visibility = attr.WPFVisibility.ToString().ConvertTo<Visibility>();
column.CanUserReorder = attr.WPFCanUserReorder;
column.CanUserSort = attr.WPFCanUserSort;
//https://stackoverflow.com/questions/4577944/how-to-resize-wpf-datagrid-to-fit-its-content
column.Width = new DataGridLength(1.0, DataGridLengthUnitType.Auto);
Style headerS = new Style(typeof(DataGridColumnHeader));
headerS.Setters.Add(new Setter(ToolTipService.ToolTipProperty, $"{column.DisplayIndex},{attr.CSVName},{bind.Path.Path},{bind.StringFormat}"));
column.HeaderStyle = headerS;
//https://stackoverflow.com/questions/53961533/datagrid-columns-element-style-in-codebehind-has-no-effect
if (column is DataGridTextColumn col)
{
Style elementS = null;
if (attr.WPFHorizontalAlignment != WPFHorizontalAlignment.Left)
{
elementS = new Style();
elementS.Setters.Add(new Setter(FrameworkElement.HorizontalAlignmentProperty, attr.WPFHorizontalAlignment.ToString().ConvertTo<HorizontalAlignment>()));
}
if (!string.IsNullOrWhiteSpace(attr.WPFForeground))
{
if (elementS == null)
{
elementS = new Style();
}
elementS.Setters.Add(new Setter(TextBlock.FontWeightProperty, FontWeights.DemiBold));
elementS.Setters.Add(new Setter(TextBlock.ForegroundProperty, new BrushConverter().ConvertFromString(attr.WPFForeground)));
}
if (elementS != null)
{
col.ElementStyle = elementS;
}
}
}
}
}
}
C#優化後(SetHeadersByBindings更名為SetColumns):
private static void SetColumn<T>(this DataGridBoundColumn obj, Binding bind, T attr) where T : ColumnAttribute
{
obj.Header = attr.WPFName;
obj.DisplayIndex = attr.WPFDisplayIndex;
bind.StringFormat = attr.WPFStringFormat;
obj.IsReadOnly = attr.WPFIsReadOnly;
obj.Visibility = attr.WPFVisibility.ToString().ConvertTo<Visibility>();
obj.CanUserReorder = attr.WPFCanUserReorder;
obj.CanUserSort = attr.WPFCanUserSort;
//https://stackoverflow.com/questions/4577944/how-to-resize-wpf-datagrid-to-fit-its-content
obj.Width = new DataGridLength(1.0, DataGridLengthUnitType.Auto);
//https://stackoverflow.com/questions/4615081/how-to-add-a-tooltip-for-a-datagrid-header-where-the-header-text-is-generated-d
Style headerS = new Style(typeof(DataGridColumnHeader));
headerS.Setters.Add(new Setter(ToolTipService.ToolTipProperty, $"{obj.DisplayIndex},{attr.CSVName},{bind.Path.Path},{bind.StringFormat}"));
obj.HeaderStyle = headerS;
//https://stackoverflow.com/questions/53961533/datagrid-columns-element-style-in-codebehind-has-no-effect
if (obj is DataGridTextColumn col)
{
Style elementS = null;
if (attr.WPFHorizontalAlignment != WPFHorizontalAlignment.Left)
{
elementS = new Style();
elementS.Setters.Add(new Setter(FrameworkElement.HorizontalAlignmentProperty, attr.WPFHorizontalAlignment.ToString().ConvertTo<HorizontalAlignment>()));
}
if (!string.IsNullOrWhiteSpace(attr.WPFForeground))
{
if (elementS == null)
{
elementS = new Style();
}
elementS.Setters.Add(new Setter(TextBlock.FontWeightProperty, FontWeights.DemiBold));
elementS.Setters.Add(new Setter(TextBlock.ForegroundProperty, new BrushConverter().ConvertFromString(attr.WPFForeground)));
}
if (elementS != null)
{
col.ElementStyle = elementS;
}
}
}
public static void SetColumn<T>(this DataGridBoundColumn obj, T attr) where T : ColumnAttribute
{
if (obj.Binding is Binding bind)
{
obj.SetColumn(bind, attr);
}
}
public static void SetColumns<T>(this DataGrid obj, IDictionary<string, T> propertyNameMap) where T : ColumnAttribute
{
HashSet<string> existedBindings = new HashSet<string>();
foreach (DataGridColumn column in obj.Columns)
{
if (column is DataGridBoundColumn bound && bound.Binding is Binding bind && propertyNameMap.ContainsKey(bind.Path.Path))
{
existedBindings.Add(bind.Path.Path);
}
}
foreach (KeyValuePair<string, T> pair in propertyNameMap)
{
if (pair.Value.WPFDisplayIndex < 0 || existedBindings.Contains(pair.Key))
{
continue;
}
//https://stackoverflow.com/questions/6885711/wpf-c-bind-datagrid-column-with-code-behind
DataGridTextColumn column = new DataGridTextColumn()
{
Binding = new Binding(pair.Key),
};
obj.Columns.Add(column);
}
foreach (DataGridColumn column in obj.Columns)
{
if (column is DataGridBoundColumn bound && bound.Binding is Binding bind && propertyNameMap.TryGetValue(bind.Path.Path, out T attr))
{
bound.SetColumn(bind, attr);
}
}
}
請先 登入 以發表留言。