autoscroll panel to bottom - c#

i have a panel in my winforms and in it i load some usercontrols .
i would like to autoscroll to the bottom of the panel( as my panel fills ) everytime a new usercontrol is added . How can i do so ?

You can do that by setting the VerticalScroll of the Panel but I think it would be better to use ScrollControlIntoView instead.
private void panel1_ControlAdded(object sender, ControlEventArgs e)
{
panel1.ScrollControlIntoView(e.Control);
}
Good luck!

You could use ScrollControlIntoView and pass the control you last added.
An alternate solution would be:
panel.VerticalScroll.Value = panel.VerticalScroll.Maximum

I found that continuously adding controls to the panel at vertical increments would be affected negatively whenever a user had scrolled the panel up or down. I used the tip from Homam above, and found the following to work well:
panel1.VerticalScroll.Value = 0;
// Creating and adding a TextBox, tb, to the panel
panel1.ScrollControlIntoView(tb);
So first, I scroll to the top in order to use absolute vertical positions for my text boxes, then I place the Text Box, and finally, I make sure that the newly created text box comes into view.

Related

Hide Container but not Text Positioned Over It

I have a .NET 4.5 WinForm that checks for the existence of a certain file when the form loads. If the condition is met, I display the form in its entirety. If the file doesn't exist, I want to display a simple text message while hiding (setting the Visible property to false) all the other components on the form.
My issue is that the Label I want to display can only be positioned on top of a GroupBox. Well, not only but it is most aesthetically pleasing being in that location. If I set the visibility of the container to false then it hides the message as well.
Is there a way to "break out" the Label from the GroupBox?
Worst comes to worst, I will hide the indivial components within the GroupBox and live with the border that remains. I am just curious if there is a way to do this.
I found a solution using only the designer. ChrisF's answer got me thinking, and the correct method isn't to place the label behind the container, but rather to place the container on top of the label. This seems to be a quirk of the VS designer.
I created a new WinForm and added a label and a groupbox, without the two of them overlapping. Then:
Right-click the label and Send to Back, or alternatively right-click the container and Send to Front
Drag or resize the container to cover the label
And that's it... the label appears behind the container. I guess the designer correctly notes the z-index when both components have the same parent container, and placing the label on top of the groupbox changes its parent container.
To have the label on the form in the position you want, but outside the group box use the "send to back" option to push it behind the group box. It won't be visible at design time, but it will be in the right place.
Then if the file is not found you can make the group box invisible revealing the label behind.
Another alternative is to position the label outside the group box (off to the left or right and outside the form) and then move it into position at the same time as making it visible.
I know you want to benefit the capability of design support to position your label correctly right at design time, however doing so will set the groupbox as Parent of your label, you can't drag and drop that label on your form. So just try the following code to change the Parent from groupbox to the form at runtime and maintain the design location, that way changing your groupbox's visible won't affect the visible of your label:
public Form1(){
InitializeComponent();
Load += (s,e) => {
var loc = label1.PointToScreen(Point.Empty);
label1.Parent = this;
label1.Location = PointToClient(loc);
};
}

How can I set a panel to be always on top when changing tabpages in C#?

I have program with two tabs in a TabController, I also have a panel I want to always have in front. Despite what tabpage I am in. I tried setting the panel to BringToFront(), but that donĀ“t seem to work when I change tabpage. Any suggestions how to solve this?
If the Panel is contained by the TabPage, then you'd have to manually switch it to the current tab whenever the tab changes, then call BringToFront().
An alternative would be to make the Panel so it's directly contained by the Form, but in front of the TabControl (like it's "floating" over it). Then it would just stay there. You'd have to either manually fiddle with the Panel's Location() property to get it right (you couldn't drag it over the TabPage as then it would drop into it), or you could position it properly via code in the Load() event of the Form.
Edit:
For instance, if you properly positioned "panel1" in the TabPage at design-time, you could switch it to the Form using code like this:
private void Form1_Load(object sender, EventArgs e)
{
Point pt = panel1.PointToScreen(new Point(0, 0));
panel1.Parent = this;
panel1.Location = this.PointToClient(pt);
panel1.BringToFront();
}
Set the panel outside the tabcontroller and set it's dockstyle. Also set the dockstyle of the tabcontroller.
Panel belongs to a specific tabpage. When you change to another tabpage and call BringToFront(), it doesn't make anything, because you're on another tabpage right now. So you need to workaround that with righting some code. There are two ways:
1) You can place that panel on every tabpage in design time (if you don't need some shared data on that panel).
2) You should hook OnTabPageChanged event and move panel from old tabpage to the page you switched to (if you do need some shared data on that panel). I think this is your case.

Move contents of Form when a Control is re-Located

Let's just say that I have many controls on my Form, and when a User clicks on one of them, its height will expand. This means that, currently, when this clicked-control expands, other controls below it will become overlapped by the expanded control.
But what I want to happen, is for each Control below the expanded control to slide down, so that they are below the expanded control again.
I know how to handle sliding, but I just don't know how to make every control except for one move everytime a given control is moved.
Any help at all is greatly appreciated, thank you!
This is what I was thinking:
void newOrderReceived(object sender, EventArgs e)
{
foreach(Control OrderNotificationBox in OrdersPanel.Controls)
{
if(OrderNotificationBox is NotificationBox) // Checks to see if the control is a NotificationBox
{
// Add my code to slide controls down.
}
}
}
But... How do I know if the control is below the expanded control?
Is this how I should go about changing the location of all controls below the expanded control?
Edit: Just had a thought, to check to see if a NotificationBox is below the Expanded NotificationBox, see revised code below:
void newOrderReceived(object sender, EventArgs e)
{
foreach(Control OrderNotificationBox in OrdersPanel.Controls)
{
if(OrderNotificationBox is NotificationBox) // Checks to see if the control is a NotificationBox
{
if(OrderNotificationBox.Location.Y <= ExpandedNotificationBox.Location.Y + ExpandedNotificationBox.Size.Width)
{
// Add my code to slide controls down.
}
}
}
}
But would this be sufficient? Currently, this is working, so I guess I just answered my own question. But, isn't there a better way to do this? A more elegant/efficient way?
Here's a sample of how it should look:
FlowLayoutPanel provides you with dynamic layout where you can resize any control in it and all below controls will slide automatically. There are many strategies to using groups/columns of flow layout panels to be able to achieve the desired look for the whole form. Some googling will reveal some of these.
For instance in the form above, resizing the button1 control simply flows all the below controls to further down on the form. You can try that at the design time also. Drop the form a flow layout panel, drop 3-4 control in the container and start experimenting..
For each expandable content use Panel.
Dock your panels one under another (Use panel1.Dock = DockStyle.Top. For the very bottom panel use panel1.Dock = DockStyle.Fill).
Place your child controls inside of each expandable panel, set inner controls' Anchor properties accordingly.
When you expand one panel, the rest of the panels will adjust automatically. You don't need to code for this. You will only change Height of a panel that you currently expand.
What you need is some kind of 'ExplorerBar' functionality. There are several control libraries that offer that, and I found the article here on the CodeProject that has it for free.

Hosting a UserControl inside a custom DataGridViewCell

I created a custom DataGridViewCell to show a specific UserControl when the user starts editing the cell. Basically the control contains a TextBox with a suggestion list easily handled by the code.
I got my code to resize the list correctly, and have it contain exactly what I want and where I want it. The problem I have now is that the control is not being drawn correctly on the screen, and the ListBox is probably beind drawn "inside" the row, and since it is much higher than the row, does not get shown on screen.
How can I make the control draw on top of the DataGridView?
You'll probably need to put the ListBox in a separate popup form. Good luck.
Alternatively, you can put the ListBox in the GridView's parent form, then call BringToTop to make sure it's on top of the grid view.
There's a msdn article, Build a Custom NumericUpDown Cell and Column for the DataGridView Control, that paints custom controls on datagridviews. The code sample provided there might help solve your problem.
I think you'll want to take a look at Faking alternative controls within a DataGridView control in Win Forms 2.0. It will look like the control is hosted within the DataGridView, but in actuality it is just positioned nicely over the cell. I am using this now for two DateTimePickers and one ComboBox with great success.
Sample code from link:
protected void dgCategory_CellClick(object sender, DataGridViewCellEventArgs e)
{
//set Date Picker to false when initially click on cell
if (dtPicker.Visible)
dtPicker.Visible = false;
if (e.ColumnIndex == 2)
{
//set date picker for category datagrid
dtPicker.Size = dgCategory.CurrentCell.Size;
dtPicker.Top = dgCategory.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true).Top;
dtPicker.Left = dgCategory.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true).Left;
if (!(object.Equals(Convert.ToString(dgCategory.CurrentCell.Value), "")))
dtPicker.Value = Convert.ToDateTime(dgCategory.CurrentCell.Value);
dtPicker.Visible = true;
}
}
private void dtPicker_ValueChanged(object sender, EventArgs e)
{
dgCategory.CurrentCell.Value = dtPicker.Value;
dtPicker.Visible = false;
}

How do I scroll a RichTextBox to the bottom?

I need to be able to scroll a RichTextBox to the bottom, even when I am not appending text. I know I can append text, and then use that to set the selection start. However I want to ensure it is at the bottom for visual reasons, so I am not adding any text.
You could try setting the SelectionStart property to the length of the text and then call the ScrollToCaret method.
richTextBox.SelectionStart = richTextBox.Text.Length;
richTextBox.ScrollToCaret();
The RichTextBox will stay scrolled to the end if it has focus and you use AppendText to add the information. If you set HideSelection to false it will keep its selection when it loses focus and stay auto-scrolled.
I designed a Log Viewer GUI that used the method below. It used up to a full core keeping up. Getting rid of this code and setting HideSelection to false got the CPU usage down to 1-2%.
//Don't use this!
richTextBox.AppendText(text);
richTextBox.ScrollToEnd();
In WPF you can use ScrollToEnd:
richTextBox.AppendText(text);
richTextBox.ScrollToEnd();
Code should be written in the rich text box's TextChanged event like :
private void richTextBox_TextChanged(object sender, EventArgs e) {
richTextBox.SelectionStart = richTextBox.Text.Length;
richTextBox.ScrollToCaret();
}

Categories

Resources