WPF: 将数据参数传递到样式主题中?

huangapple go评论57阅读模式
英文:

WPF: Passing a data parameter into a style theme?

问题

我有一个样式,我在多个文本框中重复使用。在样式中,我定义了一个控件模板,而在控件模板内部,我有一些触发器。我想要能够从视图中将数据属性传递到其中一个触发器中。

以下是我当前在资源字典中定义的样式的简化版本:

<Style x:Key="TextBoxTheme" TargetType="{x:Type TextBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <Border x:Name="border">
                    <ScrollViewer x:Name="PART_ContentHost" Focusable="false"/>
                </Border>
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding PARAMETER}" Value="true">
                        <Setter Property="BorderBrush" TargetName="border" Value="Red"/>
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

有一个DataTrigger "(Binding PARAMETER}”,它将确定边框是否设置为红色。根据我在文本框中使用的位置,我想将其绑定到不同的变量。

我想能够从我的视图中将其作为参数传递。我想象中的实现方式如下(这只是我认为应该工作的一种方式的想法,但实际上不起作用):

<TextBox Style="{StaticResource TextBoxTheme, Parameter={Binding PARAMETER}}"/>
<TextBox Style="{StaticResource TextBoxTheme, Parameter={Binding DIFFERENT_PARAMETER}}"/>

由于我还无法弄清楚如何做到这一点,每次调用它时,我几乎都在重新编写相同的代码。

示例(在我的'Name'文本框中使用此样式):

<TextBox Text="{Binding Name}">
    <TextBox.Style>
        <Style TargetType="TextBox" BasedOn="{StaticResource TextBoxTheme}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TextBox}">
                        <Border x:Name="border">
                            <ScrollViewer x:Name="PART_ContentHost" Focusable="false"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <DataTrigger Binding="{Binding DuplicateName}" Value="False">
                                <Setter Property="BorderBrush" TargetName="border" Value="Green"/>
                            </DataTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TextBox.Style>
</TextBox>

示例(当我希望在不同的绑定中使用相同样式时):

<TextBox Text="{Binding IpAddress}">
    <TextBox.Style>
        <Style TargetType="TextBox" BasedOn="{StaticResource TextBoxTheme}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TextBox}">
                        <Border x:Name="border">
                            <ScrollViewer x:Name="PART_ContentHost" Focusable="false"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <DataTrigger Binding="{Binding DuplicateIP}" Value="False">
                                <Setter Property="BorderBrush" TargetName="border" Value="Green"/>
                            </DataTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TextBox.Style>
</TextBox>

有没有更好的方法来做到这一点?我找到了一篇文章,其中显示了如何将属性传递给样式(https://thomaslevesque.com/2011/10/01/wpf-creating-parameterized-styles-with-attached-properties/),但我没有看到如何将数据属性传递进去的示例。

英文:

I have a style that I re-use for multiple textboxes. Within the style, I define a control template - and within that control template, I have some triggers. I want to be able to pass a Data Property into one of those triggers from the View.

Here is a shortened version of my current style defined in a Resource Dictionary:

&lt;Style x:Key=&quot;TextBoxTheme&quot; TargetType=&quot;{x:Type TextBox}&quot;&gt;
    &lt;Setter Property=&quot;Template&quot;&gt;
        &lt;Setter.Value&gt;
            &lt;ControlTemplate TargetType=&quot;{x:Type TextBox}&quot;&gt;
                &lt;Border x:Name=&quot;border&quot;&gt;
                    &lt;ScrollViewer x:Name=&quot;PART_ContentHost&quot; Focusable=&quot;false/&gt;
                &lt;/Border&gt;
                &lt;ControlTemplate.Triggers&gt;
                    &lt;DataTrigger Binding=&quot;{Binding PARAMETER}&quot; Value=&quot;true&quot;&gt;
                        &lt;Setter Property=&quot;BorderBrush&quot; TargetName=&quot;border&quot; Value=&quot;Red&quot;/&gt;
                    &lt;/DataTrigger&gt;
                &lt;/ControlTemplate.Triggers&gt;
            &lt;/ControlTemplate&gt;
        &lt;/Setter.Value&gt;
    &lt;/Setter&gt;
&lt;/Style&gt;

There is one DataTrigger "(Binding PARAMETER}" that will determine if the border is set to red or not. Depending on where I use this textbox, I want to bind that to a different variable.

I want to be able to pass that as a parameter from my View. I'm imagining something like this (just an idea of how I think it should work, but this doesn't work):

&lt;TextBox Style=&quot;{StaticResource TextBoxTheme, Parameter={Binding PARAMETER}}&quot;/&gt;
&lt;TextBox Style=&quot;{StaticResource TextBoxTheme, Parameter={Binding DIFFERENT_PARAMETER}}&quot;/&gt;

Since I can't figure out how to do that yet, I am almost rewriting the same code every time I call it.

Example (Using this style with my 'Name' textbox):

&lt;TextBox Text=&quot;{Binding Name}&quot;&gt;
&lt;TextBox.Style&gt;
    &lt;Style TargetType=&quot;TextBox&quot; BasedOn=&quot;{StaticResource TextBoxTheme}&quot;&gt;
        &lt;Setter Property=&quot;Template&quot;&gt;
            &lt;Setter.Value&gt;
                &lt;ControlTemplate TargetType=&quot;{x:Type TextBox}&quot;&gt;
                    &lt;Border x:Name=&quot;border&quot;&gt;
                        &lt;ScrollViewer x:Name=&quot;PART_ContentHost&quot; Focusable=&quot;false&quot;/&gt;
                    &lt;/Border&gt;
                    &lt;ControlTemplate.Triggers&gt;
                        &lt;DataTrigger Binding=&quot;{Binding DuplicateName}&quot; Value=&quot;False&quot;&gt;
                            &lt;Setter Property=&quot;BorderBrush&quot; TargetName=&quot;border&quot; Value=&quot;Green&quot;/&gt;
                        &lt;/DataTrigger&gt;
                    &lt;/ControlTemplate.Triggers&gt;
                &lt;/ControlTemplate&gt;
            &lt;/Setter.Value&gt;
        &lt;/Setter&gt;
    &lt;/Style&gt;
&lt;/TextBox.Style&gt;

</TextBox>

Example (When I want to use this same style with a different binding):

&lt;TextBox Text=&quot;{Binding IpAddress}&quot;&gt;
&lt;TextBox.Style&gt;
    &lt;Style TargetType=&quot;TextBox&quot; BasedOn=&quot;{StaticResource TextBoxTheme}&quot;&gt;
        &lt;Setter Property=&quot;Template&quot;&gt;
            &lt;Setter.Value&gt;
                &lt;ControlTemplate TargetType=&quot;{x:Type TextBox}&quot;&gt;
                    &lt;Border x:Name=&quot;border&quot;&gt;
                        &lt;ScrollViewer x:Name=&quot;PART_ContentHost&quot; Focusable=&quot;false&quot;/&gt;
                    &lt;/Border&gt;
                    &lt;ControlTemplate.Triggers&gt;
                        &lt;DataTrigger Binding=&quot;{Binding DuplicateIP}&quot; Value=&quot;False&quot;&gt;
                            &lt;Setter Property=&quot;BorderBrush&quot; TargetName=&quot;border&quot; Value=&quot;Green&quot;/&gt;
                        &lt;/DataTrigger&gt;
                    &lt;/ControlTemplate.Triggers&gt;
                &lt;/ControlTemplate&gt;
            &lt;/Setter.Value&gt;
        &lt;/Setter&gt;
    &lt;/Style&gt;
&lt;/TextBox.Style&gt;

</TextBox>

Is there a better way of doing this? I found an article that shows you how to pass a property into a style (https://thomaslevesque.com/2011/10/01/wpf-creating-parameterized-styles-with-attached-properties/) but I don't see it working with passing a data property.

答案1

得分: 1

一般来说,对于重用现有样式,Style.Triggers 要优于 ControlTemplate.Triggers,因为 Style.Triggers 可以在派生的样式中定义。

一个简单的基础样式可能如下:

<Style x:Key="TextBoxTheme" TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
    <Setter Property="BorderThickness" Value="2"/>
</Style>

然后,您可以定义两个不同 Style.Triggers 的派生样式。

<Style x:Key="TextBoxTheme1" TargetType="{x:Type TextBox}" BasedOn="{StaticResource TextBoxTheme}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding PARAMETER}" Value="True">
            <Setter Property="BorderBrush" Value="Red"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

<Style x:Key="TextBoxTheme2" TargetType="{x:Type TextBox}" BasedOn="{StaticResource TextBoxTheme}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding DuplicateName}" Value="False">
            <Setter Property="BorderBrush" Value="Green"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

或者,如果您想为每个 TextBox 指定 Style.Triggers,可以更容易地在每个 TextBox 内定义一个样式。

<TextBox Text="example">
    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource TextBoxTheme}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding DuplicateIP}" Value="False">
                    <Setter Property="BorderBrush" Value="Green"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>
英文:

In general, for reusing an existing Style, Style.Triggers are better than ControlTemplate.Triggers because Style.Triggers can be defined at an derived Style.

A simple base Style would be like:

&lt;Style x:Key=&quot;TextBoxTheme&quot; TargetType=&quot;{x:Type TextBox}&quot; BasedOn=&quot;{StaticResource {x:Type TextBox}}&quot;&gt;
    &lt;Setter Property=&quot;BorderThickness&quot; Value=&quot;2&quot;/&gt;
&lt;/Style&gt;

Then you can define two derived Styles of different Style.Triggers.

&lt;Style x:Key=&quot;TextBoxTheme1&quot; TargetType=&quot;{x:Type TextBox}&quot; BasedOn=&quot;{StaticResource TextBoxTheme}&quot;&gt;
    &lt;Style.Triggers&gt;
        &lt;DataTrigger Binding=&quot;{Binding PARAMETER}&quot; Value=&quot;True&quot;&gt;
            &lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;Red&quot;/&gt;
        &lt;/DataTrigger&gt;
    &lt;/Style.Triggers&gt;
&lt;/Style&gt;

&lt;Style x:Key=&quot;TextBoxTheme2&quot; TargetType=&quot;{x:Type TextBox}&quot; BasedOn=&quot;{StaticResource TextBoxTheme}&quot;&gt;
    &lt;Style.Triggers&gt;
        &lt;DataTrigger Binding=&quot;{Binding DuplicateName}&quot; Value=&quot;False&quot;&gt;
            &lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;Green&quot;/&gt;
        &lt;/DataTrigger&gt;
    &lt;/Style.Triggers&gt;
&lt;/Style&gt;

Or if you want to specify Style.Triggers for each TextBox, it would be easier to define a Style inside each TextBox.

&lt;TextBox Text=&quot;example&quot;&gt;
    &lt;TextBox.Style&gt;
        &lt;Style TargetType=&quot;{x:Type TextBox}&quot; BasedOn=&quot;{StaticResource TextBoxTheme}&quot;&gt;
            &lt;Style.Triggers&gt;
                &lt;DataTrigger Binding=&quot;{Binding DuplicateIP}&quot; Value=&quot;False&quot;&gt;
                    &lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;Green&quot;/&gt;
                &lt;/DataTrigger&gt;
            &lt;/Style.Triggers&gt;
        &lt;/Style&gt;
    &lt;/TextBox.Style&gt;
&lt;/TextBox&gt;

答案2

得分: 0

如果您特别希望这个与某个样式一起使用,那么您可以使用附加的依赖属性。

https://learn.microsoft.com/en-us/dotnet/desktop/wpf/properties/custom-dependency-properties?view=netdesktop-7.0

您可以将其绑定到控件中的任何喜欢的内容。

&lt;TextBox Style=&quot;{StaticResource TextBoxTheme}&quot; 
         local:Attached.AbstractedProperty=&quot;{Binding .....}&quot;/&gt;

然后在您的样式中引用已知属性

&lt;DataTrigger Binding=&quot;{Binding Path=(local:Attached.AbstractedProperty), RelativeSource={RelativeSource Self}}&quot; Value=&quot;False&quot;&gt;
      &lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;Green&quot;/&gt;
英文:

If you particularly want this to work with the one style then you could use an attached dependency property.

https://learn.microsoft.com/en-us/dotnet/desktop/wpf/properties/custom-dependency-properties?view=netdesktop-7.0

You can bind that to whatever you like in the control.

&lt;TextBox Style=&quot;{StaticResource TextBoxTheme}&quot; 
         local:Attached.AbstractedProperty=&quot;{Binding .....}&quot;/&gt;

You then reference that known property in your style

&lt;DataTrigger Binding=&quot;{Binding Path=(local:Attached.AbstractedProperty), RelativeSource={RelativeSource Self}}&quot; Value=&quot;False&quot;&gt;
      &lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;Green&quot;/&gt;

huangapple
  • 本文由 发表于 2023年3月4日 08:40:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75632955.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定