【问题标题】:Set the default Control Template of a Custom Control without using a Style在不使用样式的情况下设置自定义控件的默认控件模板
【发布时间】:2020-02-14 10:20:10
【问题描述】:

我正在寻找一种将自定义控件的默认Control Template 更牢固地绑定到控件的方法,而不是使用Style。我将在这里展示我最简单的示例来解释需求:

    public class UnitTextBox : TextBox
    {
        public string UnitLabel {...}
        public static readonly DependencyProperty UnitLabelProperty =
            DependencyProperty.Register("UnitLabel", typeof(string), typeof(UnitTextBox), new PropertyMetadata(""));
    }

这个控件只是为单位标签(如毫米)添加了一个额外的字符串属性,给定以下从TextBox 派生的简单控件模板,它在文本框中放置了一个单位标签,以保持内容美观、干净和适当的尺寸:

    <ControlTemplate x:Key="UnitTextBoxTemplate" TargetType="{x:Type local:UnitTextBox}">
        <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
            <DockPanel>
                <TextBlock DockPanel.Dock="Right" Text="{TemplateBinding UnitLabel}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="8,0,2,0" Focusable="False" IsHitTestVisible="False" Background="Transparent" Foreground="{TemplateBinding Foreground}"
                            FontSize="{TemplateBinding FontSize}" FontStyle="{TemplateBinding FontStyle}"   />
                <ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
            </DockPanel>
        </Border>
...(triggers)
    </ControlTemplate>

所有这些都非常好,但是这个控件基本上仍然是TextBox,而且我已经有很多我使用的 TextBoxes 样式,所以我不想使用默认样式来应用模板:

    <Style  TargetType="{x:Type local:UnitTextBox}">
        <Setter Property="Template" Value="{DynamicResource UnitTextBoxTemplate}"/>
    </Style>

执行上述操作意味着我不能使用我的RegularTextBox 样式,它适用于我的UnitTextBox。因此,每次我想添加 UnitTextBox 时,我都必须明确指定使其正常运行的模板:

  <ctrl:UnitTextBox Template="{DynamicResource UnitTextBoxTemplate}" UnitLabel="mm/min" 
                    Style="{StaticResource RegularTextBox}"/>

我已经使用 WPF 多年了,但我做的自定义控件相对较少,并且在我这样做时受到了默认样式方法的影响,但我认为那里 必须 更好方式,但是 google-fu 一次又一次地让我失望。

我希望有某种方法可以在UnitTextBox 的构造函数/Init 例程中分配模板,但我正在努力从代码中获取资源字典;所以我想知道是否有更深奥的方法来做到这一点。

【问题讨论】:

  • 您不能简单地将默认样式基于现有样式并设置Template 属性吗? &lt;Style TargetType="{x:Type local:UnitTextBox}" BasedOn="{StaticResource RegularTextBox}"&gt;...&lt;/Style&gt;。这种方法有什么问题?
  • 你可以,但是你必须将你拥有的 TextBox 样式的数量乘以 TextBox 衍生品的数量。由于我还有其他一些类似的案例,因此我预计这会在短期内造成混乱。这是我勉强的解决方案,但似乎应该有一些优雅的东西,对吧?
  • 我不认为我理解这个问题。如果您想要不同于默认样式的其他样式,只需设置该特定元素的 Style 属性。 “我希望有一些方法可以在 UnitTextBox 的构造函数/Init 例程中分配模板”。这有什么帮助?
  • UnitTextBox 控件的核心功能(在 TextBox 中添加 TextBlock)绑定在默认样式中,如果我有 5 种不同的 TextBox 样式,在 UnitTextBox 上使用这些样式可以正常工作,除了它覆盖提供模板的默认样式。所以我必须明确分配模板,或者我必须根据 5 种样式中的每一种创建一个样式,为 Template 添加一个 setter 并使用它。它有效,但很糟糕。在初始化中设置模板意味着如果样式失败,它已经分配了模板。
  • 您可以处理Loaded 并在事件处理程序中设置Template 属性。

标签: .net wpf custom-controls desktop-application


【解决方案1】:

如果您不想定义默认的Style,您可以在控件类中处理Loaded 事件并在事件处理程序中设置Template 属性。

public UnitTextBox() : base()
{
    this.Loaded += UnitTextBox_Loaded;
}

private void UnitTextBox_Loaded(object sender, RoutedEventArgs e)
{
    var res = this.FindResource("UnitTextBoxTemplate");
    this.Template = res as ControlTemplate;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-04
    相关资源
    最近更新 更多