【问题标题】:Using a Button control in a ButtonBase derived template在 ButtonBase 派生模板中使用 Button 控件
【发布时间】:2015-04-20 09:32:16
【问题描述】:

我们的应用程序中的按钮具有特定的外观和感觉,这些按钮在 ButtonBase 的命名样式中定义,这也恰好是 ButtonToggleButtonRepeatButton 的默认样式。

我们还有 ToolbarButtons 派生自 ButtonBase 并包含额外的属性,例如 TextIcon。这些用于在ToolbarButton 上放置特定文本和图标。

ToolbarButtons的主题在Themes/generic.xaml中定义如下:

<Style TargetType="{x:Type c:ToolbarButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type c:ToolbarButton}">
                <Button Command="{TemplateBinding Property=Command}">
                     .. controls to place text and icon etc ..
                </Button>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如您所见,我在基于ButtonBase 的控件中使用Button 控件,并将Command 绑定到包含的Command 上的Button。这个 hack 确保我可以通过定义 Button 默认样式来覆盖 Toolbar 中使用的“按钮”样式。

这一切似乎都很好,但是在Button 中使用Button 感觉不对。我仍然想知道我是否在做正确的事情。有什么想法吗?

【问题讨论】:

  • 确实,我不认为在另一个按钮内部有一个按钮是正确的。我真的不明白它的目的。您想拥有应用程序的特定按钮样式,并且能够只为您的 ToolbarButton 覆盖一些属性吗?
  • 原因是我现在可以使用 ToolbarButton 样式模板化 ToolbarButton 的内部,同时使用默认按钮样式模板化按钮的镶边。

标签: wpf wpf-controls controltemplate


【解决方案1】:

您的方法很好,但您不必在模板中使用第二个按钮,而是使用ContentPresenter。每次重新定义ContentControl(例如按钮)的模板时都使用它。 BasedOn 属性对于覆盖特定的按钮样式很有用。

看起来像这样:

<Style TargetType="{x:Type c:ToolbarButton}" BasedOn="{StaticResource {x:Type ButtonBase}}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ToolbarButton}">

                <StackPanel>

                    <!-- Image -->
                    <Image Source="{TemplateBinding Image}"/>

                    <!-- Content -->
                    <ContentPresenter Content="{TemplateBinding Content}"/>
                </StackPanel>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

您会发现ItemsControlListBoxListView 等)的模板与ItemsPresenter 的机制相同。

更新:

要考虑您的评论,也许您应该覆盖 ContentControl 以将您的特定 chrome 应用到它:

公共类 ButtonContentControl : ContentControl { }

<Style TargetType="{x:Type local:ButtonContentControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ButtonContentControl}">

                <!-- Specific chrome -->

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

然后您可以在 ButtonBase 和 ToolbarButton 的模板中使用它:

Style TargetType="{x:Type ButtonBase}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type c:ToolbarButton}">
                <ButtonContentControl>
                     <!-- ContentPresenter or something else -->
                </ButtonContentControl>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="{x:Type c:ToolbarButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type c:ToolbarButton}">
                <ButtonContentControl>
                     .. controls to place text and icon etc ..
                </ButtonContentControl>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【讨论】:

  • 这不起作用,通过覆盖模板您覆盖了ButtonBaseStyle 的模板。此外,ContentPresenter 不呈现镶边,它只呈现 ToolbarButton.Content 属性中的内容。 (我们不使用)。
  • 好的,确实很复杂。你不认为你应该重写一个 ContentControl(例如 ButtonContentControl),在它的模板中使用你的特定样式,然后在你的 ButtonBase 的模板和你的 ToolbarButton 的模板中使用这个 ContentControl 吗?
  • 我看不到任何好处,Button 本身已经是ContentControl,现在您将按钮包装成按钮。可能更适用的是创建一个 ButtonChrome 自定义组件,但我不确定如何传播 VisualStateManager 状态。
  • 我没有将按钮包装在按钮中,而是在两个按钮模板中包装了一个简单的 ContentControl。这是一种将 chrome 集中在一个模板中的方法。但是如果你使用 VisualStateManager 它将不起作用。如果你创建一个 ButtonChrome,我想你会遇到和以前一样的问题。抱歉没有帮到你……
  • 这与 WPF 中用于某些默认控件的解决方案相同:Microsoft.Windows.Themes.ButtonChrome
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-17
  • 2015-04-10
  • 1970-01-01
相关资源
最近更新 更多