如何在间接使用时动态切换列 header 样式,在每列中使用 BasedOn 继承
How to switch a column header style with another dynamically when they're used indirectly, inherited using BasedOn in each column
我有一个数据网格。我希望设计它的样式,允许用户从一组主题(最初是浅色和深色)中选择 select 一个主题。据我所知,我只能对一个主题执行此操作。
我考虑过在 Resources
中使用 DataGridColumnHeader 样式,通过 DynamicResource 使用它并在 code-behind 中更改它,但在任何 window 出现之前,我得到了这个错误,然后是 2 个类似的错误错误:
System.Windows.Markup.XamlParseException
HResult=0x80131501
Message=A 'DynamicResourceExtension' cannot be set on the 'BasedOn' property of type 'Style'. A 'DynamicResourceExtension' can only be set on a DependencyProperty of a DependencyObject.
Source=PresentationFramework
StackTrace:
at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at wpf_datagrid_themes_1.MainWindow.InitializeComponent() in G:\Lucru\teste\wpf-datagrid-themes-1\wpf-datagrid-themes-1\MainWindow.xaml:line 1
我也试过把这个样式移到里面 DataGrid.ColumnHeaderStyle 但是我不能继承它。
XAML
<Window x:Class="wpf_datagrid_themes_1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:wpf_datagrid_themes_1"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="450">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid x:Name="MyDataGrid">
<DataGrid.Resources>
<Style TargetType="DataGridColumnHeader" x:Key="DataGridColumnHeaderDarkStyle">
<Setter Property="Background" Value="Black"/>
<Setter Property="TextElement.Foreground" Value="White"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Gray"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Column 1" Width="*">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader" BasedOn="{DynamicResource DataGridColumnHeaderDarkStyle}">
<Setter Property="ToolTip" Value="ToolTip for column 1"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Column 2" Width="*">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader" BasedOn="{DynamicResource DataGridColumnHeaderDarkStyle}">
<Setter Property="ToolTip" Value="ToolTip for column 2"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Column 3" Width="*">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader" BasedOn="{DynamicResource DataGridColumnHeaderDarkStyle}">
<Setter Property="ToolTip" Value="ToolTip for column 3"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="1" Click="Button_Click" Margin="10">
CHANGE
</Button>
</Grid>
</Window>
Code-behind
using System.Windows;
using System.Windows.Controls.Primitives;
namespace wpf_datagrid_themes_1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Ideally, this handler should:
//
// if ( the dark style is applied ) : apply the light style
// else : apply the dark style
MyDataGrid.Resources["DataGridColumnHeaderDarkStyle"] =
new Style(typeof(DataGridColumnHeader));
}
}
}
使用 StaticResource 而非 DynamicResource 时的屏幕截图
上面显示的代码和标记不能很好地工作,因为将 BasedOn 与 DynamicResource 一起使用会引发错误。我预计它会起作用,但我必须找到一个解决方法。
我将 .NET Framework 4.7.2 与 VS 2019(撰写本文时的最新稳定版本)和 Windows 10(撰写本文时的最新稳定版本)一起使用。
谢谢。
您应该将 DynamicResource
更改为 StaticResource
:
BasedOn="{StaticResource DataGridColumnHeader}">
...然后使用 DynamicResource
:
设置属性
<Style TargetType="DataGridColumnHeader" x:Key="DataGridColumnHeaderDarkStyle">
<Setter Property="Background" Value="{DynamicResource Background}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource Foreground}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Gray"/>
</Style>
然后定义一个 Dark.xaml
资源字典,在其中定义引用的 Background
和 Foreground
资源为暗资源,并在另一个 Light.xaml
资源字典中定义资源要轻。然后您可以在运行时在这两个资源字典之间切换。
这就是您使用资源实现主题化的方式,即您始终使用相同的 Style
,但此 Style
用于设置元素属性的资源可能会在运行时发生变化。
我有一个数据网格。我希望设计它的样式,允许用户从一组主题(最初是浅色和深色)中选择 select 一个主题。据我所知,我只能对一个主题执行此操作。
我考虑过在 Resources
中使用 DataGridColumnHeader 样式,通过 DynamicResource 使用它并在 code-behind 中更改它,但在任何 window 出现之前,我得到了这个错误,然后是 2 个类似的错误错误:
System.Windows.Markup.XamlParseException
HResult=0x80131501
Message=A 'DynamicResourceExtension' cannot be set on the 'BasedOn' property of type 'Style'. A 'DynamicResourceExtension' can only be set on a DependencyProperty of a DependencyObject.
Source=PresentationFramework
StackTrace:
at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at wpf_datagrid_themes_1.MainWindow.InitializeComponent() in G:\Lucru\teste\wpf-datagrid-themes-1\wpf-datagrid-themes-1\MainWindow.xaml:line 1
我也试过把这个样式移到里面 DataGrid.ColumnHeaderStyle 但是我不能继承它。
XAML
<Window x:Class="wpf_datagrid_themes_1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:wpf_datagrid_themes_1"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="450">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid x:Name="MyDataGrid">
<DataGrid.Resources>
<Style TargetType="DataGridColumnHeader" x:Key="DataGridColumnHeaderDarkStyle">
<Setter Property="Background" Value="Black"/>
<Setter Property="TextElement.Foreground" Value="White"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Gray"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Column 1" Width="*">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader" BasedOn="{DynamicResource DataGridColumnHeaderDarkStyle}">
<Setter Property="ToolTip" Value="ToolTip for column 1"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Column 2" Width="*">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader" BasedOn="{DynamicResource DataGridColumnHeaderDarkStyle}">
<Setter Property="ToolTip" Value="ToolTip for column 2"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Column 3" Width="*">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader" BasedOn="{DynamicResource DataGridColumnHeaderDarkStyle}">
<Setter Property="ToolTip" Value="ToolTip for column 3"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="1" Click="Button_Click" Margin="10">
CHANGE
</Button>
</Grid>
</Window>
Code-behind
using System.Windows;
using System.Windows.Controls.Primitives;
namespace wpf_datagrid_themes_1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// Ideally, this handler should:
//
// if ( the dark style is applied ) : apply the light style
// else : apply the dark style
MyDataGrid.Resources["DataGridColumnHeaderDarkStyle"] =
new Style(typeof(DataGridColumnHeader));
}
}
}
使用 StaticResource 而非 DynamicResource 时的屏幕截图
上面显示的代码和标记不能很好地工作,因为将 BasedOn 与 DynamicResource 一起使用会引发错误。我预计它会起作用,但我必须找到一个解决方法。
我将 .NET Framework 4.7.2 与 VS 2019(撰写本文时的最新稳定版本)和 Windows 10(撰写本文时的最新稳定版本)一起使用。
谢谢。
您应该将 DynamicResource
更改为 StaticResource
:
BasedOn="{StaticResource DataGridColumnHeader}">
...然后使用 DynamicResource
:
<Style TargetType="DataGridColumnHeader" x:Key="DataGridColumnHeaderDarkStyle">
<Setter Property="Background" Value="{DynamicResource Background}"/>
<Setter Property="TextElement.Foreground" Value="{DynamicResource Foreground}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Gray"/>
</Style>
然后定义一个 Dark.xaml
资源字典,在其中定义引用的 Background
和 Foreground
资源为暗资源,并在另一个 Light.xaml
资源字典中定义资源要轻。然后您可以在运行时在这两个资源字典之间切换。
这就是您使用资源实现主题化的方式,即您始终使用相同的 Style
,但此 Style
用于设置元素属性的资源可能会在运行时发生变化。