I'm making such a tabbed "Product Version Control", using an UserControl which encloses fields, checkboxes, text areas, grids, and so on. At runtime, when I add a new tab (like we have on browsers), I instantiate a new UserControl (with all components inside). The issue is: I can get all internal component values and fill an object to persist, but not the other way. I can take all values from Object and set them to EditValue (or Text/Value properties) properties of internal components, but they are not showing up to the user.
Consider:
All my internal components have public set/get methods like shown below
public class TabVersion : UserControl
{
...
public DevExpress.XtraEditors.SpinEdit seRevision
{
get
{
return _seRevision;
}
set
{
_seRevision = value;
}
}
...
}
Inside TabVersion class, I have a "fill" method which receives an "Version" object and set all internal components "EditValue" properties like shown below:
public class TabVersion : UserControl
{
...
public void FillTab(Sheet sheet)
{
...
this.seRevision.EditValue = sheet.NumRevision;
...
}
...
}
At runtime, all EditValue component properties are filled but not showing to the user. Do I have to set "Enabled" or "Visible" properties for each component inside my usercontrol?
Any Ideas?
Thank you in advance.
Well... After googling everywhere with no goal, I wrote a "Fill" method that fills all DevExpress controls inside my user control, and called it inside the "Shown" event at the parent form. I think that's a bug from DevExpress, because all Windows default components works all right when I give them their respective values. That's it.
Related
I am building some applications that use OPC to control some industrial automation. I have decided it might be a good idea to create some custom controls for standard things I will use such as buttons and text boxes. One of my main reasons was that I felt in an ideal pattern the end object i.e. the button is the one who holds information about the OPC item it refers to otherwise in a typical application my Form class gets polluted by tons of variables that are in my mind scoped more global then they should. I started then by using the Tag property of the button but this requires some overhead code that is the same for each instance. I felt like the right thing to do is subclass controls that I would like to use and provide properties to configure each one.
With that context in mind my real question is this. To make it as portable as possible I decided there should a property to define the OPC Group. I declared a property like this
public class OPCButton : Button
{
[Category("OPC")]
public OPCConnectedGroup
{
get { return _OPCGroup; }
set { _OPCGroup = value; }
}
}
This shows up int the property list when I add the control but I am unable to bind this property even though my Form1 contains
public OPCConnectedGroup Connection1 = new OPCConnectedGroup();
I have resolved that the way to solve this is to probably create an additional control like OPCGrp that can be added to a Form then the Controls can reference this. To test I added a property of type Button and sure enough when I added it and browsed to the property it gave me options for all the buttons on the Form. I have no huge problems with this approach I just want to make sure that Im following a prototypical pattern because I will be responsible for maintaining the control library but not always implementing and Im trying to get it down to a 1-2 step process to implement a control.
Thanks
Matt
When defining OPCConnectedGroup you can inherit Component class.
This way if you have a property of type OPCConnectedGroup in your OPCButton, then at design time, you can put instances of OPCConnectedGroup on the form, and then if you choose your OPCButton at designer, that property of type OPCConnectedGroup will show as a drop down list that you can select one of instances that you put on the form for it.
Example:
If I have such MyButton and MyClass:
public class MyButton : Button
{
public MyClass MyClassInstance { get; set; }
}
public class MyClass : Component
{
public string SomeProperty {get;set;}
}
Then you can put some (or one) instance of MyClass on the component tray of the form:
And then if you select MyButton on your form, you can choose one of MyClass instances from in property grid:
I'll try to explain what I'm after. I don't know the technical term for it, so here goes:
Example 1:
If I place a ListView on a Form and add some columns I am able, in Design-Time, to click-and-drag the columns to resize them.
Example 2:
Now, I place a ListView in a UserControl and name it "MyCustomListView" (and perhaps add some method to enhance it somehow).
If I now place the "MyCustomListView" on a Form I am unable to click-and-drag the column headers to resize them in Design-Time.
Is there any way to easily make that happen? Some form of "pass the click-and-drag event to the underlying control and let that control do its magic". Im not really looking to recode, just pass on the mouseclick (or whatever it is) and let the, in this case, ListView react as it did in the first example above.
The Windows Forms designer has dedicated designer classes for most controls. The designer for a ListView is System.Windows.Forms.Design.ListViewDesigner, an internal class in the System.Design.dll assembly. This class gives you the ability to drag the column headers.
A UserControl uses the System.Windows.Forms.Design.ControlDesigner designer class. It doesn't do anything special, just puts a rectangle around the control with drag handles. You can see where this is heading: after you put your user control on a form, it is ControlDesigner that is used to design the class, ListViewDesigner is not in the picture. You thus lose the ability to drag the column headers. Also note that ControlDesigner doesn't give access to the controls inside the UC.
That's fixable however by creating your own designer. Start with Projects + Add Reference, select System.Design. You'll need to add a public property to the UC to expose the list view and apply the [DesignerSerializationVisibility] attribute to allow changed properties to be saved. And apply the [Designer] attribute to the UC class to replace the default designer. It all should resemble this (using the default names and a ListView that displays "employees"):
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design; // Note: add reference required: System.Design.dll
namespace WindowsFormsApplication1 {
[Designer(typeof(MyDesigner))] // Note: custom designer
public partial class UserControl1 : UserControl {
public UserControl1() {
InitializeComponent();
}
// Note: property added
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ListView Employees { get { return listView1; } }
}
// Note: custom designer class added
class MyDesigner : ControlDesigner {
public override void Initialize(IComponent comp) {
base.Initialize(comp);
var uc = (UserControl1)comp;
EnableDesignMode(uc.Employees, "Employees");
}
}
}
The list view in the user control can now be clicked and designed as normal.
In my asp.net 4.0 application I have a standard set of tabs controls across the application that has one tab for Search, one for View and one for Reporting. I am in the process of updating those tabs and I was hoping to be able to wrap their functionality up into a single user control since they all function in pretty much similar ways. The issue I am having is how to create a property called SeacrhTab/ViewTab/ReportTab that allows me to assign a different user control to it depending on the area of the application (e.g. CompanySearchControl, ContactSearchControl, etc.) Anyone ever tried to accomplish something similar? How should I approach this?
You should just be able to create a regular property in the partial class definition in your code behind page. Make it public and of the type of generic class that includes all tab controls and you should be set.
I have not made other controls properties of a user control but I have certainly used all sort of other custom classes as properties of user controls, so I don't see why it wouldn't work.
Assuming CompanySearchControl and ContactSearchControl both inherit from GenericSearchTabControlClass, for instance:
public GenericSearchTabControlClass SearchTab {get;set;}
public GenericViewTabControlClass ViewTab {get;set;}
public GenericReportTabControlClass ReportTab {get;set;}
Create an enum for the specific layout, view or tab definition ie: SearchTab, ViewTab etc. specify that as a Property of your UserControl, then use that propery to create, or hide and show a specific PlaceHolder or Panel depending on the required layout, or functionality.
public enum ControlLayoutEnum
{
SearchTab = 0,
ViewTab = 1,
ReportTab = 2
}
public class TabViewControl: System.Web.UI.UserControl
{
public ControlLayoutEnum ControlLayout { get; set; }
protected override OnInit(object sender)
{
// Create controls required or Hide/Show PlaceHolder or Panel etc
switch (this.ControlLayout)
{
case ControlLayoutEnum.SearchTab: // Create Search Layout
break;
}
}
I want to create my own component which consists two other panels. One of them has fixed contents (such as control buttons, etc.) and the other is standard panel, where I can add other components in designer (VS2008).
I know that I have to create UserControl, where I can place my two panels. Then I want to insert my component into the form. But I don't know how to create behavior where I can add other components (such as buttons, labels, etc.) only into second panel in my component.
Could anyone help me with creating this component?
Thank you.
Adam.
Here is an example (snippet of working code):
[Designer(typeof(NavigationalUserControl.Designer))]
public partial class NavigationalUserControl : UserControl
{
class Designer : ControlDesigner
{
public override void Initialize(IComponent component)
{
base.Initialize(component);
var nc = component as NavigationalUserControl;
EnableDesignMode(nc.panel2, "ContainerPanel");
EnableDesignMode(nc.bottomPanel, "BottomPanel");
}
}
// rest of normal class
}
I have found the correct solution (I hope). I have added into my UserControl a property which returns the content panel with this specific Attribute:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Panel PanelContent
{
get { return this.panel2; }
}
Thanks for your help leppie
I have a user control panel that has two buttons on it. Other user controls inherit from this control and set a property to true if the buttons should be visible. Everything runs how I want it to but what I'm looking for is a way to clear these buttons from the designer window for forms where this property is left at false.
looks like:
[DefaultValue(false)]
public bool ShowButtons{
set
{
mShowButtons = value;
UpdateButtons();
}
get
{
return mShowButtons;
}
}
This property shows in the properties window and the buttons are always shown in the designer window. Is there some way to have the designer evaluate this when the property is changed to get the buttons to clear from the inheriting form? I was unable find a designer attribute to do this.
Try adding a get:
bool mShowButtons;
[DefaultValue(false)]
public bool ShowButtons
{
get
{
return mShowButtons;
}
set
{
mShowButtons = value;
UpdateButtons();
}
}
Now when editing your derived class in the Designer, you should be able to see a ShowButtons property in properties window when the derived UserControl is selected. (It will be in the "Misc" section unless you add the appropriate attribute). If you set it there, it should have the appropriate affect in the Designer (Assuming the contents of the UpdateButtons() function work correctly)).
A property must be public and have bot get and set in order to display in the Properties editor window. Once it is, then setting the value in the properties window will "save" that setting for the designed control in the control's resources/implementation.
I use this functionality quite often to specialize derived UserControls, so I know it should work for you (although there may be other issues at play).