WPF Logical Resources

WPF Logical Resources
A Logical Resource in WPF is a XAML defined object that can be used by WPF elements inside the user interface.
You can declare a logical resource for the entire window and will be usable by all elements on that window, or you can declare it inside the Resources collection of an element, where it will be usable only within that element. You can also declare it for an entire application and it will usable anywhere.

       
              
              
       



       
            	
              	       
                      
            	
       



       
              
              
       


The application resources collection can be found inside the App.xaml file located in your project.

Every resource must have an x:Key property which defines the name of that specific object. It doesn’t have to be unique in the entire application, but it must be unique in the Resource Collection in which it was defined.

A resource in XAML can be accessed by using the {StaticResource name} syntax.


Mnemonic Keys in WPF

Mnemonic keys are keys that when pressed in combination with the ALT key move the focus to the control they are assigned to.

Labels in WPF have a built in support for mnemonic keys.

A mnemonic key can be specified by using the underscore symbol ( _ ) in front of the key you wish to assign. At runtime, you will notice that the key will appear underlined when the ALT key will be pressed.

Here is an example in XAML:



In this example, we have designated to Label1 a TextBox named TextBox1 and when the ALT+S keys will be pressed in combination, the textbox will receive focus.

SQL Banker's Rounding Function

The Banker's Rounding, also known as the Gaussian Rounding or Rounding to Even, rounds a given number if its fraction is half to the nearest even number.

The bellow SQL function rounds any given decimal number to a number of given digits and returns the rounded decimal number. It reads the number from right to left depending on the number of digits required and then rounds it. If the fraction is not half, then common rounding takes place.

CREATE FUNCTION [dbo].[BankersRounding]
(
	@value DECIMAL(28, 10),
	@digits INT
)

RETURNS DECIMAL (28, 10)
AS
BEGIN

	DECLARE @roundedValue DECIMAL(28, 10)
	DECLARE @roundingType INT 
	
		IF (ABS(@value - ROUND(@value, @digits, 1)) * POWER(10, @digits + 1) = 5)
			BEGIN
			
				IF (ROUND(ABS(@value) * POWER(10, @digits), 0, 1) % 2 = 0)
					BEGIN
						SET @roundingType = 1 
					END
				ELSE
					BEGIN
						SET @roundingType = 0
					END
						
				SET @roundedValue = ROUND(@value, @digits, @roundingType)
			END
				
		ELSE
			BEGIN
				SET @roundedValue = ROUND(@value, @digits)
			END
						
	RETURN @roundedValue
END

In C# there's the Round method inside the Math class that can take an enumeration overload called MidpointRounding.ToEven that does the exact same thing.

Here's an example:

using System;

namespace BankersRoundingProject
{
    public class BankersRounding
    {
        public static decimal GetRoundedValue(decimal value, int digits)
        {
            return Math.Round(value, digits, MidpointRounding.ToEven);
        }
    }
}

Temperature converting

In this post I'll try to explain you how to convert temperatures from Celsius to Fahrenheit or vice versa. I will create a small WinForms application that actually does that.

I used two doubles to store the temperature's values (one for Celsius and one for Fahrenheit), two labels (of which one will be displayed after the actual transformation takes places and will contain the transformed value), one combobox and one textbox. Oh... and almost forgot about the button that triggers the transformation and displays the result.

One more thing you will notice is that I've used Math.Round with two decimals to get a nice transformation result and I've used the String.Format method to display the transformed value instead of the usual concatenation.

using System;
using System.Drawing;
using System.Windows.Forms;

namespace TemperatureTrasformer
{
    public partial class mainForm : Form
    {
        double celsius;
        double fahrenheit;

        ComboBox cboxTempType;
        TextBox txtTemp;
        Label lblInitial;
        Label lblResult;
        Button btnConvert;

        public mainForm()
        {
            InitializeComponent();

            //Set up the form's proprieties
            this.Text = "Temperature Converter";
            this.ClientSize = new Size(250, 150);
            this.MaximizeBox = false;
            this.StartPosition = FormStartPosition.CenterScreen;
            this.FormBorderStyle = FormBorderStyle.FixedSingle;

            //Set up the form's controls
            lblInitial = new Label();
            lblInitial.Location = new Point(10, 10);
            lblInitial.AutoSize = true;
            lblInitial.Text = "Enter the temperature you want to convert:";

            txtTemp = new TextBox();
            txtTemp.Location = new Point(10, lblInitial.Bottom + 5); 
            txtTemp.Width = 100;

            cboxTempType = new ComboBox();
            cboxTempType.Location = new Point(txtTemp.Right + 10, lblInitial.Bottom + 5);
            cboxTempType.Width = 100;
            cboxTempType.DropDownStyle = ComboBoxStyle.DropDownList;
            cboxTempType.Items.Add("Celsius");
            cboxTempType.Items.Add("Fahrenheit");
            cboxTempType.SelectedIndex = 0;

            btnConvert = new Button();
            btnConvert.Text = "Convert";
            btnConvert.Location = new Point(10, txtTemp.Bottom + 10);
            btnConvert.AutoSize = true;
            btnConvert.Click += new EventHandler(btnConvert_Click);

            lblResult = new Label();
            lblResult.Location = new Point(10, btnConvert.Bottom + 10);
            lblResult.AutoSize = true;

            this.Controls.Add(lblInitial);
            this.Controls.Add(cboxTempType);
            this.Controls.Add(txtTemp);
            this.Controls.Add(btnConvert);
        }

        void btnConvert_Click(object sender, EventArgs e)
        {
            //Convert to Fahrenheit
            if (cboxTempType.SelectedIndex == 0)
            {
                celsius = Convert.ToDouble(txtTemp.Text);
                fahrenheit = Math.Round((celsius * 9) / 5 + 32, 2);
                lblResult.Text = String.Format("The temperature in Fahrenheit is {0} degrees", fahrenheit);
                this.Controls.Add(lblResult);
            }
            //Convert to Celsius
            else if (cboxTempType.SelectedIndex == 1)
            {
                fahrenheit = Convert.ToDouble(txtTemp.Text);
                celsius = Math.Round((fahrenheit - 32) / 9 * 5, 2);
                lblResult.Text = String.Format("The temperature in Celsius is {0} degrees", celsius);
                this.Controls.Add(lblResult);
            }
        }
    }
}

Installing IIS 5.1 (for Win XP) and enabling .aspx pages

Windows XP can only accept IIS 5.1, but IIS 5.1 does not accept by default .aspx pages. This is because .aspx pages were introduced with the Framework 2.0 while IIS 5.1 predates this framework.

Installing IIS 5.1 on Windows XP:

1. Go to Control Panel
2. Open Add/Remove Programs
3. Select the Add/Remove Windows Components Tab
4. Select Internet Information Services (IIS) from the list
5. Click Next and follow the wizard

Once the installation is complete you can open your web browser and navigate to http://localhost/. IF IIS was installed correctly you should see its homepage. You will notice on the IIS homepage the page formats that it supports, but .aspx pages will not be present. To enable these pages on IIS you will need to have at least .NET Framework 2.0 installed.

Enabling .aspx pages on ISS 5.1:

1. Navigate to C:\Windows\Microsoft .NET\Framework
2. Enter the framework directory (v4.0.30319 for .NET 4.0 as example)
3. Search for a file named aspnet_regiis.exe
4. Run this program with the “ -i” command line parameter

You should see how IIS is reconfigured to use the latest framework. Now that everything should is set up, all you’ll have to do is to copy the website in the C:\Inetpub\wwwroot directory. On the local machine you can run the website by navigating to http://localhost/ or from any computer on the intranet by accessing your machine’s IP.

NOTE that IIS 5.1 can host only one site.

WPF - how to add text in a richtextbox

You mighyt have noticed that the RichTextBox control in WPF does not have a Text or Content method. so you will have to use something a little bit different. This method is usefull when you use a read only richtextbox and you want formated text in it.

First you'll have to initialize a paragraph, then add the string inside the paragraph and lastly add the paragraph to the richtextbox.

In the bellow example I will show you how to add a specific text in a richtextbox when a button is clicked.

private void btnAddText_Click(object sender, RoutedEventArgs e)
        {
//we want to clear all text inside the richtextbox, or else each time we click the button the same text will be added over and over again

            txtRichTextBox.Document.Blocks.Clear(); 

//We initialize 3 paragraphs

            Paragraph textTitle = new Paragraph();
            Paragraph textSubTitle = new Paragraph();
            Paragraph textDescription = new Paragraph();

//We will add the strings to the paragraphs as well as bolding the first and justifying the 3rd

            textTitle.Inlines.Add("This is a bolded title");
            textTitle.FontWeight = FontWeights.Bold;
            textSubTitle.Inlines.Add("This is a subtitle");
            textDescription.Inlines.Add("This is a long text so in case you'll copy paste this code you will notice how the text is justified. Just remember not to make the richtextbox too big.");
            textDescription.TextAlignment = TextAlignment.Justify;

//And here we add all 3 paragraphs to the rich text box

            txtRichTextBox.Document.Blocks.Add(textTitle);
            txtRichTextBox.Document.Blocks.Add(textSubTitle);
            txtRichTextBox.Document.Blocks.Add(textDescription);        
}

Basic Pong Game

In this post I will try to give you a basic idea on how to create a very basic pong-like game in C# and Winforms in .NET 4.0.

To start, create a new C# Winforms project and call it whatever you want.

For this project we will need 3 PictureBoxes, 1 Timer, 5 ints and 3 sizes right above the constructor. The pictureboxes represent the ball (picBoxBall) and the 2 paddles (one for the player and one for the AI - picBoxPlayer and picBoxAI). Two of the 5 ints are constant and represent the form's width and height (SCREEN_WIDTH and SCREEN_HEIGHT). Another 2 int are for the ball's speed on the X and Y axis (ballSpeedX and ballSpeedY) and last int is for the Timer's interval (gameTimeInterval). We will call the timer gameTime and the 3 sizes (sizePlayer, sizeAI sizeBall) represent the size of the 3 pictureboxes.

PictureBox picBoxPlayer, picBoxAI, picBoxBall;
        Timer gameTime;

        const int SCREEN_WIDTH = 800;
        const int SCREEN_HEIGHT = 600;
        
        Size sizePlayer = new Size(25, 100);
        Size sizeAI = new Size(25, 100);
        Size sizeBall = new Size(20, 20);

        int ballSpeedX = 3;
        int ballSpeedY = 3;
        int gameTimeInterval = 1;

In the constructor we will need to intilize our controls and the timer's Tick event which I've set the interval to 1. Also, we are going to give the position, size and color of each control.

public gameArea()//gameArea is the form's name
        {
            InitializeComponent();

            picBoxPlayer = new PictureBox();//
            picBoxAI = new PictureBox();//Initializes the PictureBoxes
            picBoxBall = new PictureBox();//

            gameTime = new Timer();//Initializes the Timer

            gameTime.Enabled = true;//Enables the Timer
            gameTime.Interval = gameTimeInterval;//Set the timer's interval

            gameTime.Tick += new EventHandler(gameTime_Tick);//Creates the Timer's Tick event

            this.Width = SCREEN_WIDTH;//sets the Form's Width
            this.Height = SCREEN_HEIGHT;//sets the Form's Height
            this.StartPosition = FormStartPosition.CenterScreen;//opens the form in center of the screen

            picBoxPlayer.Size = sizePlayer;//sets the size of the picturebox
            picBoxPlayer.Location = new Point(picBoxPlayer.Width / 2, ClientSize.Height / 2 - picBoxPlayer.Height / 2);//sets it's location (centered)
            picBoxPlayer.BackColor = Color.Blue;//fills the picturebox with a color
            this.Controls.Add(picBoxPlayer);//adds the picture box to the form

            picBoxAI.Size = sizeAI;
            picBoxAI.Location = new Point(ClientSize.Width - (picBoxAI.Width + picBoxAI.Width / 2), ClientSize.Height / 2 - picBoxPlayer.Height / 2);
            picBoxAI.BackColor = Color.Red;
            this.Controls.Add(picBoxAI);

            picBoxBall.Size = sizeBall;
            picBoxBall.Location = new Point(ClientSize.Width / 2 - picBoxBall.Width / 2, ClientSize.Height / 2 - picBoxBall.Height / 2);
            picBoxBall.BackColor = Color.Green;
            this.Controls.Add(picBoxBall);
        }

Next, in the Timer's tick event we will need to update the ball's position by adding the ballSpeedX and ballSpeedY ints to its original location and we will call 4 methods (2 for movement and 2 for collisions) that I will explain later.

void gameTime_Tick(object sender, EventArgs e)
        {
            picBoxBall.Location = new Point(picBoxBall.Location.X + ballSpeedX, picBoxBall.Location.Y + ballSpeedY);
            gameAreaCollisions();//Checks for collisions with the form's border
            padlleCollision();//Checks for collisions with the padlles
            playerMovement();//Updates the player's position
            aiMovement();//Updates the ai's position
        }

The gameAreaCollisions method basically checks to see if the ball hits form's sides. If it hits the upper or lower side of the form it inverts the Y speed and if it hist the left or right side of the form in resets the ball bu using a new method called resetBall (explained later). You will notice that I've used to different "else if", for collision with the left or right side of the form, although we could have used only one with and "or" approach. I did this because I am planning to elaborate on this approach in a later more advanced tutorial.

private void gameAreaCollisions()
        {
            if (picBoxBall.Location.Y > ClientSize.Height - picBoxBall.Height || picBoxBall.Location.Y < 0)
            {
                ballSpeedY = -ballSpeedY;
            }
            else if (picBoxBall.Location.X > ClientSize.Width)
            {
                resetBall();
            }
            else if (picBoxBall.Location.X < 0)
            {
                resetBall();
            }
        }
The resetBall method is called when the ball hits the left or right side of the form and when it does it send the ball back to the center of the screen, reseting the position. In this method you could add score incrementation for example.
private void resetBall()
        {
            picBoxBall.Location = new Point(ClientSize.Width / 2 - picBoxBall.Width / 2, ClientSize.Height / 2 - picBoxBall.Height / 2);
        }
Next is the playerMovement method which moves the player's padlle according to the cursor position. The movement on the X axis is constant and only the Y position changes.
private void playerMovement()
        {
            if (this.PointToClient(MousePosition).Y >= picBoxPlayer.Height / 2 && this.PointToClient(MousePosition).Y <= ClientSize.Height - picBoxPlayer.Height / 2)
            {
                int playerX = picBoxPlayer.Width / 2;
                int playerY = this.PointToClient(MousePosition).Y - picBoxPlayer.Height / 2;

                picBoxPlayer.Location = new Point(playerX, playerY);
            }
        }
Next is the aiMovement method which moves the AI paddles to the ball's position on Y axis (the X is always the same) whenever the ball is moving towards him. The ball comes towards the AI's paddle only when it's speed on the X axis is positive as the paddle is located in the right side of the form where the X increases.
private void aiMovement()
        {
            if (ballSpeedX > 0)
            {
                picBoxAI.Location = new Point(ClientSize.Width - (picBoxAI.Width + picBoxAI.Width / 2), picBoxBall.Location.Y - picBoxAI.Height / 2);
            }
        }
Last we have the padlleCollision method which verifies the collision with the paddles. We verify this by using the Bounds.IntersectsWith method the the PicturBox control has. As we did in the gameAreaCollisions method all we have to do is invert the speed, but this time on the X axis. I've used two ifs, although I could have used only one for the next tutorial. You can use only one with the "or" aproach.
private void padlleCollision()
        {
            if (picBoxBall.Bounds.IntersectsWith(picBoxAI.Bounds))
            {
                ballSpeedX = -ballSpeedX;
            }

            if (picBoxBall.Bounds.IntersectsWith(picBoxPlayer.Bounds))
            {
                ballSpeedX = -ballSpeedX;
            }
        }

Now press F5 and play the game. Of course, you will notice that you can't beat the AI as its paddle always moves at the ball's position. This tutorial was meant to give you a basic and general idea on how to create a pong rip off. In a later tutorial, whenever the time will allow it, I will try to show you how to create a basic AI, add some graphics, some sounds and gameplay logics (lives, score, difficulty).

Border Collision Detection - Bouncing Control

To make a label (or any other control.. I just choose label as an example) bounce when it hits the border of a form you'll have to invert the speed with which the label is incremented each tick.

Here's an example:

I will use a label which I've called lblAI, two speed int (AISpeedX and AISpeedY - the speeds with which the label moves on the X and Y axis), two const int (SCREEN_WIDTH and SCREEN_HEIGHT) and one timer which I've called gameTime. Also I've added one Panel called gameArea, but it's not really required.

First we will have to declare our variables just above the constructor:

        const int SCREEN_WIDTH = 700;
        const int SCREEN_HEIGHT = 400;
        int AISpeedX = 3;
        int AISpeedY = 2;

Then we will need to give an initial location to the label. We can do this in the Form1_Load event:

private void Form1_Load(object sender, EventArgs e)
        {
            lblAI.Location = new Point(SCREEN_WIDTH / 2 - lblAI.Width / 2, SCREEN_HEIGHT / 2 - lblAI.Height / 2);
        }

The next step would be to add the Tick event to our timer and inside it we will move the label by incrementing the speed values. Also, at each tick we will check to see if the label's location does not exit the form's borders. For this example I've used a 1 millisecond interval for a smooth result, but you can user whatever you like. Also, remember to enable the timer as it is disabled by default.

private void gameTime_Tick(object sender, EventArgs e)
        {
            if (lblAI.Location.X < 0 || lblAI.Location.X > (SCREEN_WIDTH - lblAI.Width)) AISpeedX = -AISpeedX;
            if (lblAI.Location.Y < 0 || lblAI.Location.Y > (SCREEN_HEIGHT - lblAI.Height)) AISpeedY = -AISpeedY;

            lblAI.Location = new Point(lblAI.Location.X + AISpeedX, lblAI.Location.Y + AISpeedY);
        }

As you can see, at each tick we check to see if the Location on the X axis is lower than 0 or higher than the screen width, and if it is we invert the incrementation value on the X axis. Same goes for the Y axis.

You can notice that when checking for the higher value I've subtracted the label's width for the X axis and the label's height for the Y axis. I did this because we are using the label's location value which is given by the top left point of the label. If we wouldn't have had subtracted the width and the hight respectively we would see the label leave the area until the location point would have been greater than the width or height of the area.

Form Random BackColor

If you want to display a random BackColor for your form or simply generate a random color you can use the FromArgb method from the Color class with 3 int random arguments for Red, Green and Blue.

Here is an example where the form's BackColor is changed every time a button is clicked. In this example I've also added 3 labels to display the 3 generated numbers.

private void button1_Click(object sender, EventArgs e)
        {
            Random RandomClass = new Random();

            int rndRed = RandomClass.Next(0, 255);
            int rndGreen = RandomClass.Next(0, 255);
            int rndBlue = RandomClass.Next(0, 255);

            this.BackColor = Color.FromArgb(rndRed, rndGreen, rndBlue);

            lblBlue.Text = "Blue: " + rndBlue.ToString();
            lblGreen.Text = "Green: " + rndGreen.ToString();
            lblRed.Text = "Red: " + rndRed.ToString();
        }

Sorting Combobox Items Alphabetically

To sort a collection of items inside a combobox alphabetically, one way to do it would be to use the SortDescription class. For this, first you need to add the System.ComponentModel namespace. Then initialize a new SortDescription class in which you can tell by what and how to arrange the list. And finally simply add the class to the combobox you wish to be arranged. In case you want to arrange a simple combobox (only one thing to arrange it by) use the "Content" string when initializing the class as shown in the example bellow:

SortDescription sd = new SortDescription("Content", ListSortDirection.Ascending);
comboBox1.Items.SortDescriptions.Add(sd);

Get The Total Size of Multiple HDD

The following code will show you how it can be retrieved the total size of multiple HDDs installed on your system. Using the same method you can do this for available free space. I've also converted bytes to GB as the value is retrieved in bytes. For this you can use the Size property from the Win32_DiskDrive class:

private static String getHDDsize()
        {
            Double sum = 0;

            ManagementObjectSearcher mos = new ManagementObjectSearcher("Select * From Win32_DiskDrive");

            foreach (ManagementObject item in mos.Get())
            {
                double HDD_size = Convert.ToDouble(item["Size"]);
                sum += HDD_size;
            }

            return Convert.ToString(Math.Round(sum / 1073741824, 2)) + " GB";
        }

Retrieving the System's Total Physical Memory

Recently I was creating an app in which I needed to display the total physical memory inside a label. At first I was tempted to retrieve the memory using the Capacity property from Win32_PhysicalMemory, but it seems that this property retrieves the memory from each module. Although it does the job, I found out that is more efficient to retrieve the total physical memory using the TotalPhysicalMemory property from the Win32_ComputerSystem WMI class.

The following code shows you how to retrieve it using a foreach loop. Note that this property retrieves the memory in bytes and I've did some calculations to display it in GB. Then, this method can be used to display the memory amount inside a label... or whatever.

private static String getRAMsize()
        {
            ManagementClass mc = new ManagementClass("Win32_ComputerSystem");
            ManagementObjectCollection moc = mc.GetInstances();
            foreach (ManagementObject item in moc)
            {
                return Convert.ToString(Math.Round(Convert.ToDouble(item.Properties["TotalPhysicalMemory"].Value) / 1073741824, 2)) + " GB";
            }

            return "RAMsize";
        }