I am creating a graphing interface and would like to give the user the option to edit the graphs look, i.e. Series color, BackColor, Data point size, etc... The chart is being created using
System.Windows.Forms.DataVisualization.Charting
To allow the user to edit those options I've placed a PropertyGrid in the form. However there are some properties I do not want the user to have access to. I would like to be able to set up a chart in my form then create a propertygrid that is connected to that chart but have certain properties removed from the grid.
What I have so far tried is ...
public partial class Form1: Form
{
PropertyGrid propG1 = new PropertyGrid();
this.Controls.Add(propG1);
//... There is code here where my chart(chart1) is being populated with data
private void toolStripButton1_Click(object sender, EventArgs e)// The button is just to test
MyChart myC = new MyChart();
propG1.SelectedObject = myC;
}
So based on the recomendations I've received so far I've created a class called MyChart which contains the properties that I don't want to be displayed on my chart.
using System.ComponentModel
//...
public class MyChart : Chart
{
[Browsable(false)]
public new System.Drawing.Color Property
{
get{return BackColor;} // BackColor is just an example not necessarily a property I'd like to remove
set{base.BackColor = value;}
}
I haven't been able to remove the properties from my grid nor have I been able to connect myC with my chart1 so when a property is changed in the grid chart1 is affected. Thanks for the continuing help.
Instead of modifying the PropertyGrid component and its behavior you can modify the objects that you display with attributes. Something like this:
[Browsable(false)]
public object SomeProperty
{
}
Don't forget to add:
using System.ComponentModel;
And to override inherited properties and hide them from the propertyGrid you could do something like:
public class Chart : BaseChart
{
[Browsable(false)]
public new string BaseString // notice the new keyword!
{
get { return base.BaseString; } // notice the base keyword!
set { base.BaseString = value; }
}
// etc.
}
public class BaseChart
{
public string BaseString { get; set; }
}
Setting the Browsable attribute to false will keep SomeProperty from showing up in the PropertyGrid.
So, in a hypothetical chart class like the one below, you will see the chart instance, the SomeProperty1 property but not SomeProperty2.
public class Chart
{
public object Property1 { get; set; }
[Browsable(false)]
public object Property2 { get; set; }
// etc.
}
See Getting the most out of your property grid for more information. And here is a very, very good deep-dive into customizing the PropertyGrid control that will blow your mind. ;-)
And, even more fun with attributes and the PropertyGrid:
[DefaultPropertyAttribute("Property1")]
public class Chart
{
[CategoryAttribute("My Properties"),
DescriptionAttribute("My demo property int"),
DefaultValueAttribute(10)]
public int Property1 { get; set; }
[Browsable(false)]
public object Property2 { get; set; }
[CategoryAttribute("My Properties"),
DescriptionAttribute("My demo property string"),
DefaultValueAttribute("Hello World!")]
public string Property3 { get; set; }
// etc.
}
Related
I am trying to create a Property made up of List<> for Custom Form. Please take a look at my code below:
//Property of Custom Form
public ParametersList Parameters { get; set; }
public class ParametersList : List<Parameter>
{
private List<Parameter> parameters = new List<Parameter>();
public void AddParameter(Parameter param)
{
parameters.Add(param);
}
}
public class Parameter
{
public String Caption { get; set; }
public String Name { get; set; }
}
The Property Parameters now appear on a custom form, but the problem is when I click the Ellipsis of the Parameters property and add some list, the list is not saving when I press the Ok button. So every time I press the Ellipsis, the list is clear.
Here is an example of what I am trying to achieve:
You want a list of Parameter objects in a custom control. This is done simply by providing a List<Parameter> property on the control. Here is an example using a user form:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
ParameterList = new List<Parameter>();
}
[Category("Custom")]
[Description("A list of custom parameters.")]
public List<Parameter> ParameterList { get; }
}
Your main issue is that items you add in the list while designing the form, do not persist when the application is run. This is to be expected because the designer does not save the full design state of the controls in a form. It mainly saves the location, names and styles but not the contents.
You will need to fill the list when the form loads, either from a file, a database or programmatically. This should be done in the OnLoad() method:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
ParameterList.Add(new Parameter() { Name="First", Caption="The first parameter" });
}
for something like this, I prefer serialization into an XML file which loads automatically when the form is loaded and saves automaticall when the form closes. But that is a topic of discussion on a different question.
You can improve the visuals by creating a custom list class to use instead of List<Parameter>.
[TypeConverter(typeof(ExpandableObjectConverter))]
public class CustomParameterList : System.Collections.ObjectModel.Collection<Parameter>
{
public override string ToString() => $"List With {Count} Items.";
public void Add(string name, string caption) => Add(new Parameter() { Name = name, Caption = caption });
}
and you control class
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
ParameterList = new CustomParameterList();
}
[Category("Custom")]
[Description("A list of custom parameters.")]
public CustomParameterList ParameterList { get; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
ParameterList.Add("First", "The first parameter");
}
}
which creates the following:
Igor's comment identifies the problem, just use a List<Parameter> and not a custom class. Here's why I think that's the problem:
Your form is adding items to the ParametersList, NOT to the private List<Parameter> inside of the ParametersList.
So your class is a list of parameters (via inheritance), AND has a list of parameters (via the encapsulation). Seems like all you need is to store a collection of parameters, so I don't see the need for a custom class at all.
In Visual Studio 2008,
If you create a Form and put a Control on it,
you can edit the control's properties via the Properties window.
Some controls enable changing their properties in another way,
in addition to the Properties window.
It looks like this:
It seems that all controls that has this pane, has it in the same style,
meaning it's something that is provided by Visual Studio,
and the maker of the control just chooses the items to include inside,
like Fields, and Clickable Links that open some windows.
So my question:
What is the name of this pane control,
and how do I create one?
That menu is called Smart Tags or Designer Actions and you can add smart tag to your control. To do so, you need to create a custom Designer for your control and in the designer, override its ActionLists property.
Example
Let's say we have created a control having some properties, and we want to show the following properties of out control in smart tags window:
public Color SomeColorProperty { get; set; }
public string[] Items { get; set; }
And the expected result for us is:
MyControl
Here we decorate the control with Designer attribute to register the custom designer:
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[Designer(typeof(MyControlDesigner))]
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
void InitializeComponent() { }
public Color SomeColorProperty { get; set; }
public string[] Items { get; set; }
}
MyControlDesigner
Here we override ActionLists and return a new DesignerActionListCollection containing the action list items which we need:
public class MyControlDesigner : ControlDesigner
{
private DesignerActionListCollection actionList;
public override DesignerActionListCollection ActionLists
{
get
{
if (actionList == null)
actionList = new DesignerActionListCollection(new[] {
new MyControlActionList(this) });
return actionList;
}
}
}
MyControlActionList
Here we create properties which get/set out control properties. Also we create methods which are responsible to show custom editor for some properties or do some actions. Then return a list of action items by overriding GetSortedActionItems:
public class MyControlActionList : DesignerActionList
{
ControlDesigner designer;
MyControl control;
public MyControlActionList(ControlDesigner designer) : base(designer.Component)
{
this.designer = designer;
control = (MyControl)designer.Control;
}
public Color SomeColorProperty
{
get { return control.SomeColorProperty; }
set {
TypeDescriptor.GetProperties(
(object)this.Component)["SomeColorProperty"]
.SetValue((object)this.Component, (object)value);
}
}
public void EditItems()
{
var editorServiceContext = typeof(ControlDesigner).Assembly.GetTypes()
.Where(x => x.Name == "EditorServiceContext").FirstOrDefault();
var editValue = editorServiceContext.GetMethod("EditValue",
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.Public);
editValue.Invoke(null, new object[] { designer, this.Component, "Items" });
}
public override DesignerActionItemCollection GetSortedActionItems()
{
return new DesignerActionItemCollection() {
new DesignerActionMethodItem(this, "EditItems", "Edit Items", true),
new DesignerActionPropertyItem("SomeColorProperty", "Some Color"),
};
}
}
For more information about this topic, take a look at this MSDN Walkthrough.
Download Example
You can download a working example from the following repository:
r-aghaei/ControlSmartTagsExample
Zip File
This is called 'DesignerActionList' or SmartTag. Smart tags are menu-like user interface (UI) elements that supply commonly used design-time options.
Step:
You must add a reference to the design-time assembly, System.Design.dll
Create DesignerActionList class and get the reference to control in the constructor.
public class MyControlTasks : System.ComponentModel.Design.DesignerActionList
{
private MyControl myControl;
private DesignerActionUIService designerActionUISvc = null;
public MyControlTasks( IComponent component ) : base(component)
{
this.myControl = component as MyControl;
this.designerActionUISvc =
GetService(typeof(DesignerActionUIService))
as DesignerActionUIService;
}
}
Add methods and properties that you want to associate to smart-tag items
Create base designer for the control
public interface IDesigner {
void Dispose();
void Initialize(IComponent component);
IComponent Component {
get;
}
}
Return a new instance of the MyControlTasks class that you created earlier.
public override DesignerActionListCollection ActionLists
{
get
{
var actionLists = new DesignerActionListCollection();
actionLists.Add(new MyControlTasks(this.Component));
return actionLists;
}
}
I'm creating a properties grid using C#.NET for my AutoCAD plugin. This plugin checks each entity in an AutoCAD drawing for XRecord data and if it finds any, attempts to deserialize it into a class. All of that is working so now I want to show a stored object's properties in my form's properties grid. Here is the class who's information I want to show
public class SerializeTest
{
#region class variables
public int X { get; set; }
public int Y { get; set; }
#endregion
#region Constructors
public SerializeTest(int passedX, int passedY)
{
this.X = passedX;
this.Y = passedY;
}
private SerializeTest()
{
}
#endregion
}
And here's what it looks like in my form when I click the AutoCAD entity that is storing it as an XRecord
I want to add the object's class type (in this case SerializeTest) before the other properties. How would I customize the properties grid like that?
Specifically, I want it to look like this except with the class field at the top not the bottom
I am trying to implement a Custom Composite WebControl with "nested" properties, i.e., encapsulate a group of properties into a class.
For example, in this composite control, I have placed a button. I would like to be able to encapsulate relevant properties for the button into a class (e.g., buttonText, buttonStyle, etc.). This would make defining properties in multi-button/controls composite-control easier and consistent and intuitive.
Note: I would like for the encapsulated properties to appear grouped in the Properties dialog in VisualStudio, in a manner very similar to Style/Font.
Sample:
public class fooButtonProperties
{
[Category("Appearance"), Description("URL for the Profile page")]
public string URL { get; set; }
[Category("Appearance"), Description("Text to display"), DefaultValue("Profile")]
public string ButtonText { get; set; }
/// <summary>
/// Position of the control on the page, default is Right-Aligned
/// </summary>
[Category("Appearance"), Description("Position in the Header"), DefaultValue(PIONEERFramework.Web.UI.WebControls.PageHeaderFooter.Classes.DesignEnum.DesignLayoutEnums.HorizontalPositions.Right)]
///Here is the composite control
public PIONEERFramework.Web.UI.WebControls.PageHeaderFooter.Classes.DesignEnum.DesignLayoutEnums.HorizontalPositions PositionInHeader { get; set; }
}
public class myCustomClass: System.Web.UI.WebControls.CompositeControl
{
protected System.Web.UI.HtmlControls.HtmlLink myButton;
[Category("Appearance")]
public fooButtonProperties myButtonProperties { get { return _profileButtonProp; } }
private fooButtonProperties _myeButtonProp;
#region Constructor
public myCustomClass()
{
this._myeButtonProp = new fooButtonProperties ();
}
#endregion
}
Unfortunately, this approach dos not work. The new property myButtonProperties does not appear at all in the "Properies" dialog.
To create a nested property use the System.ComponentModel.DesignerSerializationVisibility attribute in your control like this:
[Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public fooButtonProperties myButtonProperties { get { return _profileButtonProp; } }
The final property name will be "myButtonProperties-URL" (with a hyphen). You can also add this attribute to properties in your fooButtonProperties class for even more nesting.
Please note that you may have to close the aspx file and rebuild the solution to refresh the Properties window.
The Category attribute works in your control and in your nested class.
The Description attribute for the descriptions seems correct BUT it does not work which could be a bug in Visual Studio. I found this link:
https://www.beta.microsoft.com/VisualStudio/feedback/details/653335/webcontrol-property-descriptions-do-not-appear-in-property-window
Also I observed that no properties show descriptions.
Regards
Oli
I am trying to bind a List to a Combobox as datasource. My list is composed of custom class objects.
Binding works fine, but I can not set DisplayMember.
My class definitions; I have a custom class "Sett_Colection" that keep a List of another custom class
"Sett".
public class Sett
{
public string nameOfSett;
public Sett(){
...
}
}
public class Sett_Colection
{
public List<Sett> listOfSetts;
public Sett_Colection(){
...
}
}
The code in my Form is something like this;
public partial class Form1: Form
{
Sett_Colection collectionOfSetts;
public Form1()
{
// Here I add Sett instances into collectionOfSetts
// So collectionOfSetts.listOfSetts is not empty
combobox1.DataSource = collectionOfSetts.listOfSetts;
cmb_ayar.DisplayMember = "nameOfSett";
}
}
When I did this, datasource assigned succesfully. But display member has not been set as "nameOfSett".
The item names display as "Namespace.Sett";
I found a lot of example codes on internet, but none of them worked. I think my situation is a bit different
You need it to be a property:
public string nameOfSett {get; set;}