C# Label Properties won't update upon resize - c#

I recently started getting acquainted with Visual Studio 2010 and C# for an internship. C# doesn't include a built-in InputBox function, so I made my own form, with a text box, two buttons and a simple label.
I have a function set up to allow the programmer to call the form in regular format (where the user enters input via the textbox) or yes/no format (where the form just displays a question and the yes and no buttons).
When I switch over to yes/no format, I want to center the label programmatically. I've been using the code:
labelNote.Left = inputBox.Left + (inputBox.Width / 2) - (labelNote.Width / 2);
This should put the center of the note in the center of the form. However, if the contents of the label change (making the new label longer or shorter) the properties don't update to reflect the new size. It won't center unless it includes the original text. Is there some way to force an update? I foresee this becoming a problem with positioning objects for scalability in the future.
Thank you for your time

I'm assuming you have the sizing within an actionlistener. Specifically the forms' resize action listener. Then whenever the form is resized it is called and all of you code is recalled. Then to force an update from somewhere else you just have to call the actionlistener.
Actionlistener:
Private Sub formName_Resize(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Resize
Calls actionlistener:
formName_Resize(sender, e)

Well, you could attach an event to Label.TextChanged. Frankly it would be better to change the TextAlign or something like that though: try to perform the layout in a declarative fashion instead of doing it explicitly through code. That tends to make things work rather better.
I've found the [TableLayoutPanel]1 control to be reasonably easy to work with - most of the time (and occasionally a complete pain).

It turns out that I made a stupid mistake (a common theme for me in debugging. The really small stuff goes unnoticed for the longest amount of time).
The label resizing was not the issue. The issue was the order in which I changed the contents of the label and then called the function to calculate its new location. I was calling the location calculation first, so it found where to center the label based on the old contents. I didn't notice for so long, because the text was changing properly. I took it for granted that the functions were being called in the correct order.
So, when it doubt, check the order in which you're writing your code. Thanks for you help anyway, everyone. I ended up finding out some neat things that could be applicable to other scenarios (such as the MeasureString function in the Graphics class).

Related

How do I avoid having my Rich Text Box, "scroll bar," freeze up?

My issue is in the .NET framework using C# to create a simple form application that contains a rich text box (RTB) control.
Briefly the issue I am experiencing is that when trying to clear the contents (.Text) of the RTB, the scroll bar doesn't go away. I would like to know if there is anything inherently wrong with the way I am using the RTB. I apologize, but the site will not allow me to post images yet. So if there is a misunderstanding regarding what "doesn't go away" means, please ask!
So first, I write data to the box using the following code snippet:
// append the new message
this.rtb_receive_0.Text += message;
this.rtb_receive_0.SelectionStart = this.rtb_receive_0.Text.Length;
this.rtb_receive_0.ScrollToCaret();
Later on, I clear the RTB contents (RTB.Text) with the following code:
this.rtb_receive_0.Text = String.Empty;
this.rtb_receive_0.Refresh();
In the above code I have attempted to fix my problem with the, "Refresh," method. However it does not seem to be doing the job.
When I clear the RTB contents, the scroll bar does not go away... I noticed that if I grab another window and drag it over the top of the application, that the frozen scroll bar disappears. Also, I can minimize the application, then maximize it again and the bar will disappear. There has to be a way to prevent this frozen scroll bar from happening in the first place though.
Per the answer, here was the fix to stop the bar from freezing up:
this.rtb_receive_0.Text = String.Empty;
this.rtb_receive_0.Clear();
this.rtb_receive_0.ScrollBars = RichTextBoxScrollBars.None;
this.rtb_receive_0.ScrollBars = RichTextBoxScrollBars.Vertical;
this.rtb_receive_0.Refresh();
Have you tried simply just programatically setting the Scrollbars property on the RTB?
myRichTextBox.ScrollBars = RichTextBoxScrollBars.None;
Edit: I think I misinterpreted what you needed. Searching around, I found this similar post on another forum: http://www.vbforums.com/showthread.php?793671-RESOLVED-RichTextBox-Visual-Bug
This user is setting the value of an RTB based on a selection in a list view. When a new value is set and does not require a scrollbar it doesn't re-draw and still shows the bar.
It seems like adding myRichTextBox.Clear(); myRichTextBox.Refresh(); should help. In this case that user is also programatically setting the ScrollBars property as well.
Also, are you able to determine how many lines of text can fit in the RichTextBox before a scrollbar is needed? I suppose that might vary based on system settings on the machine, but you might just be able to programatically check myrtb.Scrollbars = (myrtb.Lines.Length > X) ? Vertical : None; (excuse the psuedo code syntax)
What helped for me was just calling the refresh() method twice. Very ugly, but it does the job.
Hmm, after more thorough testing this ugly fix proved to be not so much of a fix afterall. It helps, but still some glitches.
refresh();
update();
seems like a better solution.
I was having this same problem. I solved it by calling the Invalidate() method which forces the control to repaint.
Me.RichTextBox.Clear()
'Call Invalidate in order to force the RichTextBox to repaint. I do this so that any
'Visible Scroll bars are removed after clearing the Text
Me.RichTextBox.Invalidate()
I tried with Refresh(); Update(); Invalidate();,but it didn't worked for me.
I solved this problem using following three lines :-
RitchTextBox.Clear(); //Clearing text in RichTextBox
RitchTextBox.ScrollBars = RichTextBoxScrollBars.None; //Remove scroll
RitchTextBox.ScrollBars = RichTextBoxScrollBars.Vertical; //Again add scroll
Try those above three lines. It will work 100%.

Multiple forms one windows C# possible or only panels/usercontrol?

So here's my Question, I'm new to C#(teaching my self at that) Here's the thing, I'm working on a basic sim game, nothing to complex but I've got the design and basic functions done.
However In order to implement it, I'm currently using multiple Forms(Visual Studio 2013)
I have my "main" form which has the "action" buttons to it
So when i want to go to a user Profile page I have
Btn_profileview Click(object sender, EventArgs e){
Form profile = new Form();
profile.Show();
}
The User would then implement the changes(for instance change name) which is written to a text file, for use in other areas of the program.
However It opens a new windows, I've tried modal and nonmodal windows and while the benefit of Modal so they have to actual close the window solves the issue, i'd rather have it just overwrite the preexisting Form, and then on close go back to the "main" screen without actually using multiple windows.
Now I was told UserControl and/or Panel would solve the issue, but it would cause a complete redesign moving from the multiple forms to the multiple panel screens and figuring out how to get those to work(Visible and Invisible), i'm assuming it wouldn't be extremely difficult something along the lines of Panel"name".show(); and panel"name".close();
But would it be possible to actually add a line of code to the pre-existing code(so as not to cause a complete reesign) or are Panels and UserControl the only real way to implement within 1 continuous windows?
paqogomez is right: There are many ways to do it.
Here is one that combines a lot of the pros:
You create an invisible Tab on your window with as many pages as you need. Place a Panel on each tab and create all your controls on of them. This does not mean that you have to do it all over - you can move and drop the controls you already have without much hassle. Of course you need to turn off docking and maybe anchors, but other than that this is a simple process.
If you have controls on the 2nd form with the same name, these names should be changed to something unique though. I hope all Controls have proper names already, but especially Labels get neglected, at least here.. (With a little luck you can even use cut and paste to get Controls from another form to panel2!)
The big pro of this trick is that you can do all work in the designer of the same form. The Tab control serves only as a container where you keep your panels without adding to the UI and without giving the user control of what is shown.
Next you create one Panel variable in your main form:
Panel currentPanel;
On Load you assign the first 'real' Panel to it like this:
currentPanel = panel1;
this.Controls.Add(currentPanel);
Later, each time you want to switch, you re-assign the panels you need like this:
this.Controls.Remove(currentPanel);
currentPanel = panel2; // or whichever panel you want to show..
this.Controls.Add(currentPanel );
If your real panels are docked to fill the tabpage, as they should, the currentPanel will fill the form. You still have access to each panel and to each control by their names at any time but you see no overhead of tabs and your form never changes, except for the full content.

Follow-Up: Finding the Child of a Control

I believe the proper term is recursively. I have a Windows Form, and inside that I have a Tab Control, and inside the Tab Control are four Tabs, and inside each tab are multiple controls - Buttons, text boxes, etc. I want to change the cursor of every button to a type hand.
Below is where I have gotten so far with this inquiry:
foreach (Control c in tabControl1.Controls)
{
// The only controls that will be found here are the tabs themselves. So, now I must run a *foreach* loop through every tab found, and look if buttons are present.
}
The commented area explains my issue to some extent. I have found an example of a recurisively finding a control on a form but I am not sure why I would need to pass the contro's name as an argument as I am trying to find Every control of type button.
Here is the code that I found online:
http://www.dreamincode.net/code/snippet1663.htm
Thank you once again. I love hearing from all of you as it's an excellent learning experience for me.
Thank you very much for your time.
private void FindAll(Control myControl)
{
if (myControl is Button)
doStuff();
foreach (Control myChild in myControl.Controls)
FindAll(myChild);
}
I believe this will work. When you call it the first time, you'd pass in the form. The form isn't a button, but it will have children. Each child it has will be passed into FindAll(). If that control is a button, it will call doStuff() (you can set the cursor in there). Likewise if that control has any children, they'll be passed in.
You are correct, the term is recurisve (generally speaking, any function or sub that calls itself). So, in this example FindAll() will call FindAll() in a certain case.
Also, this is just sample code; you may want to check for null references depending on the nature of your application.
EDIT: Just as an FYI if you aren't familiar with recursion, it's pretty easy to get the dreaded StackOverflow exception. When you end up in a never-ending loop of calling yourself, you'll run out of stackspace and see the StackOverflow exception. Hence, the name www.StackOverflow.com
In this case, we don't have to worry because .NET prevents us from adding controls that create a circular reference. For example - this code will fail:
GroupBox g1 = new GroupBox();
GroupBox g2 = new GroupBox();
GroupBox g3 = new GroupBox();
g1.Controls.Add(g2);
g2.Controls.Add(g3);
g3.Controls.Add(g1);
I don't know if any of this makes sense, but hopefully it helps. Recursion is generally considered one of the 'harder' concepts to grasp for a lot of people. Then again, I'm not very good at explaining things.
You are correct that the correct term is recursion. In the link you have posted, it is indeed recursive because the function calls itself, which is a property common of recursive functions.
The function needs to take a Control instance because the function is trying to solve the problem "For a given control (which is the Control container that is passed in), find all controls inside." Notice how this method doesn't care about what 'level' the control is at, it can solve it regardless.
You are correct that if you ran the code in your example, it would not work. It would only pick up controls one level inside of the 'parent' control. This is why the function needs to call itself.
With the function calling itself, you get the following:
Call function with the outermost control.
Do I have any children?
If so, call the same function again for each child (which will again ask "Do I have any children?" on the child).
By calling the function inside the function, you will hit all levels.
WARNING: Just as a note of caution, recursion used carelessly can lead to problems. If you apply this on something that has 1000 'levels', your algorithm will take forever and possibly crash as you will run out of memory to handle it, since it is digging deeper and deeper (a stack overflow!). Separately, I suspect there is a better way to do what you are doing such that you don't need to use recursion, although it will work.
Hope this helps!

Speed-optimise a Windows Forms application

How do I speed optimize Windows Forms applications?
I am not talking about apparent .NET optimisation techniques - like NGEN-ing, caching objects, etc. I already tried that and what I am up to is to reduce the form initilization time from a 1500 msec down to 500 msec.
Profiling has identified the slowest code and almost all of it is in the InitializeComponent, and within this method the slowest lines is
creation of the (just new-ing) WebBrowser component
loading icon from a resource (hideous 500 msec)
creation of the ContextStripMenu
several this.Controls.Add() calls contribute a lot too.
At the moment, I can only see how to fix point (2) - move icon data from being stored as embedded resource to a private field (for example, Base64-encoded string).
What what should I do with points 1, 3 and 4?
Load the icon in a separate InitializeComponentAsync thread.
The only thing I can think of that you could do is rewrite the controls that you want to use and optimize them to initialize faster (as well as the Form class to optimize adding the adding of the controls to the form).
I can't see how that is feasible though, and I think you are going to be stuck with this, depending on your reliance on these controls.
One technique I have used in the past was to multi-thread the data load, so that it runs simultaneously to the form creation. In this instance data was being loaded out of AD, it cut about 1/3 of the load time.
I have changed the strategy of form loading, this will make a great change on form load timing, now it's taking an average of 37 ms instead of 466 ms.
Method: On First time Click on Top-tab/Icon, application load all form under that tab/icon and on click on Form Icon it will only switch visibility. And again visit on Top-tab will not load the form under that tab.
Just take another class like ClsAppearance.cs as I taken.
Initialize all controls like
static Infragistics.Win.Appearance txtBoxMidAppr = null;
I take my own name like txtBoxMidAppr instead if the appiarance1. due to it can be use for all textbox, by only once initialization.
Make a function where we can initialize the appearance and call it on the MDI/Main form loading only once.
public static void LoadAll()
{
txtBoxMidAppr = new Infragistics.Win.Appearance();
}
Make another function here and take the appearance code from designing window
public static Infragistics.Win.Appearance App_txtBoxMidAppr //text_box_small
{
get
{
txtBoxMidAppr.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(93)))), ((int)(((byte)(93)))));
txtBoxMidAppr.ImageBackground = global::CS_POS.Properties.Resources.text_box_small;
txtBoxMidAppr.ImageBackgroundStyle = Infragistics.Win.ImageBackgroundStyle.Stretched;
txtBoxMidAppr.ImageHAlign = Infragistics.Win.HAlign.Right;
return txtBoxMidAppr;
}
}
In the designing code of the form, comment all appearance setting of the text box and put the function name for getting appearance from the ClsAppearance.cs class
//appearance4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(93)))), ((int)(((byte)(93)))));
//appearance4.ImageBackground = global::CS_POS.Properties.Resources.text_box_small;
//appearance4.ImageBackgroundStyle = Infragistics.Win.ImageBackgroundStyle.Stretched;
//appearance4.ImageHAlign = Infragistics.Win.HAlign.Right;
this.uteNABoth.Appearance = CS_POS.App_Appearance.ClsAppearance.App_txtBoxMidAppr;
take all controls appearance and make a function in the class and call it from there.
So the appearance initialization will goes only once and can use many time.
Can you do lazy loading for your Webbrowser control? If it's in a tab which is not the main view then you might load webbrowser when that tab is activated.
Or you might load the form and then load the webbrowser (this might help you to show something first and then show everything, just like you'd do in a website).

.Net C# Design View errors

I have subclassed a Treeview and on instantiation it loads a new ImageList (and the associated Images).
Whenever I switch to the designer view, it's also trying to run this code, however the images aren't in the designer's path, so it crashes. I ended up putting in a hack to see if the current directory is "Visual Studio", then do nothing... but that's so ugly.
I find this happening for other things. If a control is trying to use objects during load/initalization that are only available while the program is running, then the Design View cannot bring up the control.
But is there a way to get around this?
I guess what I'm hoping for is having a try/catch for the Designer (only) with the ability to ignore a few errors I know will be happening (like FileNotFoundException, etc.).
Thanks
Everything that inherits from System.Windows.Forms.Control has a DesignMode property that returns a boolean indicating if you are in design mode or not. You could use this to determine when to/when not to load external resources.
Usually it is better to move the loading of these resources to an override of OnLoad as they are rarely required directly at construction. This fixes the issue you are seeing and means that only trees which get displayed at least once will perform these additional resource loading steps.
Otherwise, you can just exclude these steps during design time by checking the DesignMode property and acting accordingly.
This is a fine pattern to use if you're making a control library with a sample of images when shown in the designer or hook ins to other designer features but as a pattern for development I'm not sure it's very effective.
I would suggest shifting your "business logic" (in this case your loading of certain images into a treeview) outside of the bounds of your treeview control. In your case I would place the logic within the Load event of the form that the control is inside:
public void Load(object sender, EventArgs e)
{
string path = "c:\somePath\toAwesome\Images";
myFunkyTreeView.AddImages(path);
}
For larger apps I personally think you want to shift the logic even out of the forms themselves, but this is debatable measure as it requires additional plumbing as a trade-off for the flexibility this provides.
Thanks for pointing me in the right directioon guys.
I had tried registering to the OnLoad event, but that event is triggered when the Design View comes up, so that didn't quite work for me (am I doing something wrong?).
Anyway, I looked a bit more into the DesignMode property. It can only work for Controls, and sometimes your object may not even be a control.
So here's the answer I prefer:
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) {
// design-time stuff
} else {
// run-time stuff
}
Found it here.

Categories