我已经做了一些WPF项目一段时间了,但我大部分时间都远离模板和资源字典,因为它们是一个集群#。为了达到下一个水平,我在谷歌上搜索了很多,试图找到使用资源字典等应用样式的最佳实践,但似乎最佳实践是基于习惯和偏好的。我遇到的大多数例子要么假设你已经知道了一切,要么不包括所有不同的情况。最糟糕的是,有一些已知的错误和情况会影响性能,但了解这些问题是什么并纠正它们本身就是另一个麻烦。
抱歉你的咆哮。以下是我需要解决的情况:
假设我有一个默认的rd(资源字典),它具有针对文本块、按钮、文本框等的样式。然后,我有另一个类似的资源字典,它适用于类似Expander(或TabItem)的东西,它是这些相同控件(按钮、文本盒…)的集合。
-
这样的设置可以吗?
-
如何覆盖位于特定扩展器内的控件的默认rd?我尝试在扩展器的资源中添加对资源字典的引用;然而,默认的rd似乎覆盖了该样式。
-
模板的用途是什么?你什么时候会使用这些模板?
这是我当前的设置:
App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/rdMainStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
rdMainStyle.xaml:
<Style x:Key="baseStyle" TargetType="FrameworkElement">
<Setter Property="Width" Value="Auto"/>
<Setter Property="Height" Value="Auto"/>
<Setter Property="MinWidth" Value="70pt"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource baseStyle}">
<Setter Property="Margin" Value="5, 0, 0, 5"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource baseStyle}">
<Setter Property="MinWidth" Value="65pt"/>
<Setter Property="Margin" Value="5, 0, 0, 5"/>
</Style>
rdExpanderStyle.xaml:
<Style x:Key="expanderBaseStyle" TargetType="FrameworkElement">
<Setter Property="Height" Value="Auto"/>
<Setter Property="Margin" Value="5, 0, 0, 5"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource expanderBaseStyle}">
<Setter Property="Width" Value="70pt"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource expanderBaseStyle}">
<Setter Property="Width" Value="65pt"/>
</Style>
主窗口内:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Expander Grid.Row="0" Name="expSync" Header="More Options">
<Expander.Resources>
<ResourceDictionary Source="Resources/rdExpanderStyle.xaml" />
</Expander.Resources>
</Expander>
<StackPanel Margin="0,5,0,0">
<TextBlock Text="bluh"/>
<Button Content="Test" />
</StackPanel>
</Grid>
- 这样的设置可以吗
是的,很好。事实上,样式/模板/主题等。在WPF中都是关于这种层次结构的。也就是说,可以在一个地方定义默认值,但随后用优先级更高的新定义覆盖它。
- 如何覆盖位于特定扩展器内的控件的默认rd?我尝试在扩展器的资源中添加对资源字典的引用;然而,默认的rd似乎覆盖了该样式
问题与Expander.Header
属性的内容是简单的string
这一事实有关。这将被映射到ContentPresenter
类的自定义样式(其本身是Expander
类自定义样式的一部分),因此在尝试使用本地声明的样式设置样式时会被忽略。您稍后试图覆盖样式的操作实际上在样式层次结构中太靠后了。全局样式之所以有效,是因为该样式的应用时间早于控件所使用的自定义样式。
您可以通过为Expander
控件的内容提供更明确的定义来解决此问题。例如:
<Expander Grid.Row="0" Name="expSync">
<Expander.Resources>
<ResourceDictionary Source="Resources/rdExpanderStyle.xaml" />
</Expander.Resources>
<Expander.Header>
<TextBlock Text="More Options"/>
</Expander.Header>
</Expander>
通过显式地提供TextBlock
作为内容,您最终会得到一个控件实例,该控件实例在从rdExpanderStyle.xaml
文件导入的样式之后出现,并且它们将根据您的需要进行应用。
- 模板的用途是什么?何时使用这些模板
对此的全面讨论超出了合理的堆栈溢出答案的范围。MSDN、Stack Overflow和其他地方提供了大量资源来描述模板在WPF中的使用方式。也就是说…
模板的目的是为控件提供一个模式,以便在实例化时遵循。在某些情况下,您为特定控件声明模板,而在其他情况下,则为"视图模型"数据类型声明模板。前一种情况是关于自定义现有控件类型的外观和行为;后一种情况是以抽象、解耦、可重用的方式将业务逻辑数据结构映射到可视化外观。
你什么时候使用它们?好吧,我想说目的回答了这个问题。如果您需要自定义一个可模板化的控件,您可以使用模板来实现这一点。如果您需要将视图模型对象呈现为控件的组合,则可以使用模板来实现这一点(例如,当视图模型表示ItemsControl
中的项目时)。我想说,视图模型场景比通过模板自定义控件更普遍,但这并不是基于确凿的证据;这只是我对形势的总体感觉。
最后,有一点建议,我无意冒犯:
虽然你的咆哮是可以理解的,但它没有成效,而且更多的是因为你自己缺乏经验,而不是WPF的实际质量。我知道,因为我自己也去过那里。是的,WPF很复杂,很难学习。是的,它确实有很多地方的行为不是立即直观或明显的。
但是:a)WPF中模板和资源的状态甚至不是接近(用你的话说…我相信我得到了预期的含义)"一个集群#">;相反,这些是WPF的基本元素,其设计即使非常复杂,也是合乎逻辑的,并且在正确使用时也能很好地工作,而且b)事实上,在处理样式和资源字典方面存在合理、客观的"最佳实践",在很大程度上基于OOP中支撑设计的相同哲学(即,尽可能广泛地定义,必要时进行专门化,以避免在基本定义中使用特殊情况代码)。
(我本应该到此为止,但主动提出的建议也附带了一些主动提出的故事(hellip;:))
这些年来,我发现自己对很多API、平台等大放厥词。但随着年龄的增长,这些大放厥语越来越少,我不得不承认,我的许多大放厥文实际上是为了发泄我对一些我还不完全理解的事情的沮丧。是的,有例外…偶尔,我的一句咆哮仍然击中了目标。但我发现,学习一个新的编程环境需要态度调整,寻求驱动环境设计的思维模式,并重新培训自己遵循这些模式,这样我才能像设计师一样看待环境
别担心。你仍然有机会咆哮。在我编程生涯的早期,我刚刚学到了一个教训,即如果你的程序不工作,它总是你的程序中的一个错误,而不是操作系统中的错误,当时我发现自己正在为一台实验性计算机编写代码,而这台计算机仍然需要硬件工程师几乎每天都摆弄它来保持它的正确运行。我花了几天时间才学会接受这样一种想法,即我刚刚学到的非常重要的一课需要改为"这几乎是你程序中的一个错误"。那是几十年前的事了,从那时起,计算机变得更加复杂,所以编程环境而不是你自己的程序有更多的机会出现缺陷。
但别忘了:编写代码的应用程序端的人犯错误的情况仍然比编写系统端的人常见得多。如果没有别的,系统端代码的测试效果会更好,只需被大量像你一样的人使用即可。:)