Visual Studio设计器中的用户控件继承

本文关键字:用户 控件 继承 Studio Visual | 更新日期: 2023-09-27 18:03:18

abstract class CustomControl : UserControl 
{
    protected abstract int DoStuff();
}
class DetailControl : CustomControl
{
    protected override int DoStuff()
    { 
        // do stuff
        return result;
    }
}

我在表单中放置了一个DetailControl。它在运行时正确呈现,但设计器显示错误并且无法打开,因为基本用户控件是抽象的。

目前,我正在考虑下面的补丁,这对我来说似乎是非常错误的,因为我希望子类被强制实现该方法。

class CustomControl : UserControl 
{
    protected virtual int DoStuff()
    {
        throw new InvalidOperationException("This method must be overriden.");
    }
}
class DetailControl : CustomControl
{
    protected override int DoStuff()
    { 
        // do stuff
        return result;
    }
}
关于如何解决这个问题,谁有更好的主意?

Visual Studio设计器中的用户控件继承

我们想要的

首先,让我们定义最终类和基抽象类。

public class MyControl : AbstractControl
...
public abstract class AbstractControl : UserControl // Also works for Form
...

现在我们所需要的是一个描述提供者

public class AbstractControlDescriptionProvider<TAbstract, TBase> : TypeDescriptionProvider
{
    public AbstractControlDescriptionProvider()
        : base(TypeDescriptor.GetProvider(typeof(TAbstract)))
    {
    }
    public override Type GetReflectionType(Type objectType, object instance)
    {
        if (objectType == typeof(TAbstract))
            return typeof(TBase);
        return base.GetReflectionType(objectType, instance);
    }
    public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
    {
        if (objectType == typeof(TAbstract))
            objectType = typeof(TBase);
        return base.CreateInstance(provider, objectType, argTypes, args);
    }
}

最后,我们将TypeDescriptionProvider属性应用到Abstract控件。

[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider<AbstractControl, UserControl>))]
public abstract class AbstractControl : UserControl
...

就是这样。不需要中间控制。

在同一个解决方案中,提供者类可以应用到任意多的抽象基。

您可以使用TypeDescriptionProviderAttribute为抽象基类提供具体的设计时实现。详见http://wonkitect.wordpress.com/2008/06/20/using-visual-studio-whidbey-to-design-abstract-forms/。

另一个解决这个问题的方法是使用预处理指令。

#if DEBUG
  public class UserControlAdmonEntidad : UserControl, IAdmonEntidad
#else
  public abstract class UserControlAdmonEntidad : UserControl, IAdmonEntidad
#endif
  {
    ...
    #if DEBUG
    public virtual object DoSomething()
    {
        throw new NotImplementedException("This method must be implemented!!!");
    }
    #else
    public abstract object DoSomething();
    #endif
    ...
  }

有关此主题的更多信息,请参阅此链接:从抽象类继承窗体(并使其在设计器中工作)

同样的解决方案也在这个MSDN论坛的帖子中提到,以一种更简短的方式:UserControl, Inherited Control, Abstract class, (c#)

也许不是更干净的解决方案,但它仍然是我找到的最短的。

尽管这个问题已经存在多年了,我还是想补充一下我的发现。

如果你不想修改抽象基类,你可以这样做hack:

abstract class CustomControl : UserControl 
{
    protected abstract int DoStuff();
}
class BaseDetailControl : CustomControl
{
    protected override int DoStuff()
    {
        throw new InvalidOperationException("This method must be overriden.");
    }
}
class DetailControl : BaseDetailControl
{
    protected override int DoStuff()
    { 
        // do stuff
        return result;
    }
}

这样,您的表单继承自一个非抽象的基本表单,并显示在设计器中!你保留了你的抽象形式,但在继承上又多了一级。很奇怪,不是吗?

我不能让工作解决'Nicole Calinoiu'。但是在visual studio中还有另一种简单的方法:)

  1. 创建新项目
  2. 添加新元素'userControl'并添加一个按钮,例如
  3. 添加新元素'userControl' 继承userControl 然后选择继承userControl。

更多的细节在这里:'http://www.codeproject.com/Articles/20845/How-to-derive-from-a-parent-form

以下是一个通用的解决方案,适用于我,大多数。这是基于另一个答案的文章。有时它可以工作,我可以设计我的UserControl,然后我打开文件,它会给出"设计师必须创建一个MyApp类型的实例"。但它不能,因为类型被声明为抽象。"我想我可以通过清理,关闭VS,重新开放VS,重建来修复它。现在它似乎表现得很好。好运。

namespace MyApp
{
    using System;
    using System.ComponentModel;
    /// <summary>
    /// Replaces a class  of <typeparamref name="T"/> with a class of
    /// <typeparamref name="TReplace"/> during design.  Useful for
    /// replacing abstract <see cref="Component"/>s with mock concrete
    /// subclasses so that designer doesn't complain about trying to instantiate
    /// abstract classes (designer does this when you try to instantiate
    /// a class that derives from the abstract <see cref="Component"/>.
    /// 
    /// To use, apply a <see cref="TypeDescriptionProviderAttribute"/> to the 
    /// class <typeparamref name="T"/>, and instantiate the attribute with
    /// <code>SwitchTypeDescriptionProvider<T, TReplace>)</code>.
    /// 
    /// E.g.:
    /// <code>
    /// [TypeDescriptionProvider(typeof(ReplaceTypeDescriptionProvider<T, TReplace>))]
    /// public abstract class T
    /// {
    ///     // abstract members, etc
    /// }
    /// 
    /// public class TReplace : T
    /// {
    ///     // Implement <typeparamref name="T"/>'s abstract members.
    /// }
    /// </code>
    /// 
    /// </summary>
    /// <typeparam name="T">
    /// The type replaced, and the type to which the 
    /// <see cref="TypeDescriptionProviderAttribute"/> must be
    /// applied
    /// </typeparam>
    /// <typeparam name="TReplace">
    /// The type that replaces <typeparamref name="T"/>.
    /// </typeparam>
    class ReplaceTypeDescriptionProvider<T, TReplace> : TypeDescriptionProvider
    {
        public ReplaceTypeDescriptionProvider() :
            base(TypeDescriptor.GetProvider(typeof(T)))
        {
            // Nada
        }
        public override Type GetReflectionType(Type objectType, object instance)
        {
            if (objectType == typeof(T))
            {
                return typeof(TReplace);
            }
            return base.GetReflectionType(objectType, instance);
        }
        public override object CreateInstance(
            IServiceProvider provider,
            Type objectType,
            Type[] argTypes,
            object[] args)
        {
            if (objectType == typeof(T))
            {
                objectType = typeof(TReplace);
            }
            return base.CreateInstance(provider, objectType, argTypes, args);
        }
    }
}

我只是通过将"抽象"方法定义为虚拟方法,并在其中抛出异常,使抽象基类成为具体的基类,以防任何调皮的派生类试图调用基实现。

    class Base : UserControl
    {
        protected virtual void BlowUp()
        {
            throw new NotSupportedException("This method MUST be overriden by ALL derived classes.");
        }
    class Derived : Base
    {
        protected override void BlowUp()
        {
            // Do stuff, but don't call base implementation,
            // just like you wouldn't (can't actually) if the Base was really abstract. 
            // BTW - doesn't blow up any more  ;)
        }

这与真正的抽象基类之间的主要实际区别是,调用基类实现时会出现运行时错误——而如果基类实际上是抽象的,编译器将不允许意外调用基类实现。这对我来说不是什么大问题,并且允许我使用设计器而不必担心其他人建议的更复杂和耗时的工作……

PS - Akuma -你应该能够在设计器中编辑你的抽象UI类。我现在没有时间检查这一点,但我的理解是,设计人员只需要实例化BASE类。只要你所设计的类的基是具体的,那么所设计的类是什么并不重要。

我在自定义控件中解决了UWP中的这个问题。

public abstract class BaseModel : DependencyObject 
{
...
}
public class MainModel : BaseModel
{
public bool ShowLabel
{
    get{ return (bool)GetValue(ShowLabelProperty); }
    set{ SetValue(ShowLabelProperty, value) }
}
public static readonly DependencyProperty ShowLabelProperty =
    DependencyProperty.Register("ShowLabel",typeof(bool), typeof(MainModel), new PropertyMetadata(false));
}
声明

< MyCustomControl:MainModel ShowLabel=True />
<<p> 解决方案/strong>

只需在泛型资源中重写一个虚拟样式。

<Style TargetType="local:MainModel" />

问候,撒母耳

我在UWP是新手,这让我发疯了。我没有想到UserControl的抽象基类。我选择了另一个方向。我创建了一个非xaml Helper类…HBase。每个视图,比如VContract,都有一个相应的助手HContract。每个视图的所有专业代码都保存在那里。ViewModel VMContract和View VContract之间的对话现在通过HContract传递。我们可以用IHBase强制HWhatever的行为。这并不是对OP问题的真正回答,但确实展示了另一种方法。所有视图现在基本上都是shell。是否绑定VContractHContract是您自己的决定。我选择了VContract的方式,最后我认为这是一个错误。

在设计模式下异常的UWP问题现在很容易修复:

if (false == Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
            HContract = new HContract(this);
//   Put code here that fails in Design mode but must at run time               
}