1

我有一个可换肤的控件库,它从外部 xml 文件加载控件设置/属性。这些Xml类在一个单独的项目中,因为它们将在皮肤编辑器应用程序中使用,现在的问题是,控件在构造函数中接受一个 xml 对象来构建,Control但我需要找到一种创建每个控件的好方法。

xml类示例:

[Serializable]
[XmlInclude(typeof(XmlButton))]
[XmlInclude(typeof(XmlGroup))]
[XmlType(TypeName="Control")]
public class XmlControl
{
    [DefaultValue(0)]
    public int Width { get; set; }

    [DefaultValue(0)]
    public int Height { get; set; }
 ...

和每个控件类型的派生类型

[Serializable]
[XmlType(TypeName = "Button")]
public class XmlButton : XmlControl
{
    public string Label { get; set; }
}

控制类

public class GUIControl : GUI3DBase
{
    public GUIControl(XmlControl skinXml)
    {
        SkinXml = skinXml;
...

public class GUIButton : GUIControl, IActionControl
{
    public GUIButton(XmlControl skinXml) : base(skinXml)
    {
    }
...

现在这是我需要帮助的地方,目前我有一个方法可以根据传入的 xml 对象创建控件。

    public static GUIControl CreateControl<T>(T skinXml) where T : XmlControl
    {
        if (skinXml is XmlButton)
        {
            return new GUIButton(skinXml);
        }
        else if  (skinXml is XmlGroup)
        {
            return new GUIGroup(skinXml);
        }
        ....

我有大约 30 个控件,并且“if 阶梯”正在快速增长,我觉得我缺少一种创建这些控件的简单方法,而无需检查 xml 对象类型然后创建相应的控件类型。

我不能Type在 Xml 对象中添加属性,因为这会创建循环依赖。

任何对良好工厂方法或新结构布局的帮助都会很棒

4

3 回答 3

2

也许IDictionary<Type, Func<XmlControl, GUIControl>>会有所帮助。像这样的东西:

private static Dictionary<Type, Func<XmlControl, GUIControl>> _dictionary = new Dictionary<Type, Func<XmlControl, GUIControl>>()
                                                                                    {
                                                                                        {typeof (XmlControlImpl), x => new GUIControl(x)},
                                                                                        {typeof (XmlGroup), x => new GUIGroup(x)},
                                                                                    }; 

public static GUIControl CreateControl<T>(T skinXml) where T : XmlControl
{
    Func<XmlControl, GUIControl> builder;
    if (!_dictionary.TryGetValue(typeof(T), out builder))
        throw new KeyNotFoundException("");

    return builder(skinXml);
}                            
于 2013-01-09T10:46:47.140 回答
2

好的,我已经找到了一种方法,可以通过您的所有想法和一点反思来做到这一点,不确定它是否是最好的方法,但它工作得很好,并且添加一个新的可换肤控件只需要一个新的 xml 对象和控件类上的一个属性。

属性类

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class XmlControlTypeAttribute : Attribute
{
    protected Type xmlType;

    public XmlControlTypeAttribute(Type xmlType)
    {
        this.xmlType = xmlType;
    }

    public Type XmlType
    {
        get { return this.xmlType; }
    }
}

控制:

[XmlControlType(typeof(XmlButton))]
public class GUIButton : GUIControl, IActionControl
{
    public GUIButton(XmlControl skinXml) : base(skinXml)
    {
    }
    ....
}

工厂方法:

public static GUIControl CreateControl2<T>(T skinXml) where T : XmlControl
{
    var controlType = Assembly.GetExecutingAssembly().DefinedTypes
        .Where(t => t.BaseType == typeof(GUIControl) && t.GetCustomAttribute<XmlControlTypeAttribute>().XmlType.Equals(typeof(T)))
        .FirstOrDefault();

    return (GUIControl)Activator.CreateInstance(controlType, new[] { skinXml }, null);
}

感谢帮助堆的所有想法,我将把这个问题留得更久一些,因为有些人有比这更好的解决方案。

于 2013-01-09T12:08:03.733 回答
1

我很想将抽象方法添加到XmlControl

public abstract class XmlControl
{
    [DefaultValue(0)]
    public int Width { get; set; }

    [DefaultValue(0)]
    public int Height { get; set; }

    public abstract Type ControlType();

在每个实现中覆盖它,例如:

public class XmlButton : XmlControl
{
    public string Label { get; set; } 

    public override Type ControlType(){ return typeof(GUIButton); }
}

然后在Factory方法中使用反射构造正确的类:

public static GUIControl CreateControl<T>(T skinXml) where T : XmlControl
{
    return (GUIControl)Activator.CreateInstance(skinXml.ControlType(),
                                     new[]{skinXml},null);
}
于 2013-01-09T10:49:05.373 回答