Abstract UserControl inheritance in Visual Studio designer

前端 未结 9 1169
广开言路
广开言路 2020-12-01 12:13
abstract class CustomControl : UserControl 
{
    protected abstract int DoStuff();
}

class DetailControl : CustomControl
{
    protected override int DoStuff()
            


        
相关标签:
9条回答
  • 2020-12-01 12:18

    I was new to this in UWP and it was driving me nuts. I didn't think of an abstract base class for a UserControl. I went in a different direction. I created a non-xaml Helper class ... HBase. Each View, say VContract, had a corresponding Helper called HContract. All the speciality code for each view was lodged there. The conversations that would have been between the ViewModel VMContract and View VContract now pass through HContract. We can enforce how HWhatever behaves with IHBase. It's not truly an answer to the OP's question, but does show an alternative approach. All the Views are now basically shells. Whether you x:Bind to the VContract or HContract is a decision for you to make. I chose the VContract way and in the end I think that was a mistake.

    The UWP problem with exceptions in Design Mode is now easily fixed with:

    if (false == Windows.ApplicationModel.DesignMode.DesignModeEnabled)
    {
                HContract = new HContract(this);
    //   Put code here that fails in Design mode but must at run time               
    }
    
    0 讨论(0)
  • 2020-12-01 12:19

    What we want

    First, let's define the final class and the base abstract class.

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

    Now all we need is a Description provider.

    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);
        }
    }
    

    Finally we just apply a TypeDescriptionProvider attribute to the Abstract control.

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

    And that's it. No middle control required.

    And the provider class can be applied to as many Abstract bases as we want in the same solution.

    0 讨论(0)
  • 2020-12-01 12:20

    I couldn't make work the solution of 'Nicole Calinoiu'. But there is an other easy way directly in visual studio:)

    1. Create new project
    2. Add new element 'userControl' and add one button for example
    3. Add new element 'userControl' Inhereted UserControl then select the inhereted userControl.

    More details here : 'http://www.codeproject.com/Articles/20845/How-to-derive-from-a-parent-form

    0 讨论(0)
  • 2020-12-01 12:22

    I resolved this issue in UWP in my custom control.

    My Case

    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));
    
    }
    

    Declaration

    < MyCustomControl:MainModel ShowLabel=True />
    

    Solution

    Just override a dummy style in the generic resources.

    <Style TargetType="local:MainModel" />
    

    Regards,

    Samuel

    0 讨论(0)
  • 2020-12-01 12:29

    I just make the abstract base class into a concrete one by defining the "abstract" methods as virtual, and throwing an exception in them, just in case any naughty derived classes try to call Base implementation.

    e.g.

        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  ;)
            }
    

    The main practical difference between this and a real abstract base class is you get run time errors when calling the base implementation - whereas if the Base was actually abstract, the compiler would disallow an accidental calls to the Base class implementation. Which isn't a big deal for me and allows me to use the designer without worrying about more complex and time consuming work arounds suggested by others...

    PS - Akuma - you should be able to edit your abstract UI class in the designer. I don't have time to check this right now, but it is my understanding that the designer only needs to instantiate the BASE class. As long as the base of the class you are designing is concrete, it doesn't matter what the designed class is.

    0 讨论(0)
  • 2020-12-01 12:30

    You can use a TypeDescriptionProviderAttribute to provide a concrete design-time implementation for your abstract base class. See http://wonkitect.wordpress.com/2008/06/20/using-visual-studio-whidbey-to-design-abstract-forms/ for details.

    0 讨论(0)
提交回复
热议问题