Strange .NET ListView behaviour - c#

I'm trying to get my head around this behaviour: I have a ListView on a form in LargeIcon View (System.Windows.Forms.View.LargeIcon)
This line is in the constructor:
this.listView1.LargeImageList.ImageSize = new Size(32, 32);
And then this function is called upon a double click:
private void listView1_DoubleClick(object sender, EventArgs e)
{
this.listView1.LargeImageList.ImageSize = new Size(64, 64);
}
When I double click on the listview, the size changes as expected, but the icon I have is taken away, and I just get a big blank space. Even if I set the ImageIndex to use afterwards, it stays blank, and I can't seem to get it displaying again.
I assume I'm doing something wrong (although I guess .NET could be broken). What do I change such that the icon does not disappear?
(I am in .NET 2.0)

I think you are running into this caveat described in MSDN (http://msdn.microsoft.com/en-us/library/system.windows.forms.imagelist.imagesize.aspx):
Because setting the ImageSize property
causes the handle to be recreated, you
should set ImageSize prior to setting
the Images property.
Besides, relying on the system to resize the images from 32x32 to 64x64 would naturally result in low quality images.

Related

Create Form.MinimumClientSize Property

The Windows Forms have Size and ClientSize Properties. Windows Forms also have a MinimumSize property that lets you set the smallest allowed size of the form. I am looking for a way to set the minimum ClientSize of a form. I'm new to c# and I am unsure of the best way to do this.
It occurred to me that I could use the Form.SizeChanged event to check and restrict the form size but this seemed messy and I am looking for another way of doing it.
Note: If the form border size is changed I want the Minimum Client Size to be maintained.
How to set a minimum Size of a Form's Client Area.
The Form.MinimumSize property sets the minimum size of the Form as a whole, including the current borders, the Caption and the subtle internal padding that is applied when the Form is resized and a new Layout is performed (many factors determine this activity).
It may be imperceptible, because it's fast (and, usually, nobody cares), but the relation between the Form Size and the Client Size is not constant. It can change when the Form is resized, dragging its borders. Or a System event causes this to happen.
Plus, changing the System settings, in many departments (the properties of the Windows, the Theme, Dpi, Font size etc.), can determine a change in the relations between the Form size and the size of its client area.
The good thing is that the Form is aware of these changes and, when notified of a System event that alters the aspect of Windows in some way, re-performs its layout.
When this happens (and it can happen frequently, always when a Form is resized), the OnLayout method is called.
Overriding OnLayout, allows to update values that rely on the Window/Client area measures.
➨ It can be interesting to see what happens when System settings,
affecting the aspect of the Windows, are changed while the application
is running. In this specific context, how many times the OnLayout
method is called and what the LayoutEventArgs properties are set
to.
This all considered, we can create a public MinimumClientSize Property.
We override OnLayout and reset the Form.MinimumSize to the new Form.MinimumClientSize plus the difference between the Form.Size and the Form.ClientSize.
For example, if we need to keep the Client Area size to a minimum of (500, 500):
private Size m_MinimumClientSize = new Size(500, 500);
public Size MinimumClientSize {
get => m_MinimumClientSize;
set { m_MinimumClientSize = value;
PerformLayout();
}
}
protected override void OnLayout(LayoutEventArgs e) {
base.OnLayout(e);
MinimumSize = m_MinimumClientSize + (Size - ClientSize);
}
If we add to the OnLayout method:
Console.WriteLine($"ClientSize: {ClientSize}");
Console.WriteLine($"MinimumSize: {MinimumSize}");
Console.WriteLine($"Size: {Size}");
it becomes clear that the relation between Form.Size and Form.ClientSize is not always the same.
We could also calculate the difference between Size and ClientSize this way:
var borderSize = new Size(
(SystemInformation.FrameBorderSize.Width * SystemInformation.BorderMultiplierFactor
+ (SystemInformation.Border3DSize.Width * 2)) * 2,
(SystemInformation.FrameBorderSize.Height * SystemInformation.BorderMultiplierFactor
+ (SystemInformation.Border3DSize.Height * 2)) * 2);
var captionSize = new Size(0, SystemInformation.CaptionHeight);
MinimumSize = MinimumClientSize + borderSize + captionSize;
These fixed measures are correct. In normal situations, they provides the same values.
Not always, though. Never, when a Form is resized to its MinimumSize.
Plus, we're only considering a Form with a 3d Border.
Well, we could also override WndProc...

How to get real value of Screen Size in C# WPF Application

I am trying to get Screen width and Height of my System on SizeChanged Event.
It works fine in all cases excluding:
Change Screen Size to 1024 X 765 then Run my Application its works fine.
Change Screen Size Again to Another Resolution while my application running
got Width and height of my Previous Resolution not Current.
I have used screen.primaryscreen.bounds.width on Window_SizeChanged Event.
You can monitor the SystemEvents for changes.
using Microsoft.Win32;
Add this to your constructor or the like:
SystemEvents.DisplaySettingsChanged +=
new EventHandler(SystemEvents_DisplaySettingsChanged);
Here's the event handler. I have the data bound to 2 TextBoxes so I could see the values change as I messed with the resolution, including telling it to revert.
void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
data.ScreenHeight = Screen.PrimaryScreen.Bounds.Height;
data.ScreenWidth = Screen.PrimaryScreen.Bounds.Width;
}
In your case, just change the assignment to point to where you want to store it.

fullscreen is not always functioning

Good day, I have a winform that can set full screen. But sometimes it's not. It is sometimes 3/4 of the screen but sometimes it is full screen. Below is my Code. Anybody knows why it's not always fullscreen....?
private void Form1_Load(object sender, EventArgs e)
{
FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
Width = Screen.PrimaryScreen.WorkingArea.Width;
Height = Screen.PrimaryScreen.WorkingArea.Height;
}
When I run it in my pc. Its fine. But when it is in the production. I saw it did not go well. But sometimes it is ok.
By the way, I want my taskbar to be seen. If I set FormWindowState.Maximized, my taskbar would not be seen.
Thank you.
The issue is that the WorkingArea is not the same with Full Screen. WorkingArea is relative, not the common way of forcing full screen.
There are a couple of ways to attempt to force the full screen.
One of the most popular way to force fill is by setting WindowsState to Maximized (also here and here - quite popular) combined with setting TopMost property to true.
private void Form1_Load(object sender, EventArgs e)
{
this.TopMost = true;
this.FormBorderStyle = FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
}
Alternatively, less popularly, you could also use Screen.Bounds (but may not be absolute too, try to put additional TopMost = true)
And finally, you could also using WorkingArea with conditional statement. To debug and see what is the WorkingArea size in you production PC, you could use GetWorkingArea method. This way, you can debug what is the working area in the production PC and if it is not full screen comparing to the size of the PC, you could force is to full screen. Not so efficient though...
Here is more explanation on working area vs screen area to help you making decisions.
Edit: with bar to be seen, what I could think of as another way to do this is by Get Screen Size. See:
How can I get the active screen dimensions?
Then you should limit the maximum dimension of your form (y/x-axis) such that you have room for your bar - that is, to be little less than the screen size in one of the axis. Then, on form load or other related events, you could control the position of your WinForm such that you won't block your bar.
See StartupPosition property:
C# window positioning
Screen.PrimaryScreen.WorkingArea only gets the screen's working area.
I think you need to change it to
Width = Screen.PrimaryScreen.Bounds.Width;
Height = Screen.PrimaryScreen.Bounds.Height;
You just need to set the WindowState to Maximized at run-time:
WindowState = FormWindowState.Maximized;
Or at design-time, using the WindowState property of the form.

Scrolling part of a control (Form or Panel) [duplicate]

I have a Form with the following properties:
Background Image
Scrollable Panel with a transparent background, and Dock = DockStyle.Fill
PictureBox with a large Width and Height which shows scroll bars
Now all controls are set to DoubleBuffered including the form itself. Everything works as expected except when scrolling the Panel for the PictureBox, the form background image scrolls with it repeating itself showing vertical and horizontal tearing although its static image that fits the form's size, and when you stop scrolling it shows properly. This only happens when dragging the scrollbars, if i click on any point in the scrollbars to move it, it shows properly.
As per my understanding Double Buffering should eliminate such cases, but even with double buffering its the same, maybe a little bit better but still its a huge problem when scrolling.
I tried to place all controls inside another panel instead of using form background image and place this panel on the form but it didn't make any difference.
You are doing battle with a Windows system option, named "Show window content while dragging". It is turned on for all modern versions of Windows. Turning it off is not a realistic goal, since it is a system option it affects all windows of all apps. There is no back-door to selectively bypass this option.
With it enabled, the OS optimizes the scrolling of a window. It performs a fast bitblt to move the pixels in the video frame buffer and generates a paint message for only the part of the window that is revealed by the scroll. Like the bottom few rows of pixels when you scroll down. Underlying winapi call is ScrollWindowEx(). Intention is to provide an app with a more responsive UI, a lot less work has to be done to implement the scroll.
You can probably see where this is heading, ScrollWindowEx() also moves the pixels that were painted by the form's BackgroundImage. You can see that. Next thing you see is the side-effect of the optimized paint, it only redraws the part of the window that was revealed. So the moved background image pixels don't get redrawn. Looks like a "smearing" effect.
There is a simple workaround for that, just implement an event handler for the panel's Scroll event and call Invalidate(). So the entire panel gets redrawn again:
private void panel1_Scroll(object sender, ScrollEventArgs e) {
panel1.Invalidate();
}
But now you'll notice the side-effect of the paint no longer being optimized. You still see the pixels getting moved, then overdrawn. How visible that is depends a great deal on how expensive the BackgroundImage is to draw. Usually never cheap because it doesn't have the optimal pixel format (32bppPArgb) and doesn't have the right size so needs to be rescaled to fit the window. The visual effect resembles the "pogo", rapid jittering on one edge of the panel.
Pretty unlikely you'll find that acceptable or want to do the work to optimize the BackgroundImage. Stopping ScrollWindowEx() from doing its job requires a pretty big weapon, you can pinvoke LockWindowUpdate(). Like this:
using System.Runtime.InteropServices;
...
private void panel1_Scroll(object sender, ScrollEventArgs e) {
if (e.Type == ScrollEventType.First) {
LockWindowUpdate(this.Handle);
}
else {
LockWindowUpdate(IntPtr.Zero);
panel1.Update();
if (e.Type != ScrollEventType.Last) LockWindowUpdate(this.Handle);
}
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool LockWindowUpdate(IntPtr hWnd);
Works pretty well, the background image pixels are now rock-steady. Any other pixels, well, not so much. Another visual effect, lets call it a "wrinkle". Getting rid of that artifact can be done by putting the window into compositing mode. Which double-buffers the entire window surface, including the child controls:
protected override CreateParams CreateParams {
get {
const int WS_EX_COMPOSITED = 0x02000000;
var cp = base.CreateParams;
cp.ExStyle |= WS_EX_COMPOSITED;
return cp;
}
}
Only remaining artifact is the side-effect of this not being very cheap code. It probably doesn't look that smooth when you scroll. Which otherwise tells you why windows were designed to be opaque 28 years ago.
It is not easy but it is doable and the following worked fine for me though took me 2 hours to discover:
First you need to make sure the column gets null value without the default 'null' icon, before add it to the grid:
DataGridViewImageColumn imagecol = new DataGridViewImageColumn { ImageLayout = DataGridViewImageCellLayout.Stretch };
imagecol.DefaultCellStyle.NullValue = null;
grid.Columns.Add(imagecol);
Then you need to delete this column value for all rows within ANY event that resizes or moves the rows of that particular column (the example here is for scroll event):
private void DataGridViewScrollEventHandler(object sender, ScrollEventArgs e)
{
if (e.ScrollOrientation == ScrollOrientation.VerticalScroll)
{
DataGridView grid = (DataGridView)sender;
foreach (DataGridViewRow row in grid.Rows)
{
row.Cells[1].Value = null;
}
}
}
Finally you need to fill the image value again for all rows you delete it at paint event:
private void DataGridViewPaintEventHandler(object sender, PaintEventArgs e)
{
DataGridView grid = (DataGridView)sender;
foreach (DataGridViewRow row in grid.Rows)
{
row.Cells[1].Value = myImage;
}
}
If you have a lot of rows you need to do this for the visible rows only for performance. There is a property for this so it would be doable.
The best solution is to set the form's background image again on the control scroll event
private void panel1_Scroll(object sender, ScrollEventArgs e) {
/*
Your Code if any exists
*/
//reset the form's background image again in the scroll event
this.BackgroundImage = Properties.Resources.your_background_image;
}

.net Resizing control won't work?

I have a couple of pictureboxes that need to be resized by aspect ratio when the window size changes. I assumed I can anchor the width, but set the height manually (i.e. anchor the left, right, and top edges; but not the bottom.) However, my control won't resize if I try changing the Size property. Why wouldn't that work? How can I resize my control?
private void Form1_Resize(object sender, System.EventArgs e)
{
int oldWidth = 1280;
int oldHeight = 1024;
int newWidth = webcamPictureBox.Size.Width; // this is auto-resized w/ window; becomes 591
int newHeight = (oldHeight * newWidth) / oldWidth; // this is calculated manually; becomes 472
// Control won't resize if I change the Size property
// Size property stays the same
this.webcamPictureBox.Size = new Size(newWidth, newHeight);
this.thumbnailPictureBox.Size = new Size(newWidth, newHeight);
}
You could be running into one of a few problems, I suppose:
What's the SizeMode of the PictureBox? Is it AutoSize, StretchImage, or something like that? It should probably be Normal for what you want to do.
Are you sure you have your anchoring set up correctly?
Did you debug and check the final size of the picture boxes you're trying to resize? You should verify that it's what you expect and that the form has been repainted.
These are just some ideas; your code along is not enough to provide a great response.
It's difficult to answer this question definitively with the information you've posted.
Windows forms controls problems are difficult to debug by nature because of all the controls that might be affecting what you're doing. First off, you'll want to try debugging this on your own on a form with as few controls as possible. Are there any circumstances under which the resizing behaves properly?
That said, is the Dock property set on these controls? They definitely won't resize if they're set to DockStyle.Fill.
Thanks for the ideas -- they pointed me on the right track! Everything was set up as they should be, except the TableLayoutPanel they were in was constraining their sizes. I determined this by noticing the pictureboxes' size values were simply uneditable, both in runtime and in the designer.
So I set TableLayoutPanel's AutoSize to true, and it works great!

Categories