Custom control components setting position C# - c#

I have custom control - using Win Forms, that contains four TextBoxes, all have property to turn them off or on - I just setting visible parameter on them.
I would like to change size and position of the custom control - for example, when I turn off first textbox, I would like to change position of all 3 componets below him, to get them higher.
Of course, I would like to work it with every TextBox - every TextBoxes, below TextBox I am changing position, should change position.
I cant achieve it with changing of Position of TextBox in its own property - I can ask TextBox on top of me, if its property is set to on or of, but it dont works, because I dont know order of setting property in the application.
I can change position of TextBox below me - in the property of Top textbox, but I can do that with only one TextBox below, I dont know and cant find out, if two TextBoxes below are not off and fourth TextBox should be on position of second.
I cant change it by using some variable - when I change it, other TextBoxes dont care about it and they have set their position before.
So do you have any idea how could I achieve it?

The FlowLayoutPanel is designed for exactly this kind of behavior. Place your textboxes inside a FlowLayoutPanel, and then when you set the visible property of one or more of them to false, the other textboxes will automatically move up (or over if that's how you have it set up).

If you want for some reason do it manually, just make a chain of controls.
public class CustomTextBox
{
public CustomTextBox(CustomTextBox previousSibling)
{
PreviousSibling = previousSibling;
}
public CustomTextBox PreviousSibling { get; private set; }
public CustomTextBox PreviousVisibleSibling
{
get
{
if (PreviousSibling == null)
{
return null;
}
return PreviousSibling.Visible ? PreviousSibling : PreviousSibling.PreviousVisibleSibling
}
}
}

Related

Textbox validation: Get control of/duplicate the system validation border?

I'm wanting to validate Textbox entries for an application and provide both visual and verbal feedback in the case of an error. I'd like the normal Textbox border behavior you get from wpf when using ValidationRules or INotifyDataError, then in a separate TextBlock display an error message. Standard stuff. I've got a few ways to approach this but each one is giving me problems.
ValidationRules seems like the easiest system-based approach. My problem here is binding the error message to the separate TextBlock. Most examples use content presenters or error templates, but is there no simple way to bind to a ValidationResult directly? (Question 1)
INotifyDataError being the more modern approach is nice in theory, but it seems wayyy too complicated for what I'm doing.
However, the simplest way I have found is validating directly in the property's setter in the Viewmodel. Something like this:
private string _fileName;
public string FileName
{
get {return _fileName;}
set
{
_fileName = value;
if(String.IsEmptyOrNull(value))
{
FileNameError = "File must have a name.";
}
else
{
FileNameError = null;
}
RaisePropertyChanged();
}
}
private string _fileNameError;
public string FileNameError
{
get {return _fileNameError;}
set
{
_fileNameError = value;
RaisePropertyChanged();
}
}
Then, to show an error, I can bind 2x to FileNameError: Once to display the text in the TextBlock, and the other through a converter (checking for !null) to show the red border around the TextBox.
The problem here the way WPF does the red border is much better; it appears to be its own element rather than an actual border. When I try my StringToBorderBrush converter, the border's thickness reduces the TextBox size, so things no longer line up. The double whammy is that by setting the BorderBrush to transparent, I lose the TextBox's default border and focus border which I'd like to keep.
So is there a way to either duplicate what WPF is doing with the border, or to somehow control it with a property? I would think this would be possible because something has to call it when it is shown with ValidationRules or INotifyDataError, right? (Question 2)

A mandatory label user control in C#

Ok - I just need some ideas here. The scenario is - There are a lot of fields in my windows form which are mandatory to be entered by the user. One of them might be "Name". So for this, I have a label lblName with text Name, another label lblMandatory with text * colored in red which signifies it is mandatory. So that means I have two labels for a field Name, and similarly I have more than 20 fields in my form. I was just thinking of creating a custom label - something called MandatoryLabelControl which will have a * by default after it's text. This would help me in decreasing the number of labels in my form. The custom label is actually a combination of two things - First a text for the label, secondly the * in red color. I searched for this a lot, but can't find anything to start with. Please help with some suggestions.
You have two options - a custom label control or a user control that contains the label and the * based on a Mandatory property. If you have an explicit need to make the "*" red (seems to be the case per your q), you will need to use the user control. This is slightly heavier, so I would recommend rethinking that requirement. Here's how the custom label control would look:
public class CustomLabel : Label
{
public CustomLabel()
{
}
public bool Mandatory { get; set; }
public override String Text
{
get
{
return base.Text + " *";
}
}
}
You would now use the CustomLabel instead of the Label.

Design Surface override enabled property of a control

I have a little application that implements a DesignSurface as well as a propertyGrid. The propertygrid watches for a property attribute "IdeAccessable". For each property to become availdable I override the base property and add this attribute.
public class MyButton : Button {
[IdeAccessable()]
public new int Height { get { retun base.Height; } set { base.Height = value } }
[IdeAccessable()]
public new int Width { get { retun base.Width ; } set { base.Width = value } }
[IdeAccessable()]
public new bool Enabled { get { retun base.Enabled ; } set { base.Enabled = value }}
[IdeAccessable()]
public new bool Visible { get { retun base.Visible ; } set { base.Visible = value }
}
This works fine for all, but for Enabled and Visible. These two property seem not to be delegated during the "Design Time" and have no effect what so ever. During serilization the keep their default / base value. How to override enabled & visible that the work at design time / are delegated properly?
Details:
The DesignSurface is used in a standalone application written in c#. The designsurface is attached to a standard WinForm which is the base-design-surface. Items are placed by the user via the ToolBoxService. The Controls are mostly default winform-controls like buttons, labels etc. To control the amount of visible items which are shown via a PropertyEditor attached to the DesignSurface-Services, all controls have been derived (see example) to flag the properties with the custom IdeAccessableAttribute.
When these layouts are serialized during save or execution, all controls & components are represented in a script language (lua). During this serilizaion process (essentailly a loop over all children lying on the form) every control is touched and every property flagges with the IdeAccessable attribute is saved. During debugging I found that, as explained, that values like enabled and visible are not beeing set despite the property editor shows the correct value. This results that a component disabled during designtime is enabled during my own runtime. Another effect is that the property editor settings for the visible property allways is false. Changing it in the property editor shows the correct value but is never applied to the real value.
A possible solution might be:
to prevented this with a fake design time value that is transported manually.
The problem with this solution:
Due to the controls not having a shared base class the parts in question would have to be rewritten for every derived control individually which would result in a lot of redundant code. Not derived controls aren't anymore possible. Any change to the logic would mean that it has to be changed in about 50 classes. Also implementing new controls would result in much more work than nessary.

Winform Custom Control: Why Setter not called when used from Constructor?

I have an initial value property like this:
[Category("Main")]
[Description("Intial Value")]
[DefaultValue(10)]
public int InitialValue
{
get { return m_initialValue; }
set {
m_initialValue = value;
this.TrackBar.Value = this.m_initialValue;
}
}
So in my constructor I do this for example:
this.InitialValue = 10;
To my surprise when dragging the custom control on a form the setter is not called so that my trackbar value is not synchronized.
Why ?
Only when I change the property in dialog box the setter is called.
I decided to take your advice as suggested in one of the comments:
You can try by yourself will take 2 minutes.
So I did (it took about 3 minutes), and I was unable to reproduce the behavior that you described.
Here are the exact steps that I followed:
Created a new Windows Forms Application.
Added a new User Control to my project.
Opened the new User Control in design view and added a TrackBar control (leaving the TrackBar control's properties all set to their defaults).
Added the following code to the User Control class (exactly the same as you posted above, with the addition of a private field m_initialValue that you omitted from the original example):
public class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
this.InitialValue = 10;
}
[Category("Main")]
[Description("Intial Value")]
[DefaultValue(10)]
public int InitialValue
{
get { return m_initialValue; }
set
{
m_initialValue = value;
this.trackBar1.Value = this.m_initialValue;
}
}
int m_initialValue;
}
Built the project.
Opened the default Form (Form1) that was created with the new project in design view.
Dragged the User Control that I had just created (UserControl1) out of the toolbox where it was automatically placed and onto the surface of the form.
The indicator on the slider bar appeared all the way to the right side (the correct and expected position given the default Maximum value of 10). Now, you tell me: What are we doing differently?
Try adding [Browsable(true)] .
The key portion of your question is here:
when dragging the custom control on a form
You're still in the designer, and the designer cheats a bit to render things. Does this still happen when you actually run the application?

How to refresh a winform custom control at design time after changing a property

Let's say I create a custom control which embed a trackbar. I also create an orientation property for my custom control.
When I drop the custom control on a form by default it will be horizontal. Then I set it to vertical, the trackbar should refresh to be vertical at design time.
How to do so ?
I think you should call Refresh() after changing the value:
public OrientationProperty Direction
{
get
{
return _direction;
}
set
{
_direction = value;
if (DesignMode)
{
Parent.Refresh(); // Refreshes the client area of the parent control
}
}
}
private OrientationProperty _direction;
Here's my solution to this issue:
1. Whenever you set something property, call Invalidate() in the setter.
2. After correspondent properties and refreshing method (for eg. overridden OnPaint) are implemented, rebuild!!! then you'll see the modifications taken effect in design time
3. During design, always check whether compilation errors are present, as this might stop VS performing all his tasks.
With this, when I put my control on a form, and adjust its own properties, refreshing happens immediately as expected.
PS.: old post, but at least verified the behavior in VS2015 too :)

Categories