Showing posts with label WPF. Show all posts
Showing posts with label WPF. Show all posts

Creating a WPF User Interface from scratch using XAML

To create a WPF User Interface using XAML , first we will have to understand the what the XAML structure is, I am assuming you have an understanding of XML markup. XML is an internet technology and Microsoft has done a hard work here to bring this internet technology into the desktop user interface development pattern.

First we will understand the limitations of XML.

  • In XML , Explicit references are not allowed.
  • XML is content driven the XML markup cannot be declared and used else where as in our traditional coding technique.
  • XML always represents a state and not a behavior.
  • XML doesn't support inheritance.
Now if we look at the above points we get to know that with XML is content driven , but this leaves us with a very important question, How does the WPF framework validate this XML? 

Lets consider the below problems with using XML and their solutions. 
In my previous article about developing a WPF project from scratch , I had developed a WPF UI and attached it to the application without making any use of XAML. this seemed straight forward as it involved declaring and initializing the UI controls and Window using C# code and setting it as the content. This was straight forward for the WPF framework and the compiler as well since all it had to do was make the use of reflection and validate the structure of the controls and its properties. But now the question is How does the WPF framework achieve this when the UI controls are declared in the XML? 

Microsoft has introduced a special kind of parser for the XML now refereed as XAML where the parser makes use of the reflection technology and validate it to be of correct structure. But how does it refer to the correct DLLs to validate? since we know that the namespace reference we add in an XML document is of a special convention in the form of a URI, URL or a URN

The answer to this is that this is achieved with a special kind of a namespace resolution mechanism using the 
class XmlnsDefinitionAttribute This class makes the mapping between the .NET libraries (DLL) and the XML compliant namespaces.  

OK, now coming back. let me show you a simple example of a XAML window declaration 


XAML

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Window.Content>
    <StackPanel >
      <StackPanel.Children>
        <Button Content="Search" Height="30" Width="100"></Button>
        <TextBox Height="30" Width="100"></TextBox>
      </StackPanel.Children>
    </StackPanel>
  </Window.Content>
</Window>


Here in the above code we can see that we have a window tag , this represents a window and within which we have the name space defined as xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation
Note that the namespace definition has begun with xmlns this tells us that a namespace is defined and its the default for this current window. the reason being that it is not aliased , if you want to provide an alias to this namespace then the xmlns has to be followed by a colon ":" and the alias name hence it will look something like this 
xmlns:myalias ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

We also know that in XML we can also provide attributes within each elements , if we look at the above XML structure we see that after the <Window> element we have its child element as <Window.Content>
you may be wondering what this is since we have not come across such naming conventions in XML. In case of XAML we can define the structure of the properties for the elements in XML by Attributes or as child Elements. 
But when do we know which one to choose? The answer to this is,  if the value for the property is complex then we have to go with a child element and if the value for the property is simple then we can define it as an Attribute. For example since the content property for the window is not simple and holds more than just a value its a complex and has been defined as a child element to the Window element. But this gives us another problem, how will the parser know which complex property value belongs to which element ? to resolve this the element name whose property has to be set is appended with its property name to form the child element name for example. the content property which is a complex property for the window has to be set the element now becomes <Window.Content> </Window.Content> this will tell the compiler that the Property named Content will belong to the Element Window.

We can also see that in  the <Button Content="Search" Height="30" Width="100"></Button> element the Content property is set as an attribute as we can see that only the text value "Search" is provided and hence this becomes a simple value for the attribute , it is the same for Height and Width as well.


With the above information lets create a sample project where the UI is developed using only xaml.

Lets begin.

Step 1 :  First create an empty project.
Step 2 :  Add the following DLL reference in your project.
              Presentation Framework
              Presentation Core
              Windows Base
              System.xaml

             This is better shown below. Click on it to enlarge.


Step 3 : Add two New classes to your project
            App.cs

Step 4 : Add a new XML file to your project and name it SearchWindow.xaml
             
Now open this XAML file and paste this code in it.

XAML


<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Window.Content>
    <StackPanel >
      <StackPanel.Children>
        <Button Content="Search" Height="30" Width="100"></Button>
        <TextBox Height="30" Width="100"></TextBox>
      </StackPanel.Children>
    </StackPanel>
  </Window.Content>
</Window>


Step 5 : Open your App.cs file and paste the below code in it.


C#

[STAThread]
static void Main()
{
     //Create an instance of a new Application
     System.Windows.Application _wpfApplication = new System.Windows.Application();

     //Set the start up URI as your XAML page 
     
_wpfApplication.StartupUri = new Uri("SearchWindow.xaml",UriKind.RelativeOrAbsolute);   

     //Run this Application by callinf the Run() method
     _wpfApplication.Run();
}


Step 6 : Now right click on the project the click on properties. Here in the Applications tab set the output type of the project to Windows Application  as shown below.


Step 7 : All done. you are good to go now. click on debug and you will see this below window.




This window is your own custom window. Congrats , you just created a WPF project from scratch..



Creating a WPF project from scratch

Lets create a WPF Project from scratch, i mean really from the scratch.
Lets begin.

Step 1 :  First create an empty project.
Step 2 :  Add the following DLL reference in your project.
              Presentation Framework
              Presentation Core
              Windows Base
              System.xaml

             This is better shown below. Click on it to enlarge.


Step 3 : Add two New classes to your project
            App.cs
            MyWindow.cs 

The MyWindow.cs class is your custom window and this will extend the base class window. when you run your application this is the window we will see. Please note that there is no xaml window declaration and please do not get confused by reference to the system.xaml dll. we will make use of this in our next example.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//Add these namespaces
using System.Windows;
using System.Windows.Controls;

namespace WPFAppFromScratch
{
    //This will be your custom window class which is derieved    
    //from the base class Window.
    class MyWindow : Window
    {
        //Declare some UI controls to be placed inside the
        //window.
        Button _searchButton;
        TextBox _searchTextBox;

        //The controls can be placed only inside a panel.
        StackPanel _panel;

        public MyWindow()
        {
            //This is created just to show a reference , the 
            //below code can aswell be witten wihin this     
            //constructor.
            InitializeComponent();
        }

        void InitializeComponent()
        {
            _searchButton = new Button { Height = 30, Width = 100,  Content = "Search" };
            _searchTextBox = new TextBox{  Height = 30, Width = 100 };

            _panel = new StackPanel();

            //Add the controls inside the panel.
            _panel.Children.Add(_searchButton);
            _panel.Children.Add(_searchTextBox);

            //Set this panel as the content for this window.
            this.Content = _panel;
        }
    }
}

The Code will look something like this on your IDE.


Step 4 : Now Open the file App.cs and type the below code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace WPFAppFromScratch
{
    class App
    {
        [STAThread]
        static void Main()
        {
            //Create an instance of your window.
            MyWindow _window = new MyWindow();

            //Create an instance of a new Application
            System.Windows.Application _wpfApplication = new System.Windows.Application();

            //Run this Application by passing the window object 
            //as the argument
            _wpfApplication.Run(_window);
        }

    }
}


Be sure to add the STAThread attribute on top of your main function. The WPF applications are of Single Threaded Apartment type and if you do do not add this attribute , you will get an exception. Go ahead and try debugging  

System.Windows.Application _wpfApplication = new System.Windows.Application();

Will instantiate a new Application , and passing a Window object to its Run() method will start the application with that Window.

The File will look something like this 


Step 5 : Now right click on the project the click on properties. Here in the Applications tab set the output type of the project to Windows Application  as shown below.


Step 6 : All done. you are good to go now. click on debug and you will see this below window.




This window is your own custom window. Congrats , you just created a WPF project from scratch..


"Connecting ... " screen for C# and WPF

Recently i came across a situation where i had to create a screen which showed a establishing connection , i searched the "interweb" for this but found no good resource that provided me with the code ready to use. hence i decided to create one by my own.


What did i do? 

Well i used a canvas and ellipses within that. This  did the job for me and below are the screen shots





How to do it? 

I have provided inline comments with the code below,

The XAML code is below 


<Window x:Class="EstablishConn.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowState="Normal" WindowStyle="ToolWindow"
        Title="Connecting ..." Height="125" Width="525">
    <Grid>
        <Canvas Name="MyCanvas"> </Canvas>
    </Grid>
</Window>



Your code Behind will be as below

You will have to include the below namespaces


using System.Windows.Shapes;
using System.Windows.Threading;

namespace EstablishConn
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
    }
}

The Main Logic 

/*
Global declaration
*/
int ELLIPSE_COUNT = 25;
int CURRENT_ELLIPSE_ID = 0;
private List<Ellipse> ellipseList;
Brush DEFAULT_ELLIPSE_COLOR = Brushes.LightSteelBlue;
Brush ELLIPSE_COLOR = Brushes.Blue;
Brush LIGHT_ELLIPSE_COLOR = Brushes.SkyBlue;
Brush DARK_ELLIPSE_COLOR = Brushes.DarkBlue;

/*
The dispatch timer object will be a timer that will raise a tick event every specified interval given in timespan
*/
DispatcherTimer timer = new DispatcherTimer { Interval =   TimeSpan.FromSeconds(0.05) };

/*
Constructor
*/
public MainWindow()
{
   InitializeComponent();
   ellipseList = new List<Ellipse>();
   CreateEllipseList();
   /*
   assign an handler for the DispatchTimer
   then start the timer
   */
   this.timer.Tick += new EventHandler(timer_Tick);
   this.timer.Start();
}


/*
this method will create the Ellipse s and allocate it to the 
Canvas
The created ellipses will also be added to a list to be    handled later
*/
private void CreateEllipseList()
{
   double LEFT = 10;
   for (int i = 0; i < ELLIPSE_COUNT; i++)
   {
       Ellipse e = new Ellipse();
       e.Height = 10;
       e.Width = 10;
       e.Fill = DEFAULT_ELLIPSE_COLOR;
       Canvas.SetLeft(e, LEFT);
       Canvas.SetTop(e, 50);
       MyCanvas.Children.Add(e);
       ellipseList.Add(e);
       LEFT = LEFT + 20;
   }
}

/*
This is the event handler for the timer 
Here the actual animation takes place
*/
private void timer_Tick(object sender, EventArgs e)
{
   ellipseList[CURRENT_ELLIPSE_ID].Fill = LIGHT_ELLIPSE_COLOR;
   ellipseList[CURRENT_ELLIPSE_ID + 1].Fill = ELLIPSE_COLOR;
   if (!(CURRENT_ELLIPSE_ID >= ELLIPSE_COUNT - 2))
      ellipseList[CURRENT_ELLIPSE_ID + 2].Fill = DARK_ELLIPSE_COLOR;

   if (CURRENT_ELLIPSE_ID > 0)
      ellipseList[CURRENT_ELLIPSE_ID - 1].Fill = DEFAULT_ELLIPSE_COLOR;

   CURRENT_ELLIPSE_ID = CURRENT_ELLIPSE_ID + 1;
   if (CURRENT_ELLIPSE_ID >= ELLIPSE_COUNT - 2)
   {
      ellipseList[CURRENT_ELLIPSE_ID - 1].Fill    = DEFAULT_ELLIPSE_COLOR;
      ellipseList[CURRENT_ELLIPSE_ID].Fill        = DEFAULT_ELLIPSE_COLOR;
      ellipseList[CURRENT_ELLIPSE_ID + 1].Fill    = DEFAULT_ELLIPSE_COLOR;

      CURRENT_ELLIPSE_ID = 0;
   }
}

How to implement INotifyPropertyChanged interface in C# and WPF


 
To notify a target element in WPF that the source property value has been changed , The containing class will have to implement the INotifyPropertyChanged Interface 


Below is a sample abstract class that implements this interface, All you have to do is extend this abstract class in your ViewModel class or any class where your properties are declared.


 using System;
 using System.ComponentModel;

 namespace Logiphix
 {
    abstract public class PropogatePropertyChangesToTarget :  INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string info)
        {
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
        }
    }
}


How can you use it?

Lets declare a sample class and extend the above created abstract class

public class SampleClass PropogatePropertyChangesToTarget 
{
      /* I have my properties declared here*/
      private string employeeName;

      public string EmployeeName 
      {
          get
             { 
                   return employeeName;
             }

          set
             {
                   employeeName = value;

                   // Call the method here in the setter
                   NotifyPropertyChanged("EmployeeName"); 
             }
      }
}

Now if any target property is bound to this above property, It is likely to get notified that its value has changed.





WPF: TreeView in WPF/XAML

How to use the TreeView Element and loading it through code.

The XAML is as below. We can have any number of nodes in a tree. there is no limit for that Each new TreeViewItem that is added is made into blue color for easy understanding.

<Page 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >

<TreeView>

 <TreeViewItem>
<TreeViewItem.Header>
  <TextBlock Text ="Hello"></TextBlock>
</TreeViewItem.Header>
     <TreeViewItem Header="First element"/> 
     <TreeViewItem Header="Second element"/>
     <TreeViewItem Header="Third element"/> 
     <TreeViewItem Header="Fourth element">
<TreeViewItem>
            <TreeViewItem.Header>
<TextBlock Text ="Inside Fourth"></TextBlock>
            </TreeViewItem.Header>
            <TreeViewItem Header="Is there an end to this?"/>
</TreeViewItem>
  </TreeViewItem>
  <TreeViewItem Header="World"> 
<TreeViewItem Header="Again a first element"/> 
  </TreeViewItem>

</TreeView>

</Page>

The Output will be as follows:
Both the nodes are not expanded








First Node(Hello ) is expanded










The Node inside the node is expanded. (Fourth element)












The Node inside the node inside Node is expanded. (Inside Fourth Node)














The Tree is expanded entirely


WPF : TextBox

Text in WPF can be handled in. many ways, basically there are three types

  • The Simple text box or the plain text box
  • The Rich text box.
The two types mentioned above share the same base class the TextBoxBase.
The Simple text box or the plain text box allows you to enter only simple string. If you want to format your string. you have to use the  Rich text box. which allows you to have formatted text/ string. The Rich text box doesnot use the RTF / Rich text format even if the name suggests you so. it uses the WPF's own flow formatting to format the text.
Even though it supports RTF, it just doesn't use it as its internal model.
As they support a common base class they support the common clipboard operations like copying editing and pasting etc.

There is another type of text box that doesn't share the same base 

  • The Password Box
This is as the name suggests used for the password entering purpose . it doesn't share the same base class as the above two. because it is required that it shouldn't support some of the clip board operations like copy and paste. it also shows the entered text as dots/stars etc.

The TextBox and the RichTextBox both support spell checking. 
All we have to do is set the property SpellCheck.IsEnabled ="True"


<Page 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
  
   <Grid>
<TextBox   SpellCheck.IsEnabled ="True" />

   </Grid>
</Page>

You can see below that the spell check works as expected, the misspelled words have been underlined with red. it can be right clicked to select from a list of words.

Again it depends on the localization. and provides the options depending on it.

The Example shown below is been developed on XamlPadX.
You can download this from http://blogs.msdn.com/b/llobo/archive/2006/12/30/xamlpadx-v2.aspx









Content Model : GroupBox Headers other than just a plain text in WPF

How to have a Group box in WPF / XAML with a header other than just plain text?

We know that  WPF / XAML supports Content Model that allows us to have elements arranged in a way that makes it possible to have anything to be used as a caption!
It could be just a plain text or some graphics or some data aswell.

For example,


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >

  <Grid>
<GroupBox>
    <GroupBox.Header>
          <StackPanel Orientation="Horizontal">
                       <Button><TextBlock Text="Click Me!" /></Button>
          </StackPanel>
    </GroupBox.Header>
</GroupBox>
 </Grid>

</Page>

Here in the xaml above, the groupbox header is not just a plain text , it is a button with the text Click Me! in it, this is done within the <GroupBox.Header> </GroupBox.Header>