Tuesday, February 28, 2017

C# - Prevent Windows Form from flickering during Maximizing or Restoring

My problem today is that my windows form application has one second or more of black before displaying full screen. That make it not smooth when restoring the windows or change from minimize state to maximize. Even when the application contains only some control on the screen only.
I have tried to disable / comment out all of the source code that related to the resize related events of windows. But that doesn't resolve the issue.
After all, I thought that the solution must be that we can catch the event when user begin to maximize the windows and temporary suspend the layout redraw, then when the application comes to maximized state, we will allow it to resume the layout. Therefore, the last source code of the application will be somehow like the following.

 using System;  
 using System.Collections.Generic;  
 using System.ComponentModel;  
 using System.Data;  
 using System.Drawing;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 using System.Windows.Forms;  
 namespace TestMaximizeWindows  
 {  
   public partial class Form1 : Form  
   {  
     public Form1()  
     {  
       InitializeComponent();  
     }  
     private void Form1_Load(object sender, EventArgs e)  
     {  
     }  
     protected override void WndProc(ref Message m)  
     {  
       var msg = '\x112';  
       const int minimize = '\xf020';  
       const int maximize = '\xf030';  
       const int restore = '\xf120';  
       if (m.Msg == msg)  
       {  
         Console.WriteLine(m.ToString());  
         var param = m.WParam.ToInt32();  
         switch (param)  
         {  
           case minimize:  
             // handle minimize              
             break;  
           case maximize:  
             // handle maximize     
             this.SuspendLayout();           
             break;  
           case restore:  
             // handle restore    
             this.SuspendLayout();            
             break;  
         }  
       }  
       base.WndProc(ref m);  
     }  
     private void Form1_SizeChanged(object sender, EventArgs e)  
     {  
       this.ResumeLayout();  
     }  
   }  
 }  

There are two other events that you can use in this WinProc method

private const Int32 WM_SIZE = 0x0005;
private const Int32 WM_SIZING = 0x0214;

Friday, February 24, 2017

C# - Draw line, rectangle on a Windows Form

The following code snippet show you how to draw a line and rectangle in C#.

 using System;  
 using System.Collections.Generic;  
 using System.ComponentModel;  
 using System.Data;  
 using System.Drawing;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 using System.Windows.Forms;  
 namespace DrawOnWinForm  
 {  
   public partial class Form1 : Form  
   {  
     public Form1()  
     {  
       InitializeComponent();  
     }  
     System.Drawing.Pen bounderyPen;  
     System.Drawing.Pen OxOyPen;  
     System.Drawing.Pen ABPen;  
     System.Drawing.Pen CPen;  
     System.Drawing.Brush ACMBrush = Brushes.LightGray;  
     System.Drawing.Brush BCMpBrush = Brushes.LightCyan;  
     System.Drawing.Brush TextBrush = Brushes.Black;  
     Font textFont = new Font("Arial", 10);  
     Point TOPLEFT = new Point(0, 0);  
     Point BASEO = new Point(400, 400);  
     Rectangle Boundery = new Rectangle();  
     double xO = 0, yO = 0;  
     private void Form1_Load(object sender, EventArgs e)  
     {  
     }  
     int zoomX = 50;  
     int margin = 10;  
     int zoomY = 50;  
     System.Drawing.Brush brush = Brushes.White;  
     private void Form1_Paint(object sender, PaintEventArgs e)  
     {  
       Clear();  
       System.Drawing.Graphics formGraphics = this.CreateGraphics();  
       Boundery.X = margin;  
       Boundery.Y = margin;  
       Boundery.Width = this.Width - 4 * margin;  
       Boundery.Height = this.Height - Boundery.Y - margin * 5;  
       bounderyPen = new System.Drawing.Pen(System.Drawing.Color.Brown);  
       bounderyPen.Width = 2;  
       formGraphics.DrawRectangle(bounderyPen, Boundery);  
       BASEO.X = (int)(this.Width / 2);  
       BASEO.Y = this.Height - margin * 5 - 100;  
       OxOyPen = new System.Drawing.Pen(System.Drawing.Color.Blue);  
       OxOyPen.Width = 2;  
       formGraphics.DrawLine(OxOyPen, margin, BASEO.Y, Boundery.X + Boundery.Width - margin * 0, BASEO.Y);  
       formGraphics.DrawLine(OxOyPen, Boundery.X + Boundery.Width - 10 - margin * 0, BASEO.Y - 5, Boundery.X + Boundery.Width - margin * 0, BASEO.Y);  
       formGraphics.DrawLine(OxOyPen, Boundery.X + Boundery.Width - 10 - margin * 0, BASEO.Y + 5, Boundery.X + Boundery.Width - margin * 0, BASEO.Y);  
       string textTrucX = "x";  
       formGraphics.DrawString(textTrucX, textFont, TextBrush, new PointF(Boundery.X + Boundery.Width - 10 - margin * 0, BASEO.Y + 2));  
       formGraphics.DrawLine(OxOyPen, BASEO.X, this.Height - margin * 5, BASEO.X, this.Height - margin * 5 - Boundery.Height);  
       formGraphics.DrawLine(OxOyPen, BASEO.X - 5, this.Height - margin * 5 - Boundery.Height + 10, BASEO.X, this.Height - margin * 5 - Boundery.Height);  
       formGraphics.DrawLine(OxOyPen, BASEO.X + 5, this.Height - margin * 5 - Boundery.Height + 10, BASEO.X, this.Height - margin * 5 - Boundery.Height);  
       string textTrucY = "y";  
       formGraphics.DrawString(textTrucY, textFont, TextBrush, new PointF(BASEO.X - 15, this.Height - margin * 5 - Boundery.Height));  
       string textO = "O(" + xO + "," + yO + ")";  
       formGraphics.DrawString(textO, textFont, TextBrush, new PointF(ToaDoFormXZoomY(xO), ToaDoFormYZoomY(yO)));  
     }  
     private void Clear()  
     {  
       System.Drawing.Graphics formGraphics = this.CreateGraphics();  
       #region Ve Boundery  
       Rectangle screen = new Rectangle();  
       screen.X = 0;  
       screen.Y = 0;  
       screen.Width = this.Width - 1;  
       screen.Height = this.Height;  
       formGraphics.FillRectangle(brush, screen);  
       #endregion  
       formGraphics.Dispose();  
     }  
     private int ToaDoFormXZoomY(double x)  
     {  
       return (int)(BASEO.X + x * zoomY);  
     }  
     private int ToaDoFormYZoomY(double y)  
     {  
       return (int)(BASEO.Y - y * zoomY);  
     }  
     private int ToaDoFormXZoomX(double x)  
     {  
       return (int)(BASEO.X + x * zoomX);  
     }  
     private int ToaDoFormYZoomX(double y)  
     {  
       return (int)(BASEO.X - y * zoomX);  
     }  
   }  
 }  

Here is the output of the project.

C# - Change the size of text, apps, and other items to 125%, 150% by using AutoScaleMode

When user changes his Windows display settings of the size of text, apps, and other items to 125%, 150%, etc, how can a Windows Application can automatically response to the changes without breaking its structure and texts.

The solution is that we should let the .NET Framework to work on it automatically by using the following line of code.

       this.AutoScaleMode = AutoScaleMode.Dpi;  

Additionally, you may need to set the Application property of the main project's Properties to "Create application without a manifest".

Don't forget to set the Autosize property of the form to true.

Happy coding...

C# - Hide "Not Responding" message on Windows Form application

Sometimes, in a Windows Form application, we have a situation that make the application "Not Responding". This is not good from user's perspective. If any improvement cannot make any changes, you can choose a solution to hide the message from the application. The following application show you a case of "Not Responding" and a version that can hide the message.

This function will make the application "Not Responding".

     private void button1_Click(object sender, EventArgs e)  
     {  
       for (int i = 0;i < 100000000; i++)  
       {  
         label1.Text = "i = " + i.ToString();  
       }  
     }  


However, adding the following code, you can see no "Not Responding" on your application.
     [DllImport("user32.dll")]  
     public static extern void DisableProcessWindowsGhosting();  
     private void Form1_Load(object sender, EventArgs e)  
     {  
       DisableProcessWindowsGhosting();  
     }  


C# - Try / catch and application performance

The following test shows you how much the try / catch block cost your application performance. Therefore, please consider carefully every cases you use try / catch.

 using System;  
 using System.Collections.Generic;  
 using System.ComponentModel;  
 using System.Data;  
 using System.Drawing;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 using System.Windows.Forms;  
 using System.Diagnostics;  
 namespace TryCatchTest  
 {  
   public partial class Form1 : Form  
   {  
     public Form1()  
     {  
       InitializeComponent();  
     }  
     private void Form1_Load(object sender, EventArgs e)  
     {  
       Stopwatch sw = new Stopwatch();  
       sw.Start();  
       try  
       {  
         int count = 0;  
         for (int i = 0; i < 10000; i++)  
         {  
           count += 1;  
           label1.Text = count.ToString();  
         }  
       }  
       catch(Exception ex)  
       {  
         Console.WriteLine(ex.ToString());  
       }  
       sw.Stop();  
       Console.WriteLine("With try / catch, the elapsed time is: " + sw.ElapsedMilliseconds + " miliseconds");  
       Stopwatch sw2 = new Stopwatch();  
       sw2.Start();  
       int count2 = 0;  
       for (int i = 0; i < 10000; i++)  
       {  
         count2 += 1;  
         label1.Text = count2.ToString();  
       }  
       sw2.Stop();  
       Console.WriteLine("Without try / catch, the elapsed time is: " + sw2.ElapsedMilliseconds + " miliseconds");  
     }  
   }  
 }  


The output in the Console window is as follows:


With try / catch, the elapsed time is: 1364 miliseconds
Without try / catch, the elapsed time is: 1152 miliseconds

Tuesday, February 21, 2017

C# - Prevent "Not Responding" error in Win form by using Task.Run

This function will make your application "Not Responding".

     private void button1_Click(object sender, EventArgs e)  
     {  
       for (int i = 0;i < 100000000; i++)  
       {  
         label1.Text = "i = " + i.ToString();  
       }  
     }  

Modify it a little bit, we can prevent "Not Responding" error happen by using Task.Run method like this:
     private async void button2_Click(object sender, EventArgs e)  
     {  
       await Task.Run(() =>  
       {  
         for (int i = 0; i < 100000000; i++)  
         {  
           label1.Text = "i = " + i.ToString();  
         }  
       });  
     }