How to make dynamic user controls play nice with the designer - c#

I have a dynamic user control that instantiates various bars and labels dynamically based on the number of members in a object group. This functionality works out very well, but the issue is that I am not the only developer on this project. I am new to the team and the "senior" members want all of the components to work in the designer. Since the components of the user control are generated at run time I am not sure how to go about making some/any of them show up in design view. Is this even an option?

I don't think that's possible, because there is no markup for the designer to show. I find it hard to believe that they would expect dynamically created controls to show in the designer.
EDIT
Thinking about it some more, why don't you just add a few hard-coded instances of the control in the markup, with the ability to add/remove. That way, the control is displayed in the designer, but you can still add/remove instances. That would probably be the best compromise in this case.

Why not give both the possibility of defining the number of dynamic controls at design time, and at run time?
In your custom control class, you can define a property that specifies the number of controls. Implement adding/removing controls in the set{} method of this property.
Make your property a "designer property". See http://msdn.microsoft.com/en-us/library/a19191fh.aspx
Keep in mind that the designer actually creates an instance of your class. Also, when a user changes your "property" in the designer, the set{} method is invoked.
I hope this helps

Related

Templated Control vs Custom Control in UWP. No clear answer found online

In my UWP app, my control options are User Control and Templated Control. My understanding of a User Control is KIND OF clear at this point.
I was told that a Custom Control's style/template is only instantiated in memory once, and that this only happens at the time the control is first used. That's what I want since I know the control I am creating will be used in a ListView.
In the book, XAML Unleashed, however, the author creates his Custom Control by starting with a User Control, and then simply changing it's base class. The thing is that the control he created calls InitializeComponent(). I hear that this type of class uses more memory because it is re-instatiated for each item in the ListView.
Also, I never thought that Custom Controls used the InitializeComponent() method. I thought there was simply a call to this.DefaultStyleKey = typeof(MyClass); in the constructor. What gives? I am confused on what is what...
And last, why is the style/template of the Templated Control placed in the global Generic.xaml file, instead of its own separate file (i.e., xaml file and a code-behind file pair)? If the control is supposed to be custom and "portable", then shouldn't it be totally separate from other code? I haven't found a single article explains any of these things in detail on any level.
This is something most people get wrong so I'll try to clarify a few things for you.
Memory
The whole memory thing, it's all in the Visual Tree. When you instantiate any control, whether templated or UserControl, you will use up memory with every instance because in both cases you are creating a full copy of the visual components in the template.
The templated control will create a copy from the ControlTemplate while the UserControl parses the XAML file when InitializeComponent() is called.
Memory usage will be the same if you create 100 templated controls or 100 user controls if their content is the same.
Usage
Templated controls are best for situations where you're creating a single component, like a Button, Slider, MyStarRatingInput, etc. and you're giving the users of your control the ability to swap out the template with their own. It takes a lot more effort to do this properly than UserControls because the logic has to be template agnostic and your templates have to react properly with visual state changes.
A UserControl is best for layout or views, like forms, popups, screens, pages, etc. You will not give someone the freedom to tamper with the content of your view. You may expose a few public/dependency properties if some views are reusable in a small way, but generally they are set in stone.
Generic.xaml
I honestly don't have an answer for this. Microsoft should've allowed multiple resource dictionaries to enable cleaner partitioning of control templates. Generic.xaml is a reserved filename that referencing projects will look for as the root source of the base styles of your controls. You could reference other XAML files from Generic.xaml, but that's annoying and it bloats the root of your resource dictionary. For now, you're stuck with this method.
Recommendation
If you're sharing a control library, you would want to use templated controls as much as possible. If you're building controls, views, pages, etc for your current project and they're not meant for reuse, then use UserControls.
You can still create a UserControl in your control library if you plan on owning the template and forcing all users to accept your design.
I also recommend templated controls for items that you plan on instantiating a hundred times in a single view, like a ListView. You will see noticeable speed improvement if your template is preloaded into memory instead of parsing a XAML file on every instance.

C# UserControl factory

Let's say you have two classes that extend UserControl. Each of the controls provides a custom event (this could be done by using an interface).
You want to display one of the controls in the odd days and the other in the even days.
You also want to be able to drag&drop (Visual Studio) the UserControl on your form without knowing what the Control type will finally be.
How do you do that ? Is the factory pattern useful here ?
I would make a container control that is added on the form (and that is present in the designer toolbox), that internally uses some factory to create an instance of the actual control to use and then adds it to the container with Dock set to Fill.
You could make a third usercontrol that creates & hosts the usercontrol depending on the day.
But, this has a bad feeling to it, could you explain more in detail what you actually are trying to do?

What are the purpose of User Controls in Visual C#?

User Controls -- Do they serve a special purpose?
As far as I can tell they are no different to forms - they have the same toolbox and features.
Are there certain times when they are appropriate to use over forms?
It would be interesting to understand what they are good for.
You use them to group a set of controls and behaviors together in a re-usable way. You can't show a control on the screen unless it's added to a form somewhere.
One good example is a textbox. It's very common to have a label next to your textboxes. You can build a user control to make this easier. Just drop a label and a textbox on the control, expose whatever your properties you want, setup the new control in your toolbox, and now you can just drop this control on your form instead of needing to arrange a label and a toolbox on the form separately.
You could kind of think of them as a panel which "remembers" what controls you put on it. And there's one more important piece. You can put code in these controls as well, and use that to also build special behaviors into your custom controls.
I have to disagree (slightly) with the selected answer. Reusability is only part of what a UserControl is for.
All Controls are reusable. Almost all controls are reusable on the same Form/Window/Panel/etc. For example, a TextBox is a control.
There are two ways to create your own reusable control:
Custom Control
Completely custom, and reusable.
Created entirely in code.
You get a bit more granular control over what your control is doing this way.
Lighter weight (usually), because there isn't anything added in for designability within Visual Studio.
In ASP.Net only: No "HTML" type file to use or edit.
User Control
Completely custom, and reusable.
Created partially in a designer in Visual Studio, and partially in code. (via code behind)
Much easier to deal with from a visual aspect.
A little heavier, as there is pre-existing code added in by the framework to support designing inside Visual Studio.
In ASP.Net only: You can change the appearance a bit simply by editing the .ascx file (basically HTML).
User Controls serve the purpose of reusing controls.
Imagine you need a search box in several pages of your application. You can create a search user control and drop it in every page where you want it visible.
So, it's nothing more than a container that aggregates reusable blocks for your pages.
Forms have a lot of extra furniture that you don't need if you simply want a collection of controls together - the minimize and maximize buttons for example. If you just simply grouped your controls in a Panel, you'd have all the event handlers on the same form as the panel - with a user control, the event handling code is in the user control class, not the form class.
You can reuse the same control on many forms. In fact all items you are using while creating windows forms are the controls. User controls are just extra controls extending controls library provided by .NET.
In ASP.NET, user controls enable you to split your page into reusable components. For example, you may want to have a search box which can be used in different places on your website, so you'd use a user control. They can also be used for partial page caching. You can cache portions of your page to improve performance.

Change Control Types (but not names) on Form with Minimal Impact

I need to change a lot of textboxes to NumericUpDowns and other similar changes on some forms in my multiform c# app. I'd like to keep the name of each control the same as I make the change. There's also code for events associated with some of the controls that I'd like to change as little as possible.
How do I do this without screwing things up badly in Visual Studio? It's version 2008. I'm worried I'll surely run into the dreaded designer errors.
Make the changes in the designer.cs file, and keep your fingers crossed :)
This might make it slightly less painful:
Create a new class, derived from TextBox (let's call it MyClass). Change all of the occurrences of TextBox that you want to change, via the search and replace method. Then you can change MyClass and derive it from NumericUpDown, and see if anything breaks.
Your only alternative is to create a class that is derived directly from either TextBox or NumericUpdown, and then implement methods compatible with the other one. So in effect you would have a control that is compatible with both NumericUpDown and TextBox.

How to create a simple Custom Container control with 2 Divs inside?

Im looking to create a custom ASP.NET container control that will allow me to drag further controls into it within the VS designer.
The final HTML that im looking for is very simple..
<div id="panel1">
<div id="panel2">
</div>
<div id="panel2">
</div>
</div>
With additional controls being able to be dragged into panels 2 and 3.
Im sure its very simple but im struggling to find examples that will help.
Any pointers or ideas are appreciated!
Cheers
Stuart
I've done such things in the past, and yes, from my experience at that time there is not much documentation available. Even worse, at that time some of the documentation was incorrect or vague!
So, to save you all the headaches (ouch, it already starts to hurt when I just think of it :-P), here is some information you definitely need to know.
Basically all controls are for run-time use only. You can attach a ControlDesigner to a control with an attribute on the class definition, which the design time environment (VS.NET IDE) will load and use as a layer on top of your control.
Templates
Chris' suggestion to use Templates is in the right direction. Your control needs to store somewhere the 'content' of the div's, and Templates are the perfect solution. Make sure you get this part right at first. Note: template properties can behave weird if they have a set clause! Moreover, check the use of NotifyParentAttribute also.
When you've got the templates in place, and you can use declarative syntax in ASPX pages to add controls, and they render well, then you can start working on the designer.
For the designer you have 2 options; the easy and complex way.
Easy designer solution
Let's start with the easy way. The base ControlDesigner classes already provide a framework to show templates. You have probably already seen this in action, like in the GridView control and its template fields.
Check out the following MSDN article on creating a template control designer.
With this easy solution, you get an automatic implementation of the smart tag (the arrow to the right of a control during design-time), and can select a template to edit from a drop down list.
Complex designer solution
Now, if this is not really satisfying for you, and you would like to be able to edit controls just like a Panel control, then you have to dig deeper. So here is the complex solution using Control Designer Regions.
See the example in the example in the EditableDesignerRegion class.
What this example does, is overriding the CreateChildControls of the designer class. Remember I said the designer control is a layer on top of your run-time control? So this CreateChildControls method will run after your control's implementation. What you have to do, is mark a HTML element within your render output with a special designer region HTML attribute. In this way, the designer knows what part in your rendered control should be a region.
Now you have to instruct the IDE to assign a editor or viewer to your regions. You have to do this in the GetDesignTimeHtml(DesignerRegionCollection regions) method (notice the overloaded version of this method). As you can see, this method receives a collection of regions. You have to assign your editable of view regions to this collection. Important here - and this is the badly documented part - is that the order in this collection is very important. The value of the region attribute in your HTML, refers to the index in this collection.
So, now we have defined regions in our rendered output, assigned a editor or viewer to it. Next up is how to fill these regions and store the value from these regions back into our controls declaration.
These two actions are handled in GetEditableDesignerRegionContent and SetEditableDesignerRegionContent methods of the control designer. Here you see why it's important to name the regions that you've added to the collection in the GetDesignTimeHtml method. In these two methods you receive the region reference and by it's Name property you could determine which Template property of your control to read/write.
To read and write the template properties we use the magic of the ControlPersister and ControlParser. The persister creates an template instance from declarative ASP.NET (HTML) code. The parser does the job the other way around; creates plain HTML from a template instance.
In a nutshell
So it's up to you to decide whether the standard template editing framework is good enough for you. If you want to have fancy edit capabilities for both of your edit regions in your IDE, then you will have to implement the complex solution. Otherwise just stick with the simple implementation. The examples mentioned will help you a lot.
Here is a link to a MSDN article regarding what you are trying to do, unfortunently there is no VS designer support so it renders correctly from the server but not in the IDE.
How to: Create Templated ASP.NET User Controls
http://msdn.microsoft.com/en-us/library/36574bf6.aspx

Categories