8

我对 wpf 主题有点困惑。我想让 wpf 屏幕在 Vista、Windows 7 和 Windows 8 上看起来相同。所以我对组件进行了相应的样式设置,除非在 Windows 8 上运行它们不会造成问题。例如,我有一个组合框,我是像这样在 xaml 中更改其默认背景。

<Style TargetType="{x:Type ComboBox}" >
    <Setter Property="FontStyle" Value="Normal"/>
    <Setter Property="Height" Value="24" />
    <Setter Property="Background" Value="{StaticResource GradientButtonBackgroundBrush}"/>
</Style>

组合框背景属性在 Windows 8 中无效,我得到的只是一个右侧带有箭头的平面矩形(默认的 Windows 8 组合框,设计得相当糟糕!)。

所以,我的问题是如何让组合框在所有版本的 Windows 上看起来都一样。我尝试在我的 App.xaml 中添加 windows Aero 主题,如下所示,但它对组合框显示没有影响。这是我添加 Aero 主题的方法

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/PresentationFramework.Aero;component/themes/aero.normalcolor.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>

关于主题还有另一个疑问。我正在 Windows 7 机器上构建 wpf 应用程序,默认情况下(我相信)设置了 Aero Theme。因此,在 Windows 7 机器上查看时,我所有的样式都基于 Aero 主题。如果我在 XP 上运行应用程序会发生什么。那么我是否需要在 App.xaml 中为资源字典(Aero 主题)添加一个条目,如上面代码中列出的那样?

我知道我的问题有点含糊,但相信我,我真的对不同 Windows 版本上 wpf 的默认主题感到困惑。

编辑: 我仍然无法根据我的需要设置组合框样式。组合框仍然看起来像一个灰色矩形。

这就是我所做的。我从微软网站下载了 Aero.NormalColor.xaml 并包含在应用程序的主题文件夹中。然后我在 App.xaml 中添加了以下内容

    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Themes/Aero.NormalColor.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>

然后我编译了应用程序并部署在 Windows 8 上。仍然是之前显示的相同组合框。请注意,所有其他元素都会根据主题正确设置样式。我对 Luna.Metallic.xaml 做了同样的事情,除了ComboBox之外,每个元素都设置了样式。

我相信当我加载一个使用ControlTemplate定义样式的特定主题时,它应该由 wpf 选择。我很困惑为什么即使在给它一个 Aero(或 Luna)控制模板之后只有ComboBox不会改变它的外观。有任何想法吗 ?

EDIT-2 Windows 8 上组合框外观的屏幕截图 在此处输入图像描述

4

5 回答 5

2

那么ComboBox可点击区域实际上是一个ToggleButton

如果您查看 Windows-8 中的Stylefor that ToggleButton,您会看到如下内容:

<ControlTemplate TargetType="{x:Type ToggleButton}">
  <Border x:Name="templateRoot"
          Background="{StaticResource ComboBox.Static.Background}"
          BorderBrush="{StaticResource ComboBox.Static.Border}"
          BorderThickness="{TemplateBinding BorderThickness}"
          SnapsToDevicePixels="true">
...

从上面可以看到,Backgroundused 不是 a {TemplateBinding Background}but {StaticResource ComboBox.Static.Background}。因此,为什么Background在 Windows-8 中为此设置属性时看不到任何效果ComboBox

如果您希望Style使用不同的操作系统版本(无需回溯并继续检查新版本是否搞砸了您的覆盖),简单的规则是自己创建。

创建 aStyle并将其设置为由TargetType和不应用 aKey以自动应用。这样,在任何操作系统中,Style使用的是您的操作系统,而不是默认的底层操作系统。

因此,这可以保证您的代码在每个操作系统上都按预期运行。将您的样式基于任何操作系统的默认设置,并根据您的喜好对其进行调整。

旁注

从可用性 POVComboBox来看,在 Windows-8 上运行的应用程序中为用户提供 Windows-7 并不是很好(除非您的整个应用程序看起来像一个更糟糕的 Windows-7 应用程序)。您希望用户习惯您的应用程序的样式并忘记他在他的操作系统中使用的所有其他应用程序的习惯,这些应用程序使用基于操作系统的默认样式。如果您有这样做的具体原因,请继续,但请考虑其影响。

举个例子,你说 Windows-8 风格是你不喜欢的东西,我正好相反。实际上,我确实喜欢 Windows-8 干净简洁的外观。闪烁的渐变和让您远离您放在他们面前的内容的东西不会分散用户体验。这是一个永远持续下去的争论。在编写程序时,请注意最终用户的期望和想法,而不仅仅是您认为好的。

更新:

请首先评论相关答案。你的回答和你的评论更新没有关系。

好的,至于您的问题编辑,您尝试的内容在 Windows-8 中不起作用,因为 PresentationFramework.Aero.dll在 Windows-8 中不存在,这是什么Aero.NormalColor.xaml。在 Windows-8 中,您的选项PresentationFramework.Aero2.dll是默认选项以及PresentationFramework.AeroLite.dll我认为 Windows Server 2012 使用的选项(不确定)

尝试在 Windows-8 上编译您的程序,您会发现它甚至不想编译。

您必须明确地向您的项目添加对PresentationFramework.Aeroand的引用PresentationUI(我认为它是 .net3 的一部分)。

然后,您必须将您的内容编辑Aero.NormalColor.xaml为:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
                    xmlns:ui="clr-namespace:System.Windows.Documents;assembly=PresentationUI">
...

^^ 我们明确声明了 Aero Theme 的程序集。我不使用 Windows-7,所以我不确定是否只需要这些。但你可以试一试。

尝试在 Windows-8 中编译您的代码,以确保它可以在 Windows-8 上正常工作

于 2013-04-24T10:32:37.827 回答
2

最后,经过几个小时的挫折,我在这里看到了一个解释帖子。滚动查看长答案。它准确地解释了我一直面临的场景,特别是Aero 风格没有应用于我的 Combobox。该链接很好地解释了为什么如果我们不希望选择默认的 OS 样式,我们需要为我们设置样式的每个元素添加BasedOn属性。所以为 Combobox 添加这个 BasedOn 让它对我有用。

<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}">

现在 Aero 主题样式用于组合框。正如@Viv 指出的那样,它可能还需要将 PresentationFramework.Aero.dll 和 PresentationUI.dll复制到 Windows 8 机器,因为它们没有随操作系统提供。

谢谢,尼尔文

于 2013-04-25T15:48:39.367 回答
1

我对内置模板做了一些修改。不是最干净的解决方案,但消除了必须滚动我自己的模板的麻烦。后面的代码基本上将内置模板边框的属性与组合框的属性绑定在一起。

<Style TargetType="ComboBox">
    <Setter Property="Border.Background" Value="White"/>
    <EventSetter Event="Loaded" Handler="ComboBox_Loaded"/>
    <Style.Triggers>
        <Trigger Property="IsReadOnly" Value="True">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
        </Trigger>
        <Trigger Property="IsFocused" Value="True">
            <Setter Property="Background" Value="{StaticResource ResourceKey=FocusedControlBackcolorBrush}"/>
            <Setter Property="BorderBrush" Value="{StaticResource ResourceKey=FocusedControlBorderBrush}"/>
        </Trigger>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="BorderBrush" Value="{StaticResource ResourceKey=FocusedControlBorderBrush}"/>
        </Trigger>
    </Style.Triggers>
</Style>


    private void ComboBox_Loaded(object sender, RoutedEventArgs e)
    {
        var comboBox = sender as ComboBox;
        var toggleButton = comboBox.Template?.FindName("toggleButton", comboBox) as ToggleButton;
        var border = toggleButton?.Template.FindName("templateRoot", toggleButton) as Border;
        if (border != null)
        {
            Binding b = new Binding("Background");
            b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ComboBox), 1);
            BindingOperations.SetBinding(border, Control.BackgroundProperty, b);

            b = new Binding("BorderBrush");
            b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ComboBox), 1);
            BindingOperations.SetBinding(border, Control.BorderBrushProperty, b);
        }
    }
于 2014-10-14T03:17:02.500 回答
0

回应@Viv

@Viv,我觉得您的回答很清楚,但不知何故,您的观点/建议对我来说无法理解,我将简要提及原因

您的建议

如果您希望在不同的操作系统版本中使用样式(无需回溯并继续检查新版本是否搞砸了您的覆盖),简单的规则就是自己创建。

这似乎不切实际。主题的想法是为应用程序中的所有元素创建一致的外观并跨所有平台。所以,如果我使用框架提供的特定主题,无论如何,我应该能够达到令人满意的一致性水平,至少在当前主要平台上是这样。最重要的是,并不是每个人都具备从头开始创建所有样式和模板的专业知识。主题的概念应该是,

“框架提供者正在提供适用于正常场景的主题,如果有人希望推出他的主题,欢迎他这样做”

相反,这里的概念似乎

“框架提供商正在提供主题,但不能保证它会保持一致并且不会中断。所以总是推出你的主题”

您的报价

从上面可以看出,使用的背景不是 {TemplateBinding Background} 而是 {StaticResource ComboBox.Static.Background}。因此,为什么在 Windows-8 中为该 ComboBox 设置 Background 属性时看不到任何效果

我不知道用这种方式制作模板是谁的主意!一定是他疯了,否则我太笨了,无法理解优点。想象一下,我在我的应用程序中使用了一些蓝色主题,明天,在 Windows 9 上,有人将红色定义为{StaticResource ComboBox.Static.Background}。所以,你猜怎么着,我现在有一个漂亮的窗口屏幕,所有元素都以“蓝色”为主题,只有组合框出现“红色”。我的意思是主题的想法在这里被打破了!

你的旁注

举个例子,你说 Windows-8 风格是你不喜欢的东西,我正好相反。实际上,我确实喜欢 Windows-8 干净简洁的外观。

我的组合框看起来像一个禁用的按钮,我什至无法更改它的背景!这些按钮看起来不像是可点击的!当然,正如你所说,这是个人选择。

我的结论 如果有人对我如何让组合框在 Windows 8 上工作有任何建议,我会等待一段时间。你的回答提出了事实,所以如果我没有其他选择,我很乐意将其标记为正确解决方案。

涅槃

于 2013-04-24T11:32:40.923 回答
0

较新的模板有一个 Grid->ToggleButton->Border 带有硬编码的背景颜色,它不尊重任何背景样式。根据@Matstar 的回答,我找到了一种同步背景颜色的方法。

您仍然可以将绑定设置为背景颜色,代码会在需要时选择它并重新应用它:

<ComboBox ItemsSource="{Binding Values}" x:Name="Cbo2"
Background="{Binding Path=SelectedValueBgColor}" ... />

然后在 xaml.cs

cbo.Loaded += (sender, args) =>
{
    var comboBox = sender as ComboBox;
    if (comboBox != null)
    {
        var toggleButton = comboBox.Template?.FindName("toggleButton", comboBox) as ToggleButton;
        var border = toggleButton?.Template.FindName("templateRoot", toggleButton) as Border;
        if (border != null)
        {
            var existing = BindingOperations.GetBinding(comboBox, BackgroundProperty);
            BindingOperations.SetBinding(border, BackgroundProperty, existing);
        }
    }
};

确保您的后台绑定永远不会返回 null

如果您没有有意义的值,则返回透明或白色或其他一些默认值。如果绑定到返回 null 的背景,组合框将停止工作。

如果事件发生时需要刷新,请确保通知后台绑定上的属性已更改。

于 2016-01-27T02:12:14.830 回答