I am writing a control for c# (WinForms) and I have one property of Collection type.
When user select this property, button with "..." will be shown and new modal dialog will open. All this work fine, I have create:
public class ItemsEditor : UITypeEditor
In this class I have override EditValue method and open modal editor with ShowDialog. As I say this work fine.
But, I want to open this dialog when user of control double-click on it.
For this purpose I have inherit ControlDesigner:
public class MyControlDesigner : ControlDesigner
and in this class I have inherit next method:
public override void DoDefaultAction()
{
string propertyName = "Items";
IServiceProvider provider = (IServiceProvider)GetService(typeof(IServiceProvider));
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(MyControl);
PropertyDescriptor property = properties[propertyName];
UITypeEditor editor = (UITypeEditor)property.GetEditor(typeof(UITypeEditor));
editor.EditValue(provider, null);
}
As may be seen, I have put some random code and of course don't work.
Can somebody help me how to solve this, and how to open property on double-click.
Thank you for all help
Best regards
Bojan
I am not certain about feasibility of showing the editor on double click but one of other way could be using ActionLists aka SmartTag - please see article: http://msdn.microsoft.com/en-us/library/ms171829.aspx
Related
I am trying to add some fields to a custom UserControl that I am making. I have some fields that I like them to be visible in the Properties window of Visual Studio. I tried to use the flags below but I dont see the field in the designer, even after a compile.
How should I do this correctly?
public partial class TosChartControl: UserControl
{
#region PUBLIC FIELDS
[Browsable(true)] //Added this but still does not show up
[Category("Data")]
[DefaultValue(0)]
[Description("ID of the Sensor Node")]
public int NodeId { get; set; }
#endregion
public TosChartControl()
{
InitializeComponent();
}
}
I did clean and rebuild the soloution and projects but I cant still see this field in Properties window. Even restarting the Visualstudio didnt help.
UPDATE: Your public properties are visible in the designer only when it's in another control in the designer. It turns out that you don't need to add this attribute, properties are visible by default in the designer. As far as I understand, when it's in another component's design view, an instance of the user control is created and properties can be shown. Sorry for misleading you in the beginning, I thought it was necessary to add it.
Try this attribute:
[Browsable(true)]
http://msdn.microsoft.com/en-us/library/system.componentmodel.browsableattribute.aspx
To elaborate on henginy's updated answer:
Be sure that you are looking at an instance of the control you want to modify properties for, and not the definition of the control itself.
To clarify, when you add a property to your TosChartControl class, you won't see the property in the TosChartControl.cs [Design] tab, you will see it where you implement a TosChartControl, such as your Form1.cs [Design] tab, e.g. the containing control to which you have added your custom control.
...Assuming that your Properties window is visible, and that you have the control selected.
What to take away from this lesson:
Understanding what the properties window is actually showing you — It's contextual.
The difference between the model and the implementation of the model — e.g. Designing the custom control and designing the form that uses the custom control.
Consider a form with some custom UserControl and a Button.
In Visual Studio designer, you can click the button off to the right of your property (like you would when you change other common properties on controls such as Font or Image) and use the Editor for this property.
During runtime, if you've added a PropertyGrid to the form and point it to this UserControl, you can also click the button off to the right of that complex property at runtime and get the same UITypeEditor dialog.
How can I get this editor window to come up during run-time through say, a button click without having a PropertyGrid on the form?
Though I've gotten the PropertyDescriptor and the UITypeEditor from this descriptor, I don't know what to call to get the instances of ITypeDescriptorContext and IServiceProvider when calling UITypeEditor.EditValue to get the editor to display.
This is related to building a custom UITypeEditor for a property: Building Windows Forms Controls and Components with Rich Design-Time Features. In this case, I've already configured all of this and it all works beautifully so I just want to call the editor window at runtime.
I you had managed to implement a TypeDescriptor, you almost done.
This may be a start for you:
public class MyEditor: UITypeEditor {
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
return UITypeEditorEditStyle.DropDown;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
IWindowsFormsEditorService service = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
if (service != null) {
SomeControl ctrl = new SomeControl();
ctrl.XYZ = ...
service.DropDownControl(ctrl);
value = ctrl.XYZ;
}
return value;
}
WinForms handles the rest of it.
Return UITypeEditorEditStyle.Modal form GetEditStyle and also use service.ShowDialog(ctrl), if you have a form instead of a control.
). How can you set the default size with which the Popup Editor shows up when you invoke it from a Property Grid.
This is for everybody who is familiar with Windows Forms' Property Grid Editor.
You know that if you throw a List property to a Grid, it shows the little [...] button which if you press it pops up its default sub-value editor. I actually use the editor for another type of object, but I gave this example just so you know what I'm referring to. And here's a picture, at least until the link lives:
http://www.perpetuumsoft.de/sf/en/ims/rssSilverlight/GetStart/image032.jpg
My understanding is that (both for modal and non-modal editors) it is completely up to the whim of the control being shown. If the UITypeEditor involved chooses a big form, it will be big...
The only way to change that would be to define your own UITypeEditor and associate it with the types involved (sometimes possible with TypeDescriptor.AddAttributes(...), that creates the same form as the runtime wanted to show, but resizes it before showing.
You can achieve this by inheriting from the standard System.ComponentModel.Design.CollectionEditor and then set the desired size in the CreateCollectionForm override.
Decorate your collection to use the custom collection editor.
Below is an example that will start up the collection editor in full screen
class FullscreenCollectionEditor : System.ComponentModel.Design.CollectionEditor
{
protected override CollectionForm CreateCollectionForm()
{
var editor = base.CreateCollectionForm();
editor.WindowState = System.Windows.Forms.FormWindowState.Maximized;
return editor;
}
public FullscreenCollectionEditor(Type type) : base(type)
{
}
}
And then decorate your collection property with [Editor(typeof(FullscreenCollectionEditor), typeof(UITypeEditor))] i.e.
public class MyModel
{
[Editor(typeof(FullscreenCollectionEditor), typeof(UITypeEditor))]
public List<FileModel> Files { get; set; }
}
I'm using WinForms : C# .NET.
I'm facing a problem with ContextMenuStrip and Toolstrip. Visual Stuido's Property editor is not letting me to change the property I want.
Here is the snapshot of how I want my ContextMenuStrip to looklike & same is the case with Toolstrip. I don't understand how to do this.
If I need to learn something, please suggest appropriate good material (tutorials, articles etc.)
alt text http://f.imagehost.org/0289/KproxyChecker.jpg
You'll have to assign the Renderer property to a class that renders the CMS or tool strip the way you want it. Use this code as a template to get started:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
contextMenuStrip1.Renderer = new myRenderer();
}
class myRenderer : ToolStripProfessionalRenderer {
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e) {
// Replace this with your own drawing code...
base.OnRenderToolStripBackground(e);
}
}
}
There is no single property that you can set to make a ContextMenuStrip look like that.
You need to create your own ToolStripRenderer class that paints menus like that, then set the Renderer property of the ContextMenuStrip to an instance of your ToolStripRenderer.
Good luck.
EDIT: You can find sample code here.
I was wondering if it is possible to have a user control open a winform that allows a user to select options on it and then when he closes the form - the options / values he selected are returned to the user control?
Why not create some public properies on your dialog form, and access them from the UserControl once the dialog has been closed?
public class OptionsForm : Form
{
// ...
public string Option1 { get; set; }
public bool Option2 { get; set; }
}
And then, within the UserControl:
public void ShowOptionsForm()
{
using (var form = new OptionsForm())
{
if (form.ShowDialog() == DialogResult.OK)
{
var option1Value = form.Option1;
var option2Value = form.Option2;
// use option values...
}
}
}
Please consider this answer as an "extended comment" on Steve Greatrex's now-accepted answer : it's too long for a comment, and I want to demonstrate a few options, add a few "flavours" to the taste. This is not at all a "criticism" of Steve's answer which, imho, hit the "bullseye."
Assumptions : if I had read the question earlier, I would have queried the OP via a comment on each of these points :
the OP did not specify whether the Form to be "shown" was to be shown modally or not.
the OP did not specify whether the Form was to be re-created each time it was shown, or whether one instance of it should be created and re-used.
the OP wrote "open a winform that allows a user to select options on it ... snip ... "options / values he selected are returned" : Steve's code does not show exactly how the Properties exposed as Public are set, but I'm going to assume that the OP probably intended to mean that the user interacted with some Controls on the shown Form, and that the "options / values" he refers to are Properties of Controls on the Form : like the end-user typing some text in a TextBox, or the selected indexes in a ListBox with its SelectionMode set to allow one of two choices of multiple selection.
the OP does not say if it's desireable that the Form (if used repeatedly) retain the results of the last interactions of the end-user with the Controls on the Form as described above.
the OP says nothing about whether the Form shown by the UserControl has its Parent property set to some other valid container : I'll assume they meant the Form to be displayed "parent-less."
Comments :
if the OP intended the Form to be shown modally : in order for Steve's code to work, the 'ControlBox of the Form would have to eliminated as an option, and a Button put on the Form whose 'DialogResult property was set to "OK," and whose 'Click Event closed the Form : without those conditiions being met the result of ShowDialog in Steve's code would never return "OK," and the properties' values would never be set. Note : closing a Form via the 'ControlBox will return a DialogResult of "Cancel."
re-use of the shown Form : if we assume the Form will probably be re-used, then why not create it once and 'Show and 'Close as necessary ? Let's consider the possibility that there may be good reasons to expose the created Form as a Public member of the UserControl.
Consider the following alternative idea : trying to present a solution as "different" as possible from Steve's : just to demonstrate, explore, the options.
Our "shown Form" will have a TextBox and a ListBox that allows multiple selections : our goal is to expose the Text in the TextBox and the current selection of Indices in the ListBox.
Form has a ControlBox : does not require a Button to close as described above.
it doesn't matter if the Form is shown modally or not : will set properties the same way in either case.
the Public properties to be set are to be based on reading the current state of Controls on the shown Form.
the Form is created once and exposed as Public : because of this a "side-effect" is that when the Form is re-displayed it will retain the previous results of what the user selected, etc. Of course there are other ways you could easily control that in your code to make one or all of the Controls "virgin" again.
in The "shown Form" which we have named 'DataEntryForm :
Just as Steve shows we define public properties to expose ;
public string TextEntered { get; set; }
public ListBox.SelectedIndexCollection LBSelection { get; set; }
In the Form Closing Event we update the properties based on the state of the Controls :
private void DataEntryForm_FormClosing(object sender, FormClosingEventArgs e)
{
TextEntered = textBox1.Text;
LBSelection = listBox1.SelectedIndices;
}
in the UserControl we create a public property of type 'DataEntryform (reason why to be explained)
public DataEntryForm theDataEntryForm { get; set; }
We create an instance of the DataEntryForm in the Load Event of the UserControl and assign it to the public Property
private void UserControl1_Load(object sender, EventArgs e)
{
theDataEntryForm = new DataEntryForm();
}
At this point we will leave it to the OP's (and your) imagination to picture when the instance of the DataEntryForm is shown. But of course we want to demonstrate how you would access the properties after the Form has been closed : so we put a Button on the UserControl :
private void button2_Click(object sender, EventArgs e)
{
Console.WriteLine(theDataEntryForm.TextEntered);
Console.WriteLine(theDataEntryForm.LBSelection.ToString());
}
Note : we didn't do any "fancy" analysis of the ListBox selected indices : but we could have written out whether it was null, or how many items had been selected, etc.
Also : we didn't deal with the issue of what if the OP wants to take some action the moment the "shown Form" is closed : that's so simple : you just subscribe to the FormClosed event of the Form in the UserControl, and do what you need to do in your Event Handler code.
Finally we come to the question of why make a Public Property of type 'DataEntryForm :
Well, just consider that by exposing that "shown Form" via a Public Property in the UserControl : we allow the potential containers (probably a Form) of the UserControl instances to also have access to the values of the Controls on the "shown Form" ... which may be valuable, may save us some duplication of properties.
So, if UserControl1 is on Form1, and Form1 wants to know the Text value of the TextBox on the "shown Form" : it could be accessed like so :
this.userControl11.theDataEntryForm.TextEntered
Edit : A friend of mine wrote me to express his opinion that allowing a "higher-level" container to directly access a "component" embedded in a UserControl was a "violation" of good OOD practicem and breaks encapsulation : he issued me a moving violation ticket :) So, keep his warning in mind. From his point of view the properies should be duplicated in the UserControl with different names, and only those UserControls properties made available to the UserControl Container. My bias is to see the "UserContro/Form" as one "compound object" here, which, since the Form is exclusively used by the UserForm, justifies not duplicating the Properties /Edit
Of course we've left out checking for possibly null values of everything-under-the-sun as we all do so religiously.
here's a short example on how you could do it. It's not complete you'll have to fill in some of the blanks but it should give you an idea of how to solve your problem.
this code goes where you construct your control and you form
MyUserControl ctrl = new MyUserControl();
Action<typeYouPassBack> callBack = myUserControl.FormCallBack;
MyOptionForm form = new MyOptionForm(callBack);
the form class would then have to look something like this: (important part is the action argument)
class MyOptionForm : Form
{
private readonly Action<typeYouPassBack> _callBack;
public MyOptionForm(Action<typeYouPassBack> callBack)
{
_callBack = callBack;
Close += form_Close;
}
privatre void form_close(object sender, EventARgs e)
{
typeYouPassBack postBackData = //populate the postback data
_callBack(postBackData);
}
}
the type Action is simply a delegate with the signature void f(T arg). In the above code it's expected for the user control to have amethod called 'FormCallBack' which of course can be named anything you like as long as you use the correct name when assigning it to the 'callback' variable