I've write a program that construct a 2D matrix from txt file, and build a winforms panel with X*Y labels wich contains a char, coordinates, color and border (if select it).
it is my DrawGrid routine:
Container.SuspendLayout();
for (int y = 0; y < template.Matrix.GetLength(1); y++)
{
for (int x = 0; x < template.Matrix.GetLength(0); x++)
{
var curLabel = new LabelTemplate(template.Matrix[x, y].Content, x, y, spacing);
_templateCells.Add(curLabel);
Container.Controls.Add(curLabel);
}
}
Container.ResumeLayout();
whit it I view a txt file in my form, and select a row or columns or area with mouse, manipulate and save new text files from it getting content and coordinates from my LabelTemplate object (extends Label).
I've always test my program with a little txt files in input.
Today i've tested with a big txt file (9000 rows * 50 columns) and i've reached a maximun handles of a windows form application.
(an Win32 Exception is launched during Container.Controls.Add(curLabel)).
Googling i've found that the limit of controls in winforms application is 10000 handles.
Also view a lot of label on my form (if 10000 is a modificable value), performance are very bad (if i scroll container panel, i wait a lot of time to view results)!
There is a way or control that help me?
I think also to GDI+, but what is the right way for you? Any suggestions?
Thanks in advance
I think you should use DataGridView control.
If your amount of data is too big, you can limit the number of items and add some control to select the start of the region that you are viewing (like a NumericUpDdown or a TrackBar). Every time you change the start index, you reload your data to the DataGridView.
Sample of how to fill a DataGridView from an array: "How do I show the contents of this array using DataGridView?".
Another solution would be to use WPF, which has built-in UI Virtualization, therefore supports much bigger datasets without having any performance impact.
It is not practical to use labels for cells of a grid-like control. As agent5566 suggested, you can use DataGridView control for a fast approach or if you want full control and better performance, you can use a single UserControl and paint everything on it, handle keystrokes, simulate focus on cells (if needed) and so on.
Related
I have a scenario in which I want to display numerous images in a panel using only horizontal scroll.
To enable only Horizontal Scroll only, I used the following code in the constructor
public Form()
{
InitializeComponent();
panelImageGallery.AutoScroll = true;
panelImageGallery.VerticalScroll.Enabled = false;
panelImageGallery.VerticalScroll.Visible = false;
}
And then to display and use images in the panel I wrote the following lines of code
int increment = 0;
lblCount.Text = "0/" + files.Length;
for (int i=0;i<files.Length;i++)
{
PanelPictureBox box = new PanelPictureBox();
box.IMAGE= files[i];
box.Location = new Point(panelImageGallery.Location.X + increment, panelImageGallery.Location.Y+10);
box.INDEX = i+1;
panelImageGallery.Controls.Add(box);
increment += 300;
}
Following is the result, and it can be seen that although, I have 350 images but NOT all images are in the panel as there are only 109 images and even both the horizontal and vertical scrolls are there.
Also, when I scrolled the panel all the way to the end then there are some display issues at the end too as the last image gets joined with the second last image.
Another thing that I observed was that when I increased the margin between the images, then fewer and fewer images got displayed inside the panel. So for example, when I set the increment to 500 then only 66 images got displayed in the panel instead of all the 350 images. My feeling is that there could be restriction on the maximum size of the panel, So what is actually happening here and how to resolve this issue ?
This is a limitation because of some of the Windows messages, for example as mentioned in documentations:
Note that the WM_HSCROLL message carries only 16 bits of scroll box
position data. Thus, applications that rely solely on WM_HSCROLL (and
WM_VSCROLL) for scroll position data have a practical maximum position
value of 65,535.
In general, it's not a good idea to try to host too many controls on the form.
In your case, you may want to try controls which performs automatic layout, like FlowLayoutPanel, TableLayoutPanel, Docking into the left of a panel or decrease the margin between your controls.
Or as a proper fix, you can rely on ListView control which support virtual mode, or implement a custom drawn control, or use paging to show a limited number of controls in each page.
I have read several stack overflow questions without finding a good working solution to my problem. How can I resize my controls whenever the form is resized? I would like them to get larger or smaller when the form becomes larger or smaller.
In visual basic this was quite easy to do with the form.Zoom property (which did't really require resizing controls of course, but solved what I needed). Unfortunately this is not available in C# winforms.
Here is some other things I have tried without luck:
private void formMain_Resize(object sender, EventArgs e)
{/*
double scale;
this.scaleWidth = (float)this.Width / (float)this.origWidth;
this.scaleHeight = (float)this.Height / (float)this.origHeight;
if (this.scaleHeight > this.scaleWidth)
{
scale = this.scaleHeight;
}
else
{
scale = this.scaleWidth;
}
foreach (Control control in this.Controls)
{
control.Height = (int)(control.Height * this.scaleHeight);
control.Width = (int)(control.Width * this.scaleWidth);
this.Refresh();
// control.Font = new Font("Verdana", control.Font.SizeInPoints * heightRatio * widthRatio);
}
///////This scaling didnt work for me either
//this.Scale(new SizeF(this.scaleWidth, this.scaleHeight));
//this.Refresh();
*/
}
If I overlooked an actualy working sample of code on another stack overflow question I would love to see it, but the ones I found were similar to those above which are not working.
Perhaps I was misusing it and someone could post sample code to show for those of us who keep asking this question how to go about solving the problem.
Also, I have tried using some of the anchor/docking tools thinking they would automatically allow it but it didn't.
The best option is to use a TableLayoutPanel. Put TableLayoutPanel on the form, set the Dock property to Fill, create required rows and columns and put the controls inside the cells. Of course you need to set Dock/Anchor on the controls inside the cells, so they respond to changes to the cell size. In some situations you may need to put a Panel into a cell and drop the controls inside it, because every cell can only contain a single control. You may also need to set RowSpan/ColumnSpan on the controls.
By using a TableLayoutPanel, you have complete control over how your cotrols should be arranged. You can set absolute or percentage size for rows and columns.
Use Anchor of the control. There's an option on anchoring the top, bottom, left and right. And you're good to go.
I found an alternative solution that is working well for me, appreciate any negative or positive comments on the solution.
Using several Split Containers and Split Containers inside of Split Containers in different regions I am able to section off the primary pieces of the layout, and within there utilizing Docking and Anchoring I am able to accomplish exactly what I wanted to do - it works beautifully.
I would point out I am aware that some folks online mention split containers use lots of resources.
If your controls are in a group box, be sure to set the group boxes properties to resize. Controls inside the box are controlled by the box. The box size (unless it is inside another box) is controlled by the form.
What you are trying to do in your code is to change the sizes of the controls which isn't so good approach. Generally, the size of the Buttons and TextBoxes shouldn't be changed when you re-size your form, but they often need to move (change location). Some controls do need to change size according to the re-sized form and but in most cases only one dimension. The central controls that are used for working area (if you are developing the tool for drawing for instance) should change sizes of both dimensions. All this you can accomplish by properly setting Dock and/or Anchor properties of the controls.
textBox1.Dock = DockStyle.Bottom;
textBox1.Anchor = AnchorStyles.Bottom & AnchorStyles.Left;
All these are also easily set in the Properties panel when using designer.
But if that isn't enough for you, in rare cases, you will most definitely want to only change the location of the control:
textBox1.Location = new Point(newX, newY);
I'm developing a VSPackage (extension for Visual Studio 2010), and I have a tool window that is hosting a DataGridView control.
I have a very large data-set (e.g. 2D array of size 16384 x 16384) and I update data via VirtualMode.
I want to add index to the row header cells and column header cells,
so I tried:
Auto resize via grid methods
grid.AutoResizeRowHeadersWidth(
DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders);
Iterating through each row
foreach (DataGridViewRow row in grid.Rows) {
row.HeaderCell.Value = (row.Index + 1).ToString();
}
Subscribing to RowsAdded/OnPaint and updating the value there.
But, all these methods were SUPER SLOW!
They significantly degraded the rendering of the DGV (takes like ~ 5 seconds or more to render the view after each of these methods, or even worse).
What would you suggest to do instead?
I did do initial research into the issue and you've listed all the typical solutions, unfortunately setting 250 million cell values will take some time.
The only thing I didn't see you mention was to fake the header cells (ie first column and row with grey background) and populate them with the source data. Since the DataGridView cell values with be populated with Pixel values one idea is to a append 1 pixel strips to the left and top of each image that you load.
I still think the solution needs a better design. And below are indirect answers to your question.
Make a Picture Dialog with a Zoom-In function. When the user/developer zooms into the pixel level show them the RGB values. Here is an excellend Drawing Tool example written in C# based of MFC CLiDraw and it has an example to show you how to zoom in.
The other idea is a EyeDropper Colour Picker you can get from: http://www.codeproject.com/Articles/36540/Adobe-Eyedropper-Control
I'm developing an app that creates a timeline in run time. So I created a Grid (not a datagrid) and I wanna put some time stamps in equal spaces (60 pixels/hour - 1 pixel/minute).
I already know how to create the columns programmatically:
public void ColumnCreator(double totalInterval, double divPattern)
{
int divisionPattern = Convert.ToInt16(divPattern);
if (divisionPattern < totalInterval)
{
for (int i = 0; i < totalInterval; i += divisionPattern)
{
internalGrid.ColumnDefinitions.Add(new ColumnDefinition() {
Width = new GridLength(divisionPattern, GridUnitType.Pixel) });
}
}
}
but these lines are not synchronized. Does anybody have a solution for me?
Thanks in advance 8-)
As was pointed out especially for real time visualization Grid may be the worse choice you can made. Grid is responsible for containing controls layout management and has a heavy impact on performance.
Use a Canvas to draw a stuff on it. Use Shape and Path for drawing. To achive a reasonable performance on real time UI you need to read at least this link: http://msdn.microsoft.com/en-us/library/ms747393.aspx
Do not use Pixels but provided by WPF Units, which are device independent way to declaring the dimension of something in WPF. So your drawing will maintain a proportion on different monitors screen sizes and dpi.
I am writing a program to control a mobile robot. One of the things it has to do is to draw a map of the "world" as the robot senses it and apply changes in the map as it senses them.
It also has to highlight in some way the location of the robot and (ideally) the direction it points to.
I currently have an auto-updating array (100 x150) representing the map, using the following representations: 0 represents a clear path, 1 represents an obstacle.
I also have a variable containing the robot's location and next location.
What I need is to visualize it. I thought about using labels, but it is way too tedious using them, and the end result is not so pretty. My other possibility is to write all that data into an Excel spreadsheet, but then I will be back to square one: visualizing the data in an attractive way. Is there a drawing package of some sort that can do the job?
To sum it up:
Using:
- int[] MapArray //100 x 150 array representing the robot's world, and the data there is changing.
- Point[] Locations //Locations[0] is the current location, Locations[1] is the next step.
And I want to draw a map on a Windows Forms application that updates itself in a nice visual manner.
I hope my question is clear enough, don't hesitate to contact me if not!
Try Code: Drawing a Filled Rectangle on a Form (Visual C#) or something similar.
Graphics Programming Example Topics
Just write a couple of cycles which accesses every cell of an array and draws a rectangle on a form according to coords - that's the simplest way.
for(int i=0; i<100; i++)
{
for(int j=0;j<150;j++)
{
<access[i,j] and draw a rectangle with color accordingly to your contents.>
}
}
The same for the drawing location.
If you don't find any nice controls, you can always use a DataGridView with the column width = row height so that it always displays square cells. After that, just change the background color of the obstacles.
You could also look into observable collections for the map array so that the grid updates based on events rather than on timers. Make sure that you overwrite the observable collection to send the CollectionChanged event even when a cell changes its value, not only when adding/removing cells.