用于封装覆盖和静态装饰的设计模式

时间:2017-01-08 11:33:46

标签: c# polymorphism

我有一个为按钮添加行为的类,但我想封装添加的行为,以便我也可以将它添加到ButtonBase的其他衍生物中。该行为管理逻辑树的添加,以便我可以制作xaml可组合的多目标命令。

自定义控件

public class MultiCommandButton : Button
{

    #region Command

    public Collection<object> _logicalChildren { get; set; }

    public override IEnumerator LogicalChildren
    {
        get
        {
            if(_logicalChildren == null) return base.LogicalChildren;
            return this._logicalChildren.GetEnumerator();
        }
    }

    public static void CommandChangedCallback (DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        var multitarget = e.NewValue as MultiTargetCommand;
        if (multitarget == null) return;

        var b = d as MultiCommandButton;
        if (b == null) return;

        _changeLogicalMultiTargetCommand(b, e.OldValue, e.NewValue);

        if (e.OldValue == null) return;
        b.RemoveLogicalChild(e.OldValue);
    }

    public static void _changeLogicalMultiTargetCommand (MultiCommandButton b, 
        object oldValue, object newValue)
    {
        var children = b._logicalChildren;
        if (children != null && oldValue is MultiTargetCommand)
        {
            if (children.Contains(oldValue))
            {
                children.Remove(oldValue);
                b.RemoveLogicalChild(oldValue);

                children.Add(newValue);
                b.AddLogicalChild(newValue);

                return;
            }
            throw new InvalidOperationException("Only one MultiCommand can be set");
        }

        var baseChildren = b.LogicalChildren;
        object content = null;
        if (baseChildren != null && baseChildren.MoveNext())
        {
            content = baseChildren.Current;
        }

        b._logicalChildren = new Collection<object>();
        if (content != null)
            b._logicalChildren.Add(content);

        b._logicalChildren.Add(newValue);

        b.AddLogicalChild(newValue);
    }

    #endregion

    #region Constructor

    static MultiCommandButton()
    {
        CommandProperty.AddOwner(typeof(MultiCommandButton),
            new FrameworkPropertyMetadata(CommandChangedCallback));
    }

    #endregion
}

示例视图

<StackPanel x:Name="Targets">

    <Button x:Name="Button1">
        <Button.CommandBindings>
            <ctb:OutputToggleEnabledBind />
        </Button.CommandBindings>
    </Button>
    <Button Name="Button2">
        <Button.CommandBindings>
            <ctb:OutputToggleEnabledBind />
        </Button.CommandBindings>
    </Button>
    <Button Name="Button3">
        <Button.CommandBindings>
            <ctb:OutputToggleEnabledBind />
        </Button.CommandBindings>
    </Button>

</StackPanel>

<ctb:MultiCommandButton x:Name="MultiEnable"
                        CommandParameter="Multi Target">

    ^^^Multi Target Toggle Enabled^^^

    <ctb:MultiCommandButton.Command>
        <ctb:MultiTargetCommand
            Command="{x:Static ctb:MultiCommands.OutputToggleEnabled}">
            <ctb:CommandTarget Target="{Binding ElementName=Button1}" />
            <ctb:CommandTarget Target="{Binding ElementName=Button2}" />
        </ctb:MultiTargetCommand>
    </ctb:MultiCommandButton.Command>

</ctb:MultiCommandButton>

我尝试了什么

我试图以三种方式实现这一目标......

  1. 将公共静态元素移动到静态服务类
  2. 创建界面以概述实例要求
  3. 将静态方法转换为实例方法并使用接口
  4. 我试图避免的另一个选择是将成员简化为派生类。

    静态服务类

    我将一些方法设为静态,希望我可以将它们移动到静态服务类。我遇到的问题是静态方法引用了基类上的受保护的内部属性(例如RemoveLogicalChild中的FrameworkElement),因此静态方法由于它们的访问而在词法上绑定到我的派生类符。因此,我无法在不暴露这些属性的情况下将这些方法移动到服务类,并在派生类上使用中继属性。这看起来像代码味道。

    创建接口

    我不知道是否有任何类似于接口的方法可以应用于静态成员,因为我无法将静态成员移动到服务类,我可以&#39 ; t使用接口。我也有一个属性是覆盖,我认为这也是一个问题,但似乎可以使用new关键字:虽然这感觉像特定应用程序的风险,因为WPF可能访问基本属性并忽略新的(我实际上可以在WPF检查器中看到这种差异)。

    将静态成员转换为实例成员并使用接口

    这样可行,但是创建了可能是静态的方法的不必要的实例版本,并且我可能会因为必须使用new关键字而破坏我覆盖的虚拟FrameworkElement属性的风险。

    问题

    最干净,最干燥的方法是什么?

0 个答案:

没有答案