I have a class declared as:
public class Foo<T> : Panel where T : Control, IFooNode , new()
{
...
}
I added it by hand to test it, but I will eventually need something that can be displayed in the Forms designer. The Forms designer doesn't like this, it says:
Could not find type 'FooTestNameSpace.Foo'.
Please make sure that the assembly that
contains this type is referenced.
If this type is a part of your development project, make
sure that the project has been successfully built.
Interestingly, I ALSO get a warning that is similar, but includes the generic type I used in my declaration of the variable.
Warning is:
Could not find type 'FooTestNameSpace.Foo<FooTestNameSpace.FooNodeType>'.
Please make sure that the assembly that contains this type is referenced.
If this type is a part of your development project,
make sure that the project has been successfully built.
The declaration in my simple Form1 class is:
private FooTestNameSpace.Foo myFoo;
(FooNodeType is really just a subclass of Label that has one auxiliary property not yet being used; it does implement IFooNode).
So my question... With this type of set up, how can I get Foo to be displayed on the Forms designer, or at least get it to acknowledge that Foo is legit? Is there any Designer attribute that can handle this? I don't really care if my Foo control appears as an empty box, as long as it appears at all!
Ok, I think I have a solution:
class ConcreteFooCtl : FooCtl<FooNodeType>
{
}
class FooCtl<T> : Panel where T : Control, IFooNode , new()
{
}
The problem seems to be that the Forms designer can't handle any generic control.
The forms designer can't handle FooCtl, but has no problems with ConcreteFooCtl.
Not an ideal solution, but I think it's at least workable. Maybe the next version of VS will prompt the user to specify a generic type when adding a generic control to a form... ;)
Instead of making Foo a generic, you might be better of making it non generic, and having it contain a generic class that does what you need. You can then delegate all your processing from the form to the class.
Related
I would like to define the following control:
public partial class ObjectSelectorControl<T> : UserControl where T : class
The problem is that the designer can't resolve this. Is there a workaround to this issue?
This works
public class Control1<T> : UserControl { ... }
public class Control2 : Control1<double> { ... }
public class Control3 : Control2 { ... }
had read it here:
Generic User Controls?
Sounds much like what we do in our project.
There's a base class that is generic:
public partial class controlItemList<TBaseItem, TBaseItemCollection> : UserControl, IUIDispatcher
where TBaseItem : new()
where TBaseItemCollection : IItemCollection<TBaseItem>
Then for each use we define a non-generic version (which still couldn't be used by designer):
public class controlMessagesNonGenericParent : controlItemList<MailItem, MailItemCollection>
{
}
... and then we have derived controls that could be used in designer:
public partial class controlMessages : controlMessagesNonGenericParent
{
...
}
There are some restrictions on what your control can or cannot do in order to be able to use the designer. Fundamentally they all revolve around the designer being able to instantiate your class (must have a parameterless constructor, can't be abstract, etc.). Because the designer has no idea what type to pass as a generic argument (and I doubt this is even a consideration), your class can't be instantiated.
Your best hope would be to create your UserControl and change the constructor to protected (this, I believe, will work, since the designer uses reflection and ignores visibility, but I'm not 100% positive). You can then inherit from that UserControl and create your generic class and call the base (protected) constructor.
I don't know at which point (with which C#/.NET/VS verison update), but now it is possible to create generic control the same way you create any other generic class.
If you create your UserControl in VS the standard way (i.e. by adding it through GUI), you simply add <T> in both parts of class declaration ("base" class code and the designer managed file). Actually, that is what you have in your quoted code.
I don't believe this is possible, because the designer invokes an instance of your class. If you use generics, the designer doesn't know what type to pass into 'T'.
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=105876
The bug has been posted to microsoft's site and you can see that its marked as "Postponed" currently there is no solution !! .
Use composition instead of generics. Instead of using ObjectSelectorControl, give a generic member of another type (Selector<T> maybe) and act on that object instead of trying to force yourself to be generic.
In one namespace (Ventosa.Graphics) I have a public class named Model
namespace Ventosa.Graphics
{
public class Model : GraphicsResource
{
public Model(...)
{
...
}
...
}
}
Then in another project I try to access this class
Model player = new Model(...);
But this line creates an error. C# recognizes that Model exists, but claims that it isn't accessible due to it's protection level. Shouldn't making it public mean it's accessible from everywhere?
And yes, the base class GraphicsResource is public.
This happens in a few other places in my project too, all with classes that are derived.
EDIT:
The exact error message is (in German):
Der Zugriff auf "Ventosa.Graphics.Model" ist aufgrund der Sicherheitsebene nicht möglich. Translated to English, it says: "Ventosa.Graphics.Model" is inaccessible due to its protection level.
You describe something that clearly should not be. I'd suggest that you try to reproduce the problem in the simplest way possible. You probably won't be able to. Then add to your sample, making it more and more like your production code, until you trigger the problem.
Remove the reference to the superclass GraphicResource. Make sure there's only one constructor defined. Try to instantiate that class from the same namespace, using full namespace references (not using statements) and that single, explicit constructor. It'll probably work.
If it doesn't work, step back a bit and define a new type entirely (Ventosa.Graphics.ModelTest or something). Make sure that works.
Now, add pieces back in. Inherit from GraphicResource, try that. Remove the namespace qualifications; use using instead. Move the instantiation to a different namespace, then a different assembly.
You've verified that the definition of the GraphicResource class is public. What about any of its superclasses?
I know this may sound silly, but have tried to restart Visual Studio (after Cleaning and Rebuilding the solution)? I noticed some strange behavior, especially if you have Code-Coverage enabled and some of the Powertools for Visual Studio installed.
Was Model internal in some previous builds? It's a really common name.
Edit: A way to make sure you actually have the right type, you can hover the "Model" declaration in your second project and press F12 (or right click and choose "Go To Definition", don't know the german term right now). This should take you to your class or to the definition of some other "Model"-class (.NET internal types are displayed too).
I've got a custom class, which derives from UserControl.
The code:
public partial class Gallery<T> : UserControl where T : class, IElement, new()
This classworks like it's supposed to work. But, when I try to enter design mode of the form which contains these Gallery classes, it gives me errors:
Could not find type 'PresentrBuilder.Forms.Gallery'.
Please make sure that the assembly
that contains this type is referenced.
If this type is a part of your
development project, make sure that
the project has been successfully
built.
The variable 'pictureGallery' is either undeclared or was never
assigned.
Note: (pictureGallery actually is a Gallery<PictureElement>).
How can solve this? This way, I can't work in design mode which makes creating my userinterface quite hard.
The designer hates (i.e. doesn't support) generic controls, and that isn't going to change any time soon, so don't do that. Instead, consider having a property (or similar) that accepts a Type, and do some work at runtime (reflection etc) - or: don't use the designer.
For example, if you have:
public Type ControlType {get;set;} // comparable to T in the original
You can use:
IElement el = (IElement) Activator.CreateInstance(ControlType);
This will give you everything you currently have (new, IElement, etc) - but it just can't do any validation at compile-time.
Sometimes the easiest thing to do in this case is to make an empty subclass that qualifies the generic parameter.
This is often done with the ObservableCollection:
public class SomeItemCollection : ObservableCollection<SomeItem>{
}
It is kind of irritating, but it may solve your problems.
Like the others have stated, the Visual Studio Designer has a lot of trouble handling generics in controls. I've run into this myself when trying to implement something like a generic 'property viewer' class.
The solution that worked for me was defining an intermediary class, like Egor said. If I understand your question correctly, for your situation, that should be something like this:
public class PictureElementGallery : Gallery<PictureElement>
Then use the PictureElementGallery on your form, instead of Gallery < PictureElement >.
The designer should have no trouble with that.
Instead of having a generic control, have the control interact with a generic class that is separate from the control itself. Then pass this class into the control.
I have several forms in a C# application. I use Visual Studio 2010 Beta, but .NET 3.5 and C# 3.
I have a base form, called FilteredQueryViewForm in the Shd namespace and I want some other forms to inherit it (because they will basically do the same stuff, but with some additions).
I changed things from private to protected in the FilteredQueryViewForm class, so they're accessible from the derived forms. After this I've created a derived form and set the base class to FilteredQueryViewForm.
The designer of the derived class complained about Shd.FilteredQueryViewForm not having any constructors... regardless of the fact it had one, with 3 parameters. I thought parameters can be a problem, so I also created a (public, of course) constructor without parameters, but it still doesn't work. The error message is the same:
"Constructor on type 'Shd.FilteredQueryViewForm' not found."
And the designer of the derived class won't load.
I have tried restarting vs2010beta, re-creating the derived form, but nothing seem to help. Google didn't yield any useful results for me on this problem. :(
Is this a problem of Visual Studio 2010 Beta? Or am I doing something wrong?
You will need a constructor without parameters which calls the InitializeComponent() method in every of your forms.
Then close the designer window, rebuild the solution and try to reopen the designer. That should work. Rebuilding the solution is essential.
The problem is, that if you create a form that inheritates from Shd.FilteredQueryViewForm, the designer will try to call the constructor of the parent form, but it loads this form not from code but from it's built assembly.
I know that it's an old topic, but these things happen again, so I think that my contribute might be useful in future.
Emiswelt says "You will need a constructor without parameters which calls the InitializeComponent() method in every of your forms."
This is not really needed.
You can declare a custom parameterized constructor on the derived form and call normally "InitializeComponent" method (with a call to a custom contructor too). The important thing is that your constructor calls "InitializeComponent" (for new controls) and base constructor calls "InitializeComponent" (for inherited components).
This situation will work at runtime, but you won't see inherited controls on Visual Studio designer.
To show all the controls at design time you should only add a simple contructor without parameters in the base class.
For example, if your base is a form with a button and two radio buttons:
using System.Windows.Forms;
namespace Test
{
public partial class Form1 : Form
{
public Form1(string foo)
{
//use "foo" here
InitializeComponent(); //here button and radios will be initialized
}
}
}
You can see it on the design tool and you can avoid the blank constructor (with no parameters) without problems.
The Form2 is now inherited from Form1:
namespace Test
{
public partial class Form2 : Form1
{
public Form2(string foo) : base(foo)
{
//you can use "foo" here even if it is passed to base class too
InitializeComponent();
}
}
}
There is no blank constructor and it will compile and run normally. At rutime your Form2 will show the same control set as Form1.
But... you can't see it at design time because Visual Studio can't identify where "InitializeComponent" method is and an error is showed.
Why? Because there should be a constructor without parameters somewhere on the calls' chain.
The solution is a simple modification on the base class:
using System.Windows.Forms;
namespace Test
{
public partial class Form1 : Form
{
public Form1(string foo):base()
{
//use foo here
}
public Form1() //Visual studio designer likes this!
{
InitializeComponent();
}
}
}
That's all.
I think you meant that your Form1.cs[design] didn't update when you added your base class. I had the same problem. Strangely enough, the program will run just fine when you press start, and you'll see your base class components on your Form when you run it, but not when you're in edit mode.
Just double click Form1.cs on the solution explorer. It worked for me.
Make sure the base form(s) are defined in an assembly that is compiled using the "AnyCPU" build option.
I have tried all other answers, but in my case, the problem was in project properties. (I have experimented in default new WinForms project)
Open project properties (project -> properties -> Build)Open properties
Set "Platform target" to "Any CPU" Set platform
Inherit "Form2" class from "Form1" class Inherit
Rebuild project Rebuild
my project is on .NET Framework 4.7.1 target framework
That's all.
I had a similar issue with a different exception related to code in my base form's _Load method, so none of the solutions helped me. There was an exception in design-time that doesn't happen in run-time (null value referring to a static instance of another class). My solution was to throw a try-catch block around all of the code in that method.
I have a base class, defined as below (I'm also using DevExpress components):
public abstract partial class BaseFormClass<R> : XtraForm where R : DataRow
{
...
}
Contrary to what I've read from elsewhere, I'm still able to design this class. I didn't have to create a concrete class from it to do so. But, when I create a concrete class descended from it (as below), that class won't work in the designer.
public partial class ConcreteFormClass : BaseFormClass<StronglyTypedRow>
{
...
}
I get this message:
The designer could not be shown for
this file because none of the classes
within it can be designed. The
designer inspected the following
classes in the file:
ConcreteFormClass --- The base
class
'BaseFormClass'
could not be loaded. Ensure the
assembly has been referenced and that
all projects have been built.
Has anyone seen this before? Any sort of known workaround?
Sorry, but this just isn't going to work (which is a shame -- I've wished in the past that you could do this, too.) The problem is the basic methodology of the designer.
To present you with a model of your form, it doesn't actually try to construct the form itself; if it did that, you'd run into other problems -- what if your form doesn't have a parameterless constructor? Instead, it actually instantiates an instance of the base class of your form. Then it sweeps through your InitializeComponents() method and "layers on" all the controls that you've defined there onto the base form.
So it's obvious why this won't work. You can design an instance of BaseFormClass, because to design that, it creates an instance of XtraForm, which is concrete. But you can't design an instance of ConcreteFormClass, because to do so, it would need to create an instance of BaseFormClass, which is abstract.
The easiest workaround for this is to just make BaseFormClass non-abstract. (If you want to make absolutely sure nobody can create one, perhaps you could make the default constructor private? I'm not sure if the designer can handle that, but I don't see why it couldn't.) Sucks, but such is life. Complain to Microsoft and maybe it'll be better in Visual Studio 2012.
This sounds like a really similar issue to getting the designer to render forms that have an abstract base class. I haven't done any generic multi inheritance but you could at least try my approach and see if it works.
Edit: Yep, ok, just tried it, my solution works for sure. You just have to modify the middle classes definition and the forms definition (wrapped in the #if DEBUG)
Let me know if you're able to try it!