c# - 样式,模板和ResourceDictionaries

标签 c# wpf templates styles resourcedictionary

我已经做了一些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中支持设计的相同哲学(即,尽可能广泛地定义,在必要时进行专业化处理以避免基本定义中的特殊情况代码)。

(我应该在这里停下来,但是不请自来的建议也附带了一些不请自来的故事讲述……:))

多年以来,我发现自己对大量的API,平台等感到厌恶。但是随着年龄的增长,它们之间的距离越来越少,而且我不得不承认我的许多位置真的是关于我要对我还没有完全理解的事情感到沮丧。是的,也有例外……有时,我的一名咆哮者仍会达到合理的目标。但是我大多数时候发现,学习新的编程环境需要进行态度调整,以寻找驱动该环境设计的思维模式,并重新训练自己以遵循相同的模式,以便我以一种设计师看到了。

不用担心您仍然有机会咆哮。在我编程生涯的早期,我刚刚吸取了教训,那就是如果您的程序无法正常工作,那始终是您程序中的错误,而不是OS中的错误,当时我发现自己为实验计算机编写代码,但仍需要硬件工程师来解决。它几乎每天都保持正常运行。我花了几天的时间来适应这种想法,即我刚刚学到的非常重要的一课需要更改为“几乎总是程序中的错误”。那是几十年前的事,从那以后计算机变得越来越复杂,因此存在更多的编程环境而不是您自己的程序存在缺陷的机会。

但是请不要忘记:与编写系统端的人相比,编写代码的应用程序端的人仍然犯错误是很普遍的。如果没有其他问题,仅像您一样被大量人使用,就可以更好地测试系统端代码。 :)

关于c# - 样式,模板和ResourceDictionaries,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35734912/

相关文章:

Java Double.doubleToLongBits 转换为 C# BitConverter.ToDouble

c# - 为什么 n.GetHashCode() 有效但 n.GetType() 抛出异常?

c# - 更改 toolStripLabel C#.Net 的颜色

c# - 如何从模板重置文本框的属性文本?仅在xaml中

c++ - 为模板参数提供默认参数时,VS 2017 无法正确找到以前定义的类型

c# - 确定文本文件编码架构

c# - ExecuteNonQuery() 语法错误 c#

C# WPF 绑定(bind)不从 Property 获取数据

c++ - 当一个函数接受多个参数时如何组合 2 个函数?

C++ - 不明确的重载模板解析/推导