我对wpf主题有点困惑。我希望Vista,Windows 7和Windows 8上的wpf屏幕看起来一样。所以我相应地设计了组件,除了在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中没有任何效果,我得到的是一个右箭头的扁平矩形(默认的窗口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主题)的条目,如上面的代码中所列?
我知道我的问题有点模糊,但请相信我,我对wpf在不同Windows版本上的默认主题感到困惑。
修改 我仍然无法根据我的需要获得组合框。组合框仍然看起来像一个灰色矩形。
这就是我所做的。我从microsoft的网站下载了Aero.NormalColor.xaml,并将其包含在应用程序的themes文件夹中。然后我在App.xaml中添加了以下内容
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Themes/Aero.NormalColor.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
然后我编译了应用程序并部署在Windows 8上。仍然使用与之前显示的相同的组合框。请注意,所有其他元素都根据主题进行了正确的样式设置。我对Luna.Metallic.xaml做了同样的事情,除了 ComboBox 之外,每个元素都有样式。
我相信当我加载一个用 ControlTemplate 定义样式的特定主题时,它应该被wpf选中。我很困惑为什么只有 ComboBox 即使给它一个Aero(或Luna)控件模板后也不会改变它的外观。有什么想法吗?
修改-2 Windows 8上组合框外观的屏幕截图
答案 0 :(得分:2)
ComboBox
可点击区域实际上是ToggleButton
如果您在Windows-8中查看Style
的{{1}},您会看到以下内容:
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">
...
使用的不是Background
,而是{TemplateBinding Background}
。因此,当您在Windows-8中为{StaticResource ComboBox.Static.Background}
Background
属性时,为什么看不到任何效果?
如果您希望在不同的操作系统版本中携带ComboBox
(无需回溯并继续检查新版本是否搞砸了您的过度使用),简单的规则是创建它自己。
创建Style
并将其设置为由Style
应用,而不会TargetType
自动应用。这种方式在任何操作系统中都是你的Key
被使用而不是默认的底层。
这样可以保证您的代码在每个操作系统上都能正常运行。将你的风格基于任何操作系统的默认设置,并根据你的内心进行调整。
<强>侧注意:
从可用性POV中为用户提供在Windows-8上运行的应用程序中的Windows-7 Style
并不是很好(除非您的整个应用程序看起来像Windows-7应用程序甚至更糟)。您希望用户习惯您的应用程序的样式,并忘记他在其操作系统中使用的每个其他应用程序中使用的内容,这些应用程序使用基于操作系统的默认样式。如果您有具体的理由这样做,请继续,但要考虑其影响。
例如,你说Windows-8风格是你不喜欢的东西,我恰恰相反。我实际上喜欢Windows-8干净简洁的外观。用户体验不会分散闪烁的渐变和让你摆脱放在他们面前的内容的东西。这是一个永远存在的争论。请注意最终用户期望和思考的内容,而不仅仅是在编写程序时您认为好的内容。
<强>更新强>
首先请评论相关答案。您的答案和评论更新没有关系。
好的,对于你的问题编辑,你尝试过的东西在windows-8中没有用,因为{8}中不存在ComboBox
,这是PresentationFramework.Aero.dll
。在Windows-8中,您的选项为Aero.NormalColor.xaml
,默认情况下为PresentationFramework.Aero2.dll
,我认为Windows Server 2012使用此选项(不确定)
尝试在Windows-8上编译程序,你会发现它甚至不想编译。
您必须明确地向您的项目添加对PresentationFramework.AeroLite.dll
和PresentationFramework.Aero
(我认为是.net3的一部分)的引用。
然后,您必须将PresentationUI
修改为:
Aero.NormalColor.xaml
^^我们明确说明Aero Theme的程序集。我不使用Windows-7所以我不确定是否只需要这些。但你可以尝试一下。
尝试在Windows-8中编译代码以确保它在Windows-8上正常工作
答案 1 :(得分:2)
最后,经过几个小时的挫折,我来到了here的解释。滚动 LONG ANSWER 。它完全解释了我一直面临的情况,特别是 Aero风格没有应用到我的Combobox 。该链接非常清楚地解释了为什么我们需要为我们设置的每个元素添加 BasedOn 属性,如果我们不希望拾取默认的OS样式。因此,为Combobox添加这个BasedOn让它适合我。
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}">
现在,Aero主题样式用于组合框。正如@Viv指出的那样,它可能还需要将 PresentationFramework.Aero.dll和PresentationUI.dll 复制到Windows 8计算机,因为它们不随操作系统提供。
谢谢, NIRVAN
答案 2 :(得分: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);
}
}
答案 3 :(得分:0)
响应@Viv
@Viv,我觉得你的回答很清楚,但不知怎的,你的观点/建议对我来说都不可消化,我会简要提一下为什么你的建议
如果您希望在不同的操作系统版本中使用Style(无需回溯并继续检查新版本是否搞砸了您的过度使用),简单的规则就是自己创建。
似乎不切实际。主题的概念是为应用程序中的所有元素和所有平台创建一致的外观。因此,如果我使用框架提供的特定主题,无论如何,我应该能够达到令人满意的一致性水平,至少在当前主流平台上。最重要的是,并非每个人都具备从头开始创建所有样式和模板的专业知识。主题的概念应该是,
“框架提供商正在提供适用于正常场景的主题,如果有人希望推出他的主题,欢迎他们这样做”。
相反,这里的概念似乎是
“框架提供商正在提供主题,并且不保证它会保持一致并且不会中断。所以总是推出您的主题”
您的引用
从上面可以看出,使用的Background不是{TemplateBinding Background}而是{StaticResource ComboBox.Static.Background}。因此,当您在Windows-8中为该ComboBox
设置Background属性时,为什么看不到任何效果
我不知道以哪种方式制作模板的想法!一定是出于他的想法,或者我太愚蠢无法理解其优点。想象一下,我在我的应用程序中使用了一些 Blue 彩色主题,明天,在Windows 9上,有人将 Red 定义为 {StaticResource ComboBox.Static.Background} 即可。所以,猜猜看,我现在有一个花哨的窗口屏幕,所有元素都以“Blue”为主题,只有组合框出现“Red”。我的意思是主题的想法在这里打破了!
你的旁注
例如,你说Windows-8风格是你不喜欢的东西,我恰恰相反。我实际上喜欢Windows-8干净简洁的外观。
我的组合框看起来像一个禁用按钮,我甚至无法改变它的背景!按钮看起来不像是可点击的!如你所说,这是个人选择,当然。
我的结论 我会等一段时间,如果有人对如何让组合框在Windows 8上工作有任何建议。你的答案提出了真相,所以如果我没有得到任何替代解决方案,我很乐意将其标记为正确。
NIRVAN
答案 4 :(得分:0)
较新的模板有一个Grid-&gt; ToggleButton-&gt;边框,其背景颜色为硬编码,不考虑任何背景样式。基于@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的背景,则组合框将停止工作。
如果在事件发生时需要刷新,请确保通知后台绑定中已更改的属性。