User Control Label and Textbox flow from right to left - c#

It was pretty tough to think a title for this question so I'll try to make a better job explaining myself here.
I needed to create a dynamic Windows Form so that when checkbox gets checked/unchecked, few input fields appear/disappear. As far as I know FlowLayoutPanel seemed to be the best tool to achieve this. So I created a Custom User Control that included a Label and a Textbox. I designed this new Control in VS2013 desginer view:
Since the text on the label can vary in length it is important that textbox begins only when label has already ended. However the result I get at the moment looks like this:
The label should read out "ConnField" instead of "ConnFie". I tried adding these items in FlowLayoutPanel but that resulted in label and textbox not lining up correctly. Are there any attributes/properties that should be set in order to get the expected result? Should I use a container that does it all for me?
On a side note, if there are any other methods to dynamically show/hide elements in the fashion I described above I'd be very happy to use those instead.

For perfect fits you can script the TextChanged event(s) to make sure the TextBox always sits in place and keeps a nice size as well..
I have placed a Label and a TextBox into a Panel for testing. You will probaly not need or want the textBox1_TextChanged event but it was nice for testing..:
private void textBox1_TextChanged(object sender, EventArgs e)
{
label1.Text = textBox1.Text; // this is for testing
}
private void label1_TextChanged(object sender, EventArgs e)
{
textBox1.Left = label1.Right + 6; // <= this is what you need
textBox1.Width = panel2.Width - label1.Width - 8; // <= this is nice to have
}
Of course your offsets may vary..and obviously the Label has AutoSize = true
Edit
Since you commented on the problem of getting the TextBoxes aligned with each other across rows here are a few thoughts about this problem. As Hans noted, you can't have it all:
Complete freedom for the Labels' content
Perfect fits
And aligned Textboxes
The three goals conflict. So you need to make compromises:
If you can restrict the content to a fixed maximum, the result will look best
Sometimes it helps to have a collegue or even a user look at the content to find a shorter way to express the meaning
Ellipsis or abbreviations may help. I both cases you should set a ToolTip to show the full content
Another option is to switch to a narrower Font for some Labels
Instead of one fixed Label size maybe 2 or 3 will help: The look will be a bit jagged but will look a lot better than with completely free sizes.

Related

Split Windows with panels

I'm reading a Windows Forms book and I came to one example which is pretty confusing to me.
Here are two pictures, the first is the initial state, and the second is when the user click the Hide button.
This form contains two split containers, one horizontal, and one vertical, which is in the right panel of horizontal one.
The book says:
One of the best characteristics of docked designs is that they easily accommodate hidden
or modified controls. To implement
this design, two panels are placed in the left region of the
SplitContainer, one named pnlFileList and the other named pnlShow.
However, only one of these panels is shown at a time. The contents of
the rest of the window automatically resize themselves to accommodate
the additional view when it is displayed
private void cmdHide_Click(object sender, System.EventArgs e)
{
splitContainer1.Panel1Collapsed = true;
pnlShow.Visible = true;
}
private void cmdShow_Click(object sender, System.EventArgs e)
{
pnlShow.Visible = false;
splitContainer1.Panel1Collapsed = false;
}
And I made it, but the problem is with the button which appears when the left panel of the SplitContainer is collapsed.
I don't know where to put the panel "pnlShow"
If I put it on the right side of the horizontal SplitContainer control, it will disappear also.
Any suggestions?
The quote from the book doesn't seem accurate to me. You can't place pnlShow inside the "left region" of the SplitContainer because it will not be visible once you set the Panel1Collapsed property to true.
Instead, you can place the pnlShow on the left to the SplitContainer and set its Dock property to Left. Also, you don't seem to actually need a Panel in this case since it only contains one Button. You can simply use a Button only. Anyhow, your form would look something like this in design-time:
Then, your code should work fine.
Some remarks:
Of course, if you decided to use a button without a panel, you'd need to use YourButtonName.Visible instead of pnlShow.Visible.
If you found that the button (panel) on the left covers the SplitContainer, you just need to right-click on the SplitContainer and select "Bring to front".
It's preferred to use "btn" as a prefix for the Button name instead of "cmd". The latter was kind of widely used in the classic visual basic language, because it used to be called CommandButton. In the .NET world, the standard is to use "btn" instead.
Finally, based on what I mentioned in the last point above and the look of the screenshots in your question, this book seems to be quite outdated and was written based on the early versions of the .NET framework, so unless you have to study this book specifically, I would recommend you find a more recent book or tutorials.

Drag and drop event. Get the name of the control where the drag originated, whilst inside drop event method

I am attempting a drag and drop in WPF.
My program allows you to drag coloured labels around the screen, in essence giving you the effect that squares are being dragged and dropped.
Bearing in mind that only the text is dragged rather then the control itself (i.e. not the colour):
What I would like to achieve is that when the drop event fires, I can change the colour of the label which I dragged the text from.
After consulting MSDN I've failed to figure out how to get at the control in question and after plenty of trial and error I'm hoping somebody here can help. https://msdn.microsoft.com/en-us/library/system.windows.forms.drageventargs.data(v=vs.110).aspx
Below is a sample of code which works, but the label who's colour I want to change is hard-coded, whereas in reality it could be any one of a number of labels.
private void ObjDrop(object sender, DragEventArgs e)
{
//testSquare is a hardcoded label
testSquare.Background = Brushes.LimeGreen;
//what I really need is for a variable to detect which label to access each time before I change its colour. So something along the lines of
Label myLabel = someCodeToGetTheLabelThatWasDragged;
myLabel.Background = Brushes.LimeGreen;
}
Hopefully I explained things well enough, thanks in advance.
You would use the IDataObject.GetData(Type) method to extract the the object in DragEventArgs.Data property. From there, you should be able to access whatever you store in the IDataObject.
This is a pretty general answer. To achieve said answer, that means you'll have to write your own class that implements IDataObject which contains the original control/control's name etc., then set the IDataObject when drag in initialized.
There may be an alternate solution available. I would watch what e.Data is in your current example, and try to work with that. If e.Data is of type Label, through casting, you could access the label that way, e.g. (e.Data as Label).Background = Brushes.LimeGreen;.
In a Drag and Drop implementation I've seen, the IDataObject contains the DropTarget and the DragSource, that way you can compare the two and allow/disallow things/types from being dragged and dropped by setting the Effect.
This page provides the solution for what i'm looking to do.
WPF Drag and Drop - Get original source info from DragEventArgs
The following code in particular used in the drop event method allowed me to achieve my aim
Label lbl = e.Data.GetData("System.Windows.Controls.Label") as Label;
After that I could manipulate the source of the drag whatever way I wished.

Create filter for dynamically inserted image text

I want to create filter insert text in my simple image editor program
based on this nice article. I found out how to do it, but I need some configure.
I make insert text more dynamic, just like Photoshop or Notepad. User click add text icon, cursor change and when user click on canvas that will be position for text. I already found this solution by mouse down event to get x & y screen coordinate.
I wanna make after (1), program will create something like textbox (minus background & border) so user can type text on it where in tutorial text is static.
I don't have idea how to do this, can anyone give me suggestion or example maybe?
Update
i really don't have any idea how to make this question more clear, spesific, or etc
i already try to divided what i want to 2 problem and solved one of them
i know if there is not just single method to archive what i want...but i don't know if there will be triple many (many many many) way to do it, so i must write spesific method i wanna use...
how can i know which one i will use if i even don't have any idea one of them....
in my mind just come dumb way create custom textbox with no background & border
Code
//set flagText active or not
private void InsertText(){
if (flagText){
flagText = false;
imageBoxCamera.Cursor = Cursors.Default;
}
else {
flagText = true;
imageBoxCamera.Cursor = Cursors.IBeam;
}
}
//in mouse down event i wanna create something like textbox (minus label & border) with coordinat x & y from mouse down
private void imageBoxCamera_MouseDown(object sender, MouseEventArgs e)
if (flagText) {
MessageBox.Show(Cursor.Position.X.ToString() + " " + Cursor.Position.Y.ToString());
}
}
Take a look on OpenPDN source code(fork for Paint.NET).
As I know there is a similar function there
https://code.google.com/p/openpdn/source/browse/#hg%2Fsrc

Add and read Multiple textboxes

What is the best way to create and read multiple textboxes in a windows form? In my application, I have a windows form where customer can enter multiple addresses, email addresses
Right now I have a form like this,
TextBoxAddress1 TextBoxEmail1
TextBoxAddress2 TextBoxEmail2
.....
.....
.....
TextBoxAddressN TextBoxEmailN
For this I dragged and dropped multiple controls on a form and named each one of them.
If I use this method I had to write lengthy code to see if first row (TextBoxAddress1 TextBoxEmail1) is filled for validation and even for reading I had to write many lines of code.
Is there a better to way achieve this?
You can use the following code to add a TextBox dynamically to your form:
private int m_CurrTexboxYPos = 10;
private List<TextBox> m_TextBoxList = new List<TextBox>();
private void CreateCheckBox()
{
m_CurrTexboxYPos += 25;
TextBox textbox = new TextBox();
textbox.Location = new System.Drawing.Point(0, m_CurrTexboxYPos);
textbox.Size = new System.Drawing.Size(100,20);
Controls.Add(textbox);
m_TextBoxList.Add(textbox);
}
I would have a listbox/listview with your emails and Add/Edit/Delete buttons which show a popup form - the logic for validating emails, etc. would then be in the one place and your list can grow without you ever needing to add controls to the form.
You could dynamically create textboxes - but you end up writing code to make sure they layout nicely on the form, etc. - having some type of list is easier IMO and also lends itself to binding (e.g. to an email object)
Dynamically adding controls is pretty simple, provided you can use DockStyle and an exclusive container for them (e.g. a Panel). If you can't use DockStyle, then you need to write logic to determine Location and Size (which isn't fun).
On a simple form, I have two buttons and a panel, Button1 adds a new TextBox to Panel1, Button2 iterates through the controls in Panel1 and then checks that they are the correct type or throws an exception. This is where you you would put validation or reading logic. Panel1 needs to have AutoScroll = true; otherwise you will run controls off of the viewable screen.
This concept can be switched for anything that inherits from UserControl (all .Net native controls or your own custom controls).
private void button1_Click(object sender, EventArgs e)
{
TextBox NewEmailBox = new TextBox();
NewEmailBox.Name = "NewEmailBox" + this.panel1.Controls.Count;
NewEmailBox.Dock = DockStyle.Top;
this.panel1.Controls.Add(NewEmailBox);
}
private void button2_Click(object sender, EventArgs e)
{
foreach (Control item in this.panel1.Controls)
{
if (item is TextBox)
{
//Do your reading/validating here.
}
else
{
throw new InvalidCastException(string.Format("{0} was in Panel1 and is of type {1} not TextBox!", item.Name, item.GetType()));
}
}
}
Write a user control for each of the groupings you need. at least one One for address, one for email etc. then all of your validation, calls to your database access is contained in a single location
That is just good design. this way if you have multiple tabs for things like Home Information, Work Information, Emergency Contact Information, you can just place them on the form. This is pretty common for a user profile.
Then a listview for each grouping on a user profile page or whatever, that has edit/delete/add then popup a dialog with the appropriate user control in it.
Most simply, ListBox adove TextBox with Button.
Also you can use DataGridView, BuiltIn functionality for Add\Edit\Delete.
Here using DataGridView (ShowHeader set to false, EditMode to On Enter, with one Column with AutoSizeMode in Fill property)
The less of repeatable code you have, the better programmer you are.
Whenever you see a pattern (something what is repeatable), you could and you should try to optimize it. Unless it's something too small to worry.
In your case, determine first what is the basic of repeatable thing. Do you always have to enter address and email address? Then combine them into a control, which can carry out validation. Do you have to use this control often (or repeat N times)? Then maybe it make sense to switch to a list instead (ListBox, ListView or DataGridView).
Are you too lazy to bother configuring things? Then just optimize something what is obviously going to repeat: put validation into common method and call it from each TextBox event. Or make own TextBox with method build-in. Or do validation at once in the Ok button event by using loop.. or not by using loop.
To find best method you have to first decide best for who. Because customer want something shiny,easy to use, animated, with cats and boobs.. ok, without cats and boobs. The point is: how much work are you willing to put to have it best for the customer.
If I would have to enter table data (or data which form table), I'd go with DataGridView so it would looks like this.. or better:

how do I make my application as fast as windows explorer for rendering files

I have a folder with a large amount of files inside of it. I want to be able to render each of my files as a button. And when I click on the button something will happen.
private void Form1_Load(object sender, EventArgs e)
{
int x = 10;
int y = 10;
/// Process the list of files found in the directory.
string[] fileEntries = Directory.GetFiles(#"c:\lotsofDocs");
foreach (string fileName in fileEntries)
{
// do something with fileName
Button newbotton = new Button();
newbotton.AutoSize = true;
newbotton.Text = fileName;
panel1.Controls.Add(newbotton);
newbotton.Location = new Point(x, y);
x += 150;
if (x == 760)
{
y += 50;
x = 10;
}
}
As you can see there's nothing crazy in the code. I have a panel on a form and I've set auto scroll on the panel to true and auto size to false. This causes the form to maintain size and the buttons (some of them anyway) to get rendered off the form and I can scroll down to them.
All good so far.
If I have 100 or 200 file everything is ok, if I have 1932 files it takes about 10 seconds to render all the buttons.
I've read the follow question Super slow C# custom control and I understand that the approach I'm using might not be the best to use here.
And now the question at last:
how does windows explorer handle this? If I open this folder in Windows explorer it opens instantly.
What type of control is windows explorer using? Or is it doing it in a completly different way to me.
Thanks
Very long lists of controls are usually implemented via virtualised controls. That means that if only 20 buttons fit on the screen it only creates 20 buttons or so. When you scroll around it reuses the same 20 buttons with new data in them.
Controls can be very slow to create and manage in large numbers as they are usually added to a simple list or hierarchy (and are quite complex individually).
Better off managing a smaller set of buttons yourself to show a very long list of data. More work obviously, but the end result is lightning fast compared to the "simple way".
If you don't want to DIY, try a third party control. As an example the Telerik virtualised Tree, List and Grid controls can display a million records with no slowdown. Take a look at their Winforms grid here
You should look at the ListView. It provides the same basic set of functionality as the file area in Windows Explorer with comparable performance.
Make sure to call BeginUpdate before adding your items and EndUpdate when you are done for the best performance. Adding your items with Items.AddRange is also good for performance.
Can you allocate all the buttons at once? What I mean is, create an array of buttons after you read the file names (so you know how many buttons to create), then simply set their properties in the loop. I don't know how much that will speed things up, but it's worth a try. You might also see if there's an override on the panel's Add method that takes an array or list of controls and add them all at once, too.
One trick that often helps improving slow contruction / change operations is to hide the controls and / or the parent container involved. In your case, that would mean hiding panel1 before creating the controls, and showing it again afterwards. Might not help a bit in your case, but it's worth a try.
However, you will have fundamental problems creating so many controls in Win32 or WinForms. While the Window System now can handle these, it's not the thing tries to be good at.
It is also not the best user interface for that. 2000 Buttons in a 5 x 400 matrix? Holy effin' cow. I don't want to use that. What do you do if a file name does not fit 150 pixels? What do you do on displays where "150" means ".15 mm"?
Alternatives
Why not a list control? That at least has page up / page down, and type ahead to find items starting with the text I enter. Throw in a "quick filter" edit control on top of it, where where entering some text filters out any files that don't contain it, and you have a standard interface that can be used efficiently. If you expect many items, you can put the LitView control into virtual mode. While this loses some built-in features (e.g. autosizing columns), it works with insane numbers of items thrown at it.
You could also render the buttons as HTML links, and show it inside a browser control. That's not necessarily faster, but HTML renders progressively, I can use the list while you are still feeding items.

Categories

Resources