I am writing what i will call a survey system. The surveys will consist of a series of questions, split into sections. The survey definitions will be stored in a database. The questions can be of various types, that have different input methods and validation (e.g.textbox, numeric textbox, selectlist etc.) I am creating a set of user controls that map to different question types. I would like to completely abstract the survey rendering logic from the, survey definition logic. The way i thought i would do this is to use a dumb rendering control that simply takes a collection of controls and renders them out in a for each loop a super simplified version of what I am doing.
private void RenderControls()
{
foreach (UserControl CurrentControl in this.ControlsToRender)
{
MyPlaceholder.Controls.Add(CurrentControl)
}
}
This works in the sense that the correct controls get added to the place holder,however nothing renders. Presumably this is because it does not have the markup in the asxc file.
If i do something like this
private void RenderControls()
{
foreach (UserControl CurrentControl in this.ControlsToRender)
{
MyPlaceholder.Controls.Add(this.LoadControl("path to ascx file")
}
}
It will create the correct number of controls, but i don't want to instantiate the controls here because i would need to to set various properties based on cconditional logic i want to abstract away from this pure rendering layer.
what i want to do is instantiate the controls else where, set the relevant properties and then simply pass a collection of these into the rendering control to render out.
Is there a way to do this with user controls? Would i have to create custom controls instead?
.ascx usercontrols are difficult to make into distributable, portable components. There are ways of doing it, but they have a lot of restrictions and requires several steps. In the end it's not worth it.
Your best bet would be to make custom controls that encapsulate their own rendering.
You could do either, but it sounds to me like you might want to use custom controls.
You could use user controls by exposing properties on the user control.
MyPlaceholder.Controls.Add(CurrentControl)
by the time you get to the above line, the control has already been instantiated. just set those properties on instantiation and you should be set.
alternatively you could set the properties anytime before render
Related
I have a tabbed interface - where the tabs will contain multiple nested controls. In particular, Panels containing panels, containing Grids, etc. Even in some cases additional Tab controls. (Yes it can be a little messy)
However, now I need to create some of these tabs dynamically at run time - and still reference the controls on them. So - for example lets say I have something like
Tab
Panel
TabControl
Tab
Grid
Graph/Chart
Panel
Buttons
I need to create multiple new tabs for each result DataTable I need to display(I do not know how many I have to create until Run Time - or I would just do this all at Design time).
I understand I will create these controls at RunTime - and I can do it easily for one additional instance - but then I start running into naming issues. I cannot add three GridControls (all called DataGrid) to the same form - and because C# is strongly typed I cannot create the variable names at Runtime. AND I also need to be able to reference these controls at some times.
So - I looking for possible solutions. I could create arrays for each type of control I am hoping to create. There are over 15 controls (some nested) for each tab - so it could get a little messy. But it would allow me to access each control - as I could use the Tag Property of the Tab page to allow me to access the various arrays. If I created the arrays to hold a max of 50 elements - it should be more than enough (I do not see users creating more then 5 or 10 of these extra tabs).
As I am somewhat new to C# and Visual Studio - I am wondering how others would handle this sort of task? How would you go about creating multiple instances of embedded (nested) controls on your form - knowing that you will have to reference them elsewhere in the code??
Any thoughts and pointers would be much appreciated.
Thank you
Bradley
Since there's an arbitrary amount of tabs, you'll need to manage them programmatically.
So - I looking for possible solutions. I could create arrays for each type of control I am hoping to create. There are over 15 controls (some nested) for each tab - so it could get a little messy. But it would allow me to access each control - as I could use the Tag Property of the Tab page to allow me to access the various arrays. If I created the arrays to hold a max of 50 elements - it should be more than enough (I do not see users creating more then 5 or 10 of these extra tabs).
That would indeed become messy, and is a recipe for bugs. Tag is a very useful property in the right circumstances, but generally you should avoid using it unless you have a good reason. You might inadvertently introduce cyclic references that leak memory. I find it's most suited for storing related metadata such as an ID(however, avoid storing value types in it, as they become boxed).
If you haven't already, I suggest adopting the same naming convention you use with variables for the names you set in the designer. As backing variables reflect those names, it should help you avoid name conflicts with properties, and keep your code more consistent. My team and I use the convention mSomeField for private fields and designer set names and it has served us well in avoiding most name conflicts over the years.
Start by designing a new UserControl that will serve as the content of the most common tab category, adding as much common layout as possible. Design additional UserControls for each additional tab category. Add accessors for each nested control you need to expose.
Note that the following code uses some C#6/7 features.
In practice, here's what that could look like:
// Code-behind for the UserControl representing the content of the 1st tab category.
class Cat1TabContent : UserControl
{
//...
// These all refer to controls created and named from the designer.
public Panel PrimaryPanel => primaryPanel;
public TabControl TabManager => tabManager;
public Panel SecondaryPanel => secondaryPanel;
//...
}
Managing tabs(in the main form and all other controls that have a TabControl):
//...
private List<UserControl> tabContents = new List<UserControl>();
void AddTab<T>() where T : UserControl, new()
{
var tab = new TabPage();
var tabContent = new T();
tabContents.Add(tabContent);
tab.Controls.Add(tabContent);
tabControl.Controls.Add(tab);
}
void RemoveTab(TabPage tab)
{
if (tab == null) throw new ArgumentNullException(nameof(tab));
if (tab.Controls.Count != 0 && tab.Controls[0] is UserControl tabContent) {
tabContents.Remove(tabContent);
}
tabControl.Controls.Remove(tab);
}
//...
Accessing nested controls:
// Form >> Tab Control >> 1st Tab >> 1st Child.
// This assumes AddTab<Cat1Content>() was called.
var firstContent = (Cat1Content)tabContents[0];
// Content >> PrimaryPanel; Enumerates over nested controls.
foreach (var child in firstContent.PrimaryPanel.Controls) {
// ...
}
// Content >> Tab Control; Enumerates over nested tabs.
foreach (var child in firstContent.TabManager.Controls) {
// This is safe, TabControl throws an exception if you try to add anything that isn't a TabPage.
var tab = (TabPage)child;
// ...
}
I've been reading some explanations about the difference between User and Custom Controls, for example this:
http://www.wpftutorial.net/CustomVsUserControl.html
I want to create, for example, a simple composition of a datagrid with 2 comboboxes which are responsible to change the values from the datagrid's items. I want to create a specific control for this because I'm going to use it a lot of times. I would like to implement the logic behind and then in the xaml invocation I only have to specify the itemsSource.
For this example should I create a User or Custom control? Since I will have properties and logic, should I have a viewmodel for this control?
EDIT: Do you know some articles with clear conceptual separation between these 2 options?
Choice is not only between user control and custom control, but among user control, custom control, customizing control template, customizing data template, header template (for collection based controls), attached properties.
Refer to Control Authoring overview
I go by following order of consideration
Attached Properties : If functionality can be achieved, I use attached properties. Example, Numeric text box.
Control Template : When requirement can be fulfilled by customizing the control template, I use this. Example, circular progress bar.
Custom control: If control template cannot do it, I use custom control. Provided I need to customize/extend already present control. Example providing Sorting, Filtering based on header row in GridView (GridView is present in metro apps, used just to illustrate the example)
User control: Least preferred one. Only when composition is required, and I am unable to do it using custom control. Like in your example, 2 Combobox, and 1 datagrid. User controls does not provide seamless lookless feature that can be leveraged through custom control or control template.
You already have some great answers that explain the differences but also understand that custom controls and UserControls have different purposes:
A UserControl typically encapusulates some sort of composite behaviour. If you have an application that needs to edit contact details in many places, for example, you could create a custom control that has the labels and text fields for all the data laid out with a submit button that has the relevant code and reuse this control throughout your application.
A custom control is a control that is derived from one of the WPF control classes (E.G. Control, ContentControl etc.) and has to be created in code.
These control usually have a single cohesive purpose (think TextBox, ComboBox, Label) rather than acting together as a whole (although this doesn't have to be the case).
UserControl's are usually easier for people unfamiliar with WPF as they can be visually designed.
My suggestion would be to start off with a UserControl. You can always refactor this into a custom control at a later date as you become more familiar with the way WPF works. Creating your control as a custom control will require knowledge of ControlTemplates and Styles as you will need to provide your own to define a look and feel for your control.
When all is said and done, as long as the control behaves correctly, it doesn't matter which approach you use.
See this post for an example of two approaches to the same problem. The post author wanted a control which can present modal content in front of the primary content. The post author actually answered his own question by implementing it as a UserControl. I have added an answer to the post which creates the control as a custom control but both have the same end effect.
If you have a view-model and you wish to create a view for it use the User-Control.
If you need an autonomous control that has no specific view-model,
you probably need a custom-control.
If you find that the functionality you need as whole, already exist in other controls you need to override an existing control template.
(i.e: for a diamond shaped button - you need to override the button control template.)
Regarding attached-properties and attached-behaviors, those are useful when you have a control which you want to extend with more properties or you want it to behave slightly different than its default behavior.
In the provided case of the composition the OP described, it can be achieved with either user control or custom control. I would prefer a custom control since there is no specific view model provided, the "input" is only a property bound to an item collection.
Oh, and, I am sorry for slightly being late.
The best explanation is in the msdn. CustomControl is more a "virtual" name, there is no class called "CustomControl" in WPF, instead its meant creating a new class building on top of one of WPF control classes, like Control, ItemsControl and even more specific Controls like TextBox or Button.
For your specific case, a UserControl should be enough, creating a CustomControl is something that can easily be avoided. While its not a bad thing, a lot of people, especially beginners in WPF coming from WinForms tend to subclass more then necessary.
If this is somehow your first time building controls, I recommend UserControl as VS lets you design its interface more easily. Custom Controls are more powerful, but you have to CLEARLY separate your control's logic from its interface and this requires a bit more preparation.
You can easily Visually design CustomControl.
Create new UserControl (or Window). Create its xaml structure visually in Designer. Copy-paste body of the resulting xaml inside ControlTemplate of your new CustomControl (Eg. in generic theme file).
If I remember right, you are also able to visually design CustomControl template directly, in Blend.
Of course you can also instance the wip CustomControl in a Window and put the Window's Designer view as new panel above the control's xaml view in VisualStudio.
Some xaml bindings from style template don't show in Designer like this though, until I rebuild.
[ Imho GUI is mainly a visual matter and should not, and doesn't need to, be created in code. ]
Well to create a Custom control you need to implement it as a User control. Your own User control is called a Custom control. It is pretty simple.
UserControl is the base class for containing your custom content :
<UserControl>
Your custom WPF content
</UserControl>
I don't totally agree with the article. However in your case you need a UserControl that you can re-use latter in your UI.
I am working in windows forms application and have a following issue. I use tabControl in my application and there is a need to change a content inside certain tabPages when users perform specific actions.
for example tabPage one contains a text area and a button, when user clicks button information inside a text area should be stored somehow, and that same tabPage should display new content e.g. more text areas, buttons etc, I assume it is easier to do by using views inside it, so one view can be hidden and another can be shown.
This a to a degree a matter of taste. You can chose to show and hide controls one by one in a method or you can group them in a UserControl which you then show or hide in one command.
I would base my decision one way or the other by these questions:
Are there controls, that will always be visible and how is the layout for these?
How many controls are there to show/hide?
Is there a need to reuse one or more of your views?
The last question may make the big difference: If you want re-use, do go for the UserControl. It is basically meant to do just that: Group controls, like a form does.
For just a few controls doing it in a one by one (in a switchViewMode-method) would suffice, imo.
To add UCs you right-click your project in the project-explorer and chose add - usercontrol. Then chose a nice name, like UC_Goods or UC_Services or whatever your shop policy suggests.
You are then presented with the empty GUI. Now add the controls you need.
Here a decision is to be made: If you will reuse it make sure the controls get generic names! If not it doesn't matter. The reason is, that when you add two instances of the same UC, their controls will have the same names and you will have to qualify them by the parent (the UC)
Here you also script events etc..
Finally add instances to the TabPage as need like this:
public UC_Goods uc_goodsDelivered = new UC_Goods();
public UC_Goods uc_goodsOnHold = new UC_Goods();
public UC_Services uc_ItServices = new UC_Services ();
public Form1()
{
InitializeComponent();
tab.tp_goodsPage.Controls.Add(uc_goodsDelivered);
tab.tp_goodsPage.Controls.Add(uc_goodsOnHold);
goodsOnHold.Hide();
tab.tp_goodsPage.Controls.Add(uc_ItServices);
uc_ItServices .Hide();
// take care of dock style or anchors..
// ..and initialzing fields..
}
This delclares two UC classes and two and one instance of each respectively. Only one is visible. Since one class is used twice its controls have ambigous names until you qualify them e.g. like this: uc_goodsDelivered.Status...
hth
So what I am trying to do is to have a set UI with certain controls, and I want to have some class instance to fill in the values.
For instance:
Classes that can populate the UI:
Sharpen, Blur, Smear, ... : FilterBase
So whenever the user creates an instances of the above classes, I want to automatically fetch the values based on the UI controls, by using the class instance.
The UI has items like:
.Name (TextBox)
.Amount (NumericUpDown)
.Decay (NumericUpDown)
So if the current instance is s = new Sharpen(), I want to get s.Name to fill out UI.Name.
How do I do this in the best possible way? Elegancy, clarity, performance wise, etc.
I am gonna use reflection, but how do I store the instance of the object (Sharpen, ...) and be type safe? Should I use an System.Object instead? Or T?
public partial class ParamsUI
{
T CurrentFilter (?)
...
}
Also if I use T, how will I know what to cast it to?
Is there a better way?
Since this is using Windows Forms, the most flexible option would probably be to just use the Windows Forms PropertyGrid directly.
You can do a lot of work to customize the look and feel of this. See Getting the Most Out of the .NET Framework PropertyGrid Control for details.
Edit:
If you want to have a very flexible, easy option, and WPF is an option (hosted within an ElementHost), you could consider using WPF.
With this, you could host a UserControl containing nothing but a resource dictionary and a ContentControl.
You could then make a custom XAML file for each item you want to edit, and setup a data template in the resources specifying the mapping of which user control (xaml) to use for each element you want to edit. You can then just set the element to the user control's "DataContext" in code, and it will automatically wire everything up and "just work".
Hopefully I am stating that right. I have a WinForm(3.5) app that has 1 Form that is broke into two regions. 1 is the Navigation and the other, a Panel, is the Content. You select what you want in the Navigation Portion, i.e. Demographics, and then it embeds a UserControl containing all the Demographics controls in the Panel.
What I am asking is if each User Control should have a Property for each Control on it. Example: ucDemographics has a textbox, named txtCity. Should there be a Property to store the value of txtCity and allow my Form and other User Controls to access it?
Is that the generally accepted 'Best Practice'?
If not, what is?
It depends on what you want to achieve with your UserControl.
Normally you wouldn't expose the txtCity because the caller could manipulate everything about the textbox then. In most scenarios, you would only expose the current text รก la
public string CityText
{
get { return this.txtCity.Text; }
}
No, that's not really a best practice. The intention of a user control is to compose a new control with its own behavior. You should at most have "several" properties, methods and events that are public and allows a form to interact with the new control. If you find that the only good way to work with it is by exposing its constituent controls that you're better off not using a UserControl but just place the controls on the form directly.