Window 的 WPF 全局样式

Posted

技术标签:

【中文标题】Window 的 WPF 全局样式【英文标题】:WPF global style for Window 【发布时间】:2019-12-03 11:28:42 【问题描述】:

我正在尝试将全局样式(字体大小和字体系列)添加到我拥有的 Window 的 WPF 应用程序中,但无论我做什么,都没有对其应用样式。我认为我的问题是我的启动窗口不是 App.xaml,因为我使用 App.xaml 只是为了检查用户是否有权运行应用程序。但是在那之后我想要的窗口打开了,所以我的 App.xaml 中的 StartupUri 被设置为那个窗口。

这是我的App.xaml

<Application x:Class="MyApp.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MyApp"
             StartupUri="FirstWindowToShow.xaml">

    <Application.Resources>

        <!--Style that should be applied to all Windows-->
        <Style x:Key="Win_style" TargetType="x:Type Window">
            <Setter Property="FontFamily" Value="Comic Sans MS" />
            <Setter Property="FontSize" Value="14" />
        </Style>

        <!--Style for all Pages - works fine-->
        <Style x:Key="PageFont" TargetType="x:Type Page">
            <Setter Property="FontFamily" Value="Comic Sans MS" />
            <Setter Property="FontSize" Value="12" />
        </Style>

    </Application.Resources>

</Application>

这是我的FirstWindowToShow.xaml

   <Window x:Class="MyApp.FirstWindowToShow"
        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:Priprava_Podatkov"
        mc:Ignorable="d"
        Title="Some title" Height="480" Width="800" Loaded="Window_Loaded" Background="#FFF9F9F9" OpacityMask="Black">

    <Grid>

        <Menu x:Name="G_Menu" HorizontalAlignment="Left" VerticalAlignment="Top" Height="20" Width="792">
            <MenuItem x:Name="Menu_Program">
                <MenuItem x:Name="Menu_V" Header="About" Click="Menu_V_Click"/>
                <MenuItem x:Name="Menu_End" Header="Close" Click="Menu_End_Click"/>
            </MenuItem>
            <MenuItem Header="Department 1" Height="20" Width="148">
                <MenuItem x:Name="Dept_1" Header="Custom controlling" Click="Dept_1_Click"/>
            </MenuItem>
        </Menu>
        <Frame x:Name="Frame_s" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="772" NavigationUIVisibility="Hidden"/>

        <StatusBar DockPanel.Dock="Bottom" Margin="0,386,0,0" VerticalAlignment="Bottom" Background="Transparent">
            <StatusBarItem Width="73">
                <Label Content="User:" FontWeight="Bold" Width="73"/>
            </StatusBarItem>
            <StatusBarItem>
                <Label x:Name="LblU" Content="user" FontWeight="Light"/>
            </StatusBarItem>
            <StatusBarItem>
                <Separator Style="StaticResource x:Static ToolBar.SeparatorStyleKey" Height="10" />
            </StatusBarItem>
            <StatusBarItem>
                <Label Content="User permissions:" FontWeight="Bold" />
            </StatusBarItem>
            <StatusBarItem>
                <Label x:Name="LblN" Content="Rights" FontWeight="Light"/>
            </StatusBarItem>
            <StatusBarItem >

                <Label x:Name="Lbl_P" Content="Data exported..." >
                    <Label.Style>
                        <Style TargetType="x:Type Label">
                            <Style.Resources>
                                <Storyboard x:Key="flashAnimacija">
                                    <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" AutoReverse="True" Duration="0:0:1.5" RepeatBehavior="Forever" />
                                </Storyboard>
                            </Style.Resources>

                            <Setter Property="Visibility" Value="Hidden" />
                            <Style.Triggers>
                                <DataTrigger Binding="Binding ElementName= Progress_DoKonca, Path= IsVisible" Value="True">
                                    <Setter Property="Visibility" Value="Visible" />
                                    <DataTrigger.EnterActions>
                                        <BeginStoryboard Name="flash" Storyboard="StaticResource flashAnimacija" />
                                    </DataTrigger.EnterActions>
                                    <DataTrigger.ExitActions>
                                        <StopStoryboard BeginStoryboardName="flash"/>
                                    </DataTrigger.ExitActions>
                                </DataTrigger>

                            </Style.Triggers>
                        </Style>
                    </Label.Style>
                </Label>
            </StatusBarItem>
            <StatusBarItem HorizontalAlignment="Right" Margin="-10,0,10,0">
                <Grid>
                    <ProgressBar x:Name="Progress_TillEnd" Width="150" Height="20" />
                    <TextBlock x:Name="Progress_Txt" Text="Binding ElementName=Progress_DoKonca, Path=Value, StringFormat=0:0%" HorizontalAlignment="Center" VerticalAlignment="Center" />
                </Grid>
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>

我一直在尝试各种代码或 XAML,例如 this 或 this,但仍然没有成功。我做错了什么?

【问题讨论】:

当您说“未应用样式”时,您现有的控件是否具有默认字体,例如宋体?还是控件文本不可见?您可以从 FirstWindowToShow 中删除 Foreground="x:Null" 并尝试吗? @Insane,我发布了完整的 Window 代码,因为它没有那么长。我一直在尝试删除我想出的所有内容,但所需的字体只是没有显示在 Window 中。我也试过 Foreground="x:Null" 看起来状态栏和菜单给我带来了问题。如果我手动设置他们的样式,一切都很好。 Pages 的奇怪风格可以工作,但我那里没有 StatusBar 或 Menu, 您拥有的每个窗口都不是一个窗口。它是 MainWindow 或 Window1 或其他。因此,您的风格将不针对任何目标。最简单的方法是给样式一个键并在每个窗口中显式引用它。 @Andy,你是什么意思?我的 FirstWindowToShow 继承自 Wind 类。我什至尝试了 【参考方案1】:

这是我过去所做的,所以看看它是否适合你:

在您的 App.xaml 中,从 Window 样式中删除 x:Key,使其变为:

    <!--Style that should be applied to all Windows-->
    <Style TargetType="x:Type Window">
        <Setter Property="FontFamily" Value="Comic Sans MS" />
        <Setter Property="FontSize" Value="14" />
    </Style>

然后在您的 App.xaml.cs(代码隐藏)中,覆盖 OnStartup 方法并添加以下代码:-

    protected override void OnStartup(StartupEventArgs e)
    
        base.OnStartup(e);

        FrameworkElement.StyleProperty.OverrideMetadata(typeof(Window), new FrameworkPropertyMetadata
        
            DefaultValue = FindResource(typeof(Window))
        );
    

这会将 App.xaml Window 样式(即 FontFamily 和 FontStyle)中的这些样式应用到应用程序创建的所有窗口。

【讨论】:

这对我也不起作用。我想我需要重新创建项目,出了点问题。可能所有问题的原因是我创建了一个文件夹“WINDOW”并将两个文件都放在那里 - App.xaml 和 FirstWindowToShow.xaml,WPF 对移动文件非常敏感吗?【参考方案2】:

对于 Menu 和 StatusBar 等控件,需要明确设置样式,如下所示:

<Style  x:Key="BaseStyle" TargetType="x:Type Control">
   <Setter Property="FontFamily" Value="Comic Sans MS" />
   <Setter Property="FontSize" Value="13" />   
</Style>

<Style TargetType="x:Type StatusBar" BasedOn="StaticResource BaseStyle" />        
<Style TargetType="x:Type Menu" BasedOn="StaticResource BaseStyle" />        
<Style TargetType="x:Type local:Window1" BasedOn="StaticResource BaseStyle" />

【讨论】:

这也是我想出来的。但是伙计们说他们的解决方案也有效。所以我必须重新创建项目来确认。 @Lucy,我尝试从头开始创建项目,但这对我不起作用。我希望对你有用! 您的意思是 Andrew 和 mm8 的解决方案? mm8 说这对他有用。 我认为你是对的。我在您之前得出了相同的结论,但我标记了您的答案,感谢您的所有努力。也许即使使用这些控件也有办法做到这一点,但我敢肯定这并不容易:) @Lucy82,我很高兴这个解决方案适合你。以下帖子中还有一些额外的 cmets:https://***.com/questions/59162456/the-ability-to-propagate-default-values-down-the-element-tree-doesnt-work.【参考方案3】:

为什么要将带有“Win_style”的x:KeyStyle 应用于所有窗口?

您可以保留Win_style 并为每个基于Win_style 的窗口类型(例如FirstWindowToShow)定义一个隐含的Style

<Application.Resources>

    <!--Style that should be applied to all Windows-->
    <Style x:Key="Win_style" TargetType="x:Type Window">
        <Setter Property="FontFamily" Value="Comic Sans MS" />
        <Setter Property="FontSize" Value="14" />
    </Style>

    <!-- implicit window styles, one for each window -->
    <Style TargetType="x:Type local:FirstWindowToShow" BasedOn="StaticResource Win_style" />

    <!--Style for all Pages - works fine-->
    <Style x:Key="PageFont" TargetType="x:Type Page">
        <Setter Property="FontFamily" Value="Comic Sans MS" />
        <Setter Property="FontSize" Value="12" />
    </Style>

</Application.Resources>

【讨论】:

是的,确实如此。使用默认模板创建一个新的 WPF 应用程序,将示例标记从答案复制到 App.xaml 并将 FirstWindowToShow 替换为 MainWindow,您会看到它有效。 是的,这将是我的下一步,看起来我的项目有问题,没有解决方案适合我。一定是我过去做过的事情。 确认它甚至在新的 WPF 项目中也不起作用,您没有在我发布的 xaml 标记上尝试它。正确答案是寒鸦发布的。 @Lucy82:你的问题没有提到某些MenuStatusBar,是吗?这确实可以解决将样式应用于窗口的问题。 @Yes 它没有,因为我们不知道这些控件导致了问题。但是我发布了整个 Window 的 xaml,这就是我们想出来的。

以上是关于Window 的 WPF 全局样式的主要内容,如果未能解决你的问题,请参考以下文章

无法覆盖由 TargetType 在单个特定控件上设置的全局 WPF 样式

在WPF应用程序中全局设置文化(en-IN)

WPF 字体设置

WPF:window设置单一开启

微信小程序全局配置

WPF 精修篇 管理资源字典