【问题标题】:Avoiding duplication in WPF (following DRY)避免 WPF 中的重复(遵循 DRY)
【发布时间】:2009-03-09 20:20:24
【问题描述】:

考虑以下 2 个 XAML sn-ps(在文件中并排):

<Button
    x:Name="BuyButton"
    Margin="0,0,1,1"
    IsEnabled="{Binding CanBuy}"
    >
    <StackPanel
        DataContext="{Binding Product}">
        <TextBlock
            Foreground="Red"
            Text="BUY" />
        <TextBlock
            Foreground="Red"
            Text="{Binding BuyPrice}" />
    </StackPanel>
    </Button>

<Button
    x:Name="SellButton"
    Margin="0,0,1,1"
    IsEnabled="{Binding CanSell}"
    >
    <StackPanel
        DataContext="{Binding Product}">
        <TextBlock
            Foreground="Red"
            Text="SELL" />
        <TextBlock
            Foreground="Red"
            Text="{Binding SellPrice}" />
    </StackPanel>
</Button>

如何删除 WPF 中的重复项?这种类型的按钮我有大约 4 次使用(此处显示 2 次),并且它们的 80% 相同,如果不是更多的话。我可以将其提取到用户控件中并在其上放置一些 DP,然后我将拥有一个控件,但我担心我会开始在我的代码库中乱扔大量用户控件(我有很多“一次性"这样的情况)。我不喜欢这里的 DataTemplate 解决方案,因为我仍然需要两个模板,这将有重复的代码。在不创建一堆模板/控件的情况下,有没有办法让这段代码遵循 DRY?

【问题讨论】:

    标签: wpf dry


    【解决方案1】:

    ControlTemplate 可能会起作用:

    <ControlTemplate x:Key="ButtonControlTemplate1" TargetType="{x:Type Button}">
    <StackPanel Height="Auto" Width="Auto">
        <TextBlock Text="{TemplateBinding Content}" Foreground="Red"/>
        <TextBlock Text="{TemplateBinding Tag}" Foreground="Red"/>
    </StackPanel></ControlTemplate>  
    

    我使用 TemplateBinding 来获取这两个可变数据。现在,当您创建按钮时,应用模板并将绑定设置为您的元素:

    <Button x:Name="BuyButton"
        Margin="0,0,1,1"
        IsEnabled="{Binding CanBuy}"
        Template="{DynamicResource ButtonControlTemplate1}"
        Content="Button" 
        Tag="{Binding BuyPrice}"/>
    

    唯一缺少的是 DataContext:只需将其设置在两个按钮上方的容器中即可。

    我没有具体尝试过,但它似乎应该可以工作。我选择了上面的“标签”,因为我需要第二个元素进行绑定。我很乐意看到关于此的不同建议。

    您可能还想将 ForegroundColor="Red" 类型的内容分解为一种样式。

    【讨论】:

    • 对于 2 个元素,是的,您选择的“标签”将起作用。有了 3 个元素,现在我们回到第一个问题(我不认为标签上的 MultiBinding 是可取的;))。关于该特定问题还有其他建议吗?
    • 不幸的是,我没有,这就是为什么我希望看到更多关于这种方法的 cmets。我想知道您是否可以在 Button Content 中放置另一个 ControlTemplate,然后以某种方式在 TemplateBinding 中导航它?
    【解决方案2】:

    我没有替代解决方案,但我不同意您关于一次性控制的论点。在我看来,它归结为在大量重复代码或较少重复之间进行选择,并带有一些非常具体的控件。如果这是纯代码,当面对几块相同的代码时,您可能不会三思而后行执行提取方法,为什么这段代码现在是 XAML 的事实会让您的决定有所不同?

    【讨论】:

    • 我可以快速地说,因为我不必使用提取方法创建新文件。但是,是的,我理解你的论点,是在进行类似的内部对话。
    【解决方案3】:

    如果您的目标只是减少重复,您可以通过使用样式并在父元素上设置常见的附加属性来消除很多重复:

    <StackPanel>
        <StackPanel.Resources>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Margin" Value="0,0,1,1"/>
            </Style>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="Foreground" Value="Red"/>
                <Setter Property="DataContext" Value="{Binding Product}"/>
            </Style>
        </StackPanel.Resources>
        <Button x:Name="BuyButton" IsEnabled="{Binding CanBuy}">
            <StackPanel>
                <TextBlock Text="BUY"/>
                <TextBlock Text="{Binding BuyPrice}"/>
            </StackPanel>
        </Button>
        <Button x:Name="SellButton" IsEnabled="{Binding CanSell}">
            <StackPanel>
                <TextBlock Text="SELL"/>
                <TextBlock Text="{Binding SellPrice}"/>
            </StackPanel>
        </Button>
    </StackPanel>
    

    请注意,这最终会产生更多代码...这就是为什么“3 次打击,然后重构”是经验法则。

    【讨论】:

      【解决方案4】:

      将其分离到用户控件中。 DRY 原则和重构在几乎所有平台上都应该被同等对待。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-15
        • 1970-01-01
        • 1970-01-01
        • 2015-12-29
        • 1970-01-01
        • 1970-01-01
        • 2013-06-27
        • 2020-04-08
        相关资源
        最近更新 更多