Custom UserControl - Design-Time support for control repainting - c#

I have created my custom UserControl with some custom properties for it. For example:
[Description("Example Description"),Category("CustomSettings"),DefaultValue("Transmedicom")]
public string DatabaseAddress
{
get; set;
}
Everything works fine. I can change custom property in code and in design-time.
What I'm looking for (and cannot find anything) now is: How could I repaint (reacreate) my UserControl in design-time when my custom property change in design-time.
Let's say when DatabaseName will be changed to localhost UserControl will add and display some Label on my UserControl. It's important to work in Design-Time.

Nothing special there. You just have to set the text to Label inside the property setter. That should update the UI.
private string databaseAddress;
[Description("Example Description"), Category("CustomSettings"), DefaultValue("Transmedicom")]
public string DatabaseAddress
{
get { return databaseAddress; }
set
{
databaseAddress = value;
yourLabel.Text = value;//Set value to Label or whatever
}
}

Try this
private string _databaseAddress = "localHost";
[Description("Example Description"), Category("CustomSettings"), DefaultValue("Transmedicom")]
public string DatabaseAddress
{
get
{
return _databaseAddress;
}
set
{
if(!string.IsNullOrEmpty(value))
{
_databaseAddress = value;
lblAddress.Text = value;
lblAddress.Invalidate();
}
}
}

Both previous answers are correct.
I just want to add that the user control can even react on resizing during design time, using the Layout event.

Related

Serializing custom control's naming without DesignerSerializationVisibilityAttribute

Problem
I was trying to create a custom control which contains nothing but a label. However, I wanted the label's text to be changed to what the name property of the custom control has received at design time.
This is what my custom control's class looks like:
public partial class Tile : UserControl
{
public Tile()
{
InitializeComponent();
}
[Browsable(true)]
public override string Text { get => label1.Text; set => label1.Text = value; }
}
As you can see, I've overridden the UserControl's Text property in a way that it updates the Label's text too as soon as the Name is updated which in the end did not work. What happened was when I dragged the control from Toolbox to form the label got updated as expected but the moment I build the project, the designer got refreshed and the Label's text was lost.
What I tried
DesignerSerializationAttribute
Going through Google I came upon a solution given at StackOverflow
itself by Hans Passant that using
DesignerSerializationAttribute(DesignerSerializationVisibility.Visible)
can solve the problem as the value the Text property is given will
be persisted in the initialization code which seems valid when it was
getting lost at first (value didn't persisted and lost upon designer
repaint).
So I changed my property like this:
[Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override string Text { get => label1.Text; set => label1.Text = value; }
Doing such change actually solved the issue and now it was working even If I build the project.
What I found
Though my issue got solved but then I started to look for another way
to approach the same result.
While experimenting more with my code I found that If I create
another property that exposes the label's Text property and update
it using the overridden Text property it works exactly what it
was working using DesignerSerializationAttribute.
Here what the new code looks like:
[Browsable(false)]
public string LabelText { get => label1.Text; set => label1.Text = value; }
[Browsable(true)]
public override string Text { get => LabelText; set => LabelText = value; }
I wanted to know that
Why this works (even without DesignerSerializationVisibility):
Text---->LabelText---->Label's Text
I might be asking something very obvious right now but I've been reading about it since hours which made it a bit confusing for me .
If you look at the source code of UserControl, you can see the Text property is marked as not serializable by designer, so basically the value of the property will be lost after you close the form:
[Browsable(false),
EditorBrowsable(EditorBrowsableState.Never),
Bindable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
get {
return base.Text;
}
set {
base.Text = value;
}
}
But in your alternative solution, designer will serialize LabelText property, and later will use its value to return as Text. That's why it works.

Notify when control name changes

I am using Visual Studio 2010 (C#) and have created a user control inherited from a textbox. I need to be able to detect when the control's name changes so that I can execute some other code.
TIA
I believe I have figured out the proper coding. In the code of the textbox user control I used:
private string _name = string.Empty;
public new string Name
{
get { return base.Name; }
set
{
_name = base.Name = value;
CreateLabelText(_name);
}
}
CreateLabelText(string ValueIn)
{
...more code here...
}

Binding ListBox.SelectedItem to Property

This might be a duplicate question, but I'm unable to find a good answer. All the answers like Binding WinForms ListBox to object properties don't work on my WinForm. I'll explain.
I have a list of Firms that I show in a ListBox. I would like when the SelectedItem changes, that it updates a property on my model. So that I can read the Firms properties.
// the classes
public class Firm
{
public string Name { get; set; }
public int Id { get; set; }
// more properties ...
}
public class MyModel : INotifyPropertyChanged
{
private Firm _firm = new Firm();
public Firm Firm
{
get { return _firm; }
set
{
if (Equals(value, _firm)) return;
_firm = value;
OnPropertyChanged();
}
}
// more properties and OnPropertyChanged() ...
}
// the form
private MyModel Model;
public void MyForm(List<Firm> firms)
{
lstFirm.DataBindings.Add("SelectedItem", Model, "Firm",
true, DataSourceUpdateMode.OnPropertyChanged);
lstFirm.DisplayMember = "Name";
lstFirm.ValueMember = "Id";
lstFirm.DataSource = firms;
}
public void lstFirm_SelectedIndexChanged(object sender, EventArgs e)
{
// Do something with Model.Firm
}
The problem is that Model.Firm null is. Does anybody have an idea what I need to do to make a databinding between the ListBox and the Model? I bind other stuff on my WinForm (such as TextBoxes to String properties) and those work nicely.
From what I can see, your code never sets Model.Firm... Where's the constructor for MyModel? If you don't provide one, Model.Firm will stay null unless you explicitly set it. Here's an example constructor:
public MyModel(Firm firm)
{
_firm = firm;
}
Also, Equals() doesn't do what you think it does. Instead of if (Equals(value, _firm)) return;, use this: if (value == _firm) return;
Ok, so after a weekend of testing, I figured it out.
I was debuging in the SelectedIndexChanged event and didn't see the change in my Model.Firm just yet. But as the SelectedItemChanged event is only internal, I couldn't use that and that's where the databinding on SelectedItem applies the values to databound items.
Now the reason why the change isn't visible yet, is because the SelectedItemChanged is only fired after the SelectedIndexChanged is executed. So internally in the ListBox control, it probably looks like
this.SelectedIndex = value;
this.SelectedItem = FindItem(value);
this.SelectedIndexChanged(/*values*/);
this.SelectedItemChanged(/*values*/); // Apply databinding changes
So it's quite normal that you don't see the changes, before the change has occured. And I didn't know this, so I was kinda stumped why the SelectedItem (who was displaying the changed value) wasn't copied over to the databound model property.
So I didn't have to change anything major to get it all working. :)

Update issue with data-bound Listbox and PropertyGrid

This is part of my AOI class (nothing special about it):
class AOI : INotifyPropertyChanged
{
private Guid _id;
private string _name;
private string _comment;
public Guid Id
{
get { return _id; }
}
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public string Comment
{
get { return _comment; }
set
{
_comment = value;
OnPropertyChanged("Comment");
}
}
public override string ToString()
{
if (_name.Length > 0)
{
return _name;
}
else
{
return _id.ToString();
}
}
}
I keep them in a BindingList<AOI> which is bound to a ListBox. In the SelectedValueChanged event of the ListBox I assign the selected object to a PropertyGrid, so that the user can modify the AOI.
This works fine except for the Name field (which is displayed in the ListBox (see ToString() above)).
When I edit the name field using the PropertyGrid, the ListBox is updated correctly. But in the PropertyGrid, the Name field (just the value) is cleared as soon as I press enter. The correct (modified) value appears when I set the cursor to another field in the PropertyGrid.
What is the easiest workaround to handle this correctly?
This is a problem of the PropertyGrid.
This can also be reproduced with the designer within the Visual Studio. Simply select a control and change its minimum size to a larger value than the current one. If you take a look into the grid, the value in the size property won't be updated till you select it within the grid.
If some rows won't update correctly normally one of these two options will help:
Reattach the object to the PropertyGrid by calling propertyGrid.SelectedObject = myObject
Force the grid to redraw itself by calling propertyGrid.Invalidate()

How to access properties of a usercontrol in C#

I've made a C# usercontrol with one textbox and one richtextbox.
How can I access the properties of the richtextbox from outside the usercontrol.
For example.. if i put it in a form, how can i use the Text propertie of the richtextbox???
thanks
Cleanest way is to expose the desired properties as properties of your usercontrol, e.g:
class MyUserControl
{
// expose the Text of the richtext control (read-only)
public string TextOfRichTextBox
{
get { return richTextBox.Text; }
}
// expose the Checked Property of a checkbox (read/write)
public bool CheckBoxProperty
{
get { return checkBox.Checked; }
set { checkBox.Checked = value; }
}
//...
}
In this way you can control which properties you want to expose and whether they should be read/write or read-only. (of course you should use better names for the properties, depending on their meaning).
Another advantage of this approach is that it hides the internal implementation of your user control. Should you ever want to exchange your richtext control with a different one, you won't break the callers/users of your control.
Change the access modifier ("Modifiers") of the RichTextBox in the property grid to Public.
Add a property to the usercontrol like this
public string TextBoxText
{
get
{
return textBox1.Text;
}
set
{
textBox1.Text = value;
}
}
I recently had some issues doing this with a custom class:
A user control had a public property which was of a custom class type. The designer by default tries to assign some value to it, so in the designer code, the line userControlThing.CustomClassProperty = null was being automatically added.
The intent was to be able to provide the user control with a custom class at any point while running the program (to change values visible to the user). Because the set {} portion did not check for null values, various errors were cropping up.
The solution was to change the property to a private one, and use two public methods to set and get the value. The designer will try to auto-assign properties, but leaves methods alone.
You need to make a public property for the richtextbox, or expose some other property that does the job of setting the richtextbox text like:
private RichTextBox rtb;
public string RichTextBoxText
{
get
{
return rtb.Text;
}
set
{
rtb.Text = value;
}
}

Categories