top button
Flag Notify
    Connect to us
      Site Registration

Site Registration

How to Implementing a Simple Silverlight Control?

+4 votes
325 views

I am sure that many of you have read about Silverlight, the latest offering from Microsoft promising the ability to deliver rich interactive applications and media. Silverlight 1.1 Alpha has just been released and with this in mind, I decided to download all the tools required to start using Silverlight. To be honest, I have not spent much time looking into Silverlight 1.0; I just couldn't bring myself to start coding heavily in JavaScript. Version 1.1 gives the ability to perform the 'behind the scenes' coding in languages such as C# and VB.NET (plus others).

Having downloaded Silverlight 1.1, Visual Studio 2008 Beta 2 and Expression Blend, I started looking at development. One thing that becomes apparent very quickly is the lack of any form of controls, this is after all an Alpha release and I am sure this will change very soon. You can download the Silverlight 1.1 SDK which does provide controls such as a button, scrollbar, list box, etc. Ever the developer, I decided to have a go at implementing my own simple button control and this article is the result of my development work so far.

The Visual Studio solution file accompanying this article was produced using Visual Studio 2008 Beta 2. I am using the Standard Edition, which weighs in at around 700+ Mb as an ISO file.  It is possible to use Visual Studio 2005 with a little tweaking of a solution file, information on how to do this is readily available on the net.

The Button Control

It is fair to say that this is a very simple control; it's not a particularly pretty looking button. The sole purpose of the exercise was to see how complex implementing your own control was. The button has a rollover effect and animates upon being clicked, this to me is good enough for a simple button.

button1.jpg
Figure 1 - No roll over effect

button2.jpg
Figure 2 - Roll over effect (notice the shade of blue around the edge)

There are two elements to this button, the XAML which defines the look of the button (rectangles and colours, etc) and the 'code behind' the XAML. I used Expression Blend to produce the XAML and then tweaked it by hand. I am not going to show the whole XAML for the button within the article as there is a fair amount of it, but I will be explaining the pertinent parts of it.

The XAML

I generated the layout of the button first, this obviously gave me something to work with when adding functionality, such as events, etc. Below is the XAML for defining the button rectangle.

<Rectangle Width="180" Height="34" RadiusX="5" RadiusY="5"
 StrokeThickness="1" Stroke="#FF0E0E0E" x:Name="ButtonRectangle" >
  <Rectangle.Fill>
    <LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
      <GradientStop Color="#00909194" Offset="0"/>
      <GradientStop Color="#FF979391" Offset="1"/>
    </LinearGradientBrush>
  </Rectangle.Fill>
</Rectangle>

This defines the button outline and gradient fills the rectangle gray. The edges of the rectangle are also rounded.

The next thing we need for our button is text. Text is displayed using a <TextBlock>. The XAML for this is as follows:

<TextBlock x:Name="ButtonText" Canvas.Left="8" Canvas.Top="5"
 Foreground="#FF101010" Text="Button" FontFamily="Arial" FontWeight="Normal"
 FontSize="12" />

In this version of the button, I have hardcoded the font type and size, but ideally this would be set using properties. The layout of the text on the button surface is performed in code. When the button is clicked, to simulate the button looking like it has been pressed, the X and Y position is adjusted. To adjust the position, I am applying a transform. The XAML for this is as follows:

<Canvas.RenderTransform>
  <TransformGroup>
    <TranslateTransform x:Name="buttonPress" X="0" Y="0" />
  </TransformGroup>
</Canvas.RenderTransform>

As it stands, this transform is doing nothing as X and Y are set to 0. These values are changed programmatically to simulate the press, more on this later.

The Roll over effect

As you saw in figure 2 above, when the mouse pointer is over the button, the edges of the button glow blue. This is very simple to achieve using two rectangles similar to the button surface. Each rectangle is of a slightly smaller size. The two rectangles are defined within their own Canvas. This time the opacity is set as essentially the rectangles are placed over the top of our text. You will notice in the Canvas tag, the Visibility is set to collapsed. We only want the glow to be visible when the mouse pointer is over the button. The glow visibility is changed within code.

Our XAML for the glow effect is:

<Canvas x:Name="MouseOver" Canvas.Top="0" Canvas.Left="0" Width="180"
  Height="34" Visibility="Collapsed">
  <Rectangle Width="178" Height="32" Stroke="#FFB0DAEE" Canvas.Top="1"
    Canvas.Left="1" Opacity=".5" x:Name="MouseOverRectangle1" RadiusX="5"
    RadiusY="5" >
    <Rectangle.Fill>
      <LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
        <GradientStop Color="#00909194" Offset="0"/>
        <GradientStop Color="#FF979391" Offset="1"/>
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
  <Rectangle Width="176" Height="30" Stroke="#FFB0DAEE" Canvas.Top="2"
    Canvas.Left="2" Opacity=".5" x:Name="MouseOverRectangle2" RadiusX="5"
    RadiusY="5" >
    <Rectangle.Fill>
      <LinearGradientBrush EndPoint="0,0" StartPoint="0,1">
        <GradientStop Color="#00909194" Offset="0"/>
        <GradientStop Color="#FF979391" Offset="1"/>
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
</Canvas>

As you can see, the rectangles are almost exactly the same as the button surface. The complete XAML for the button can be found in the MyControl project in MyButton.xaml.

The control code

Now we come on to the C# code for the button. Anyone at ease with writing web custom controls, etc will feel quite at home with coding Silverlight controls. All controls inherit from Control.  To ease the creation of a control, within your Visual Studio solution, create a new Silverlight class and then to that project, right click on the project and select Add => New Item and then select Silverlight User Control. This generates boilerplate XAML and a class enabling you to add your code.

As with all controls, we will be needing properties; our properties will be to set the width and height of the control and also the text appearing on the button. To make the button worthwhile, we will also need to be able to respond to a click event, more on this a little later. Now let's get on with some code.

Within the class, I have defined some private variables and one public event. Our private variables allow us to address individual elements within the XAML.  The first two lines of code within the constructor are generated for us by Visual Studio, these lines of code basically load in the XAML for the control from the assembly. The second line of code that defines actualControl allows us to reference the control and to set references to each of the elements in our XAML. For example, doing the following:

buttonRectangle = actualControl.FindName("ButtonRectangle") as Rectangle;

Will allow us to access the attributes of our button surface.

The rest of the code sets up event handlers for handling the mouse events for our button. A call to UpdateButton is then made. let's take a look at UpdateButton.

buttonRectangle = actualControl.FindName("ButtonRectangle") as Rectangle;
mouseOverRectangle1 = actualControl.FindName("MouseOverRectangle1") as Rectangle;
mouseOverRectangle2 = actualControl.FindName("MouseOverRectangle2") as Rectangle;
mouseOverCanvas = actualControl.FindName("MouseOver") as Canvas;
TextBlock btnText = actualControl.FindName("ButtonText") as TextBlock;

buttonRectangle.Width = _width;
buttonRectangle.Height = _height;
mouseOverRectangle1.Width = _width - 2;
mouseOverRectangle1.Height = _height - 2;
mouseOverRectangle2.Width = _width - 4;
mouseOverRectangle2.Height = _height - 4;

btnText.Text = _buttonText;
double left = (buttonRectangle.Width - btnText.ActualWidth) / 2;
double top = (buttonRectangle.Height - btnText.ActualHeight) / 2;
btnText.SetValue<double>(Canvas.TopProperty, top);
btnText.SetValue<double>(Canvas.LeftProperty, left);

The first 5 lines of code assign references to individual elements defined within the XAML.  After this, we are then setting the width and height of the button surface rectangle and the 2 mouse over rectangles, also not forgetting setting the text we want displayed on the button. We then perform some simple maths to centre the text onto the button surface.

A note on inherited Properties

This class implements the properties Width and Height, so to use these in our control should be a simple matter of doing the following:

public new double Width
{
 get { . . . }
 set { . . . }
}

And in reality it is, but there is a bug in the current Alpha release. If you create an instance of your control in XAML and set the width, it will not be set. If you set the width in code, it works fine, when we come to write code to test our control, I will show you exactly the impact this has. To overcome the problem of setting the buttons text within XAML, I have created the property ButtonText which will allow the buttons text to be defined. Note that within the setter for all the properties, the UpdateButton method is being called; this is because different attributes of the button are being set and we want this reflected in the rendered button.

Mouse events

At the beginning of the article, I mentioned that the control declares a public event called Click. The reason I have done this is because I want to emulate the way controls work in general and 99% of controls have a click event. There is also another reason for this. Within Silverlight, there are two events that are fired when a mouse button is clicked, these are MouseLeftButtonDown and MouseLeftButtonUp. Neither of these two events, on their own, gives the desired click behaviour. What I want to achieve with the Click event is to check if the mouse pointer is over the button when the left button is released. Two other mouse events come into play here, these being MouseEnter and MouseLeave. Let's take a look at what each of these events is doing.

MouseEnter
Within the code, there is a Boolean variable called isPressed. When the left mouse button is pressed this is set to true. When the mouse pointer first enters the button surface we set this variable to false. As we are within the button surface, we want to make the button glow; basically we want to switch on our glow effect. To do this, we simply make the MouseOver canvas  visible, by setting the Visibility attribute to Visibility.Visible. That is all that happens within this event.

MouseLeave
We set isPressed to false. Even if the left mouse button is being held down, if we leave the surface of the button, we do not want the Click event to fire when the button is released, as we are not over the button. We set the MouseOver canvas to Visibility.Collapsed, which hides the canvas. Remember at the beginning of the article we declared a transform within the XMAL which would enable us to animate the button? Well when the mouse leaves the button surface, we want to remove this animation; we simply set the X and Y values of the transform to 0, thus setting the button back to its original position. Even if the button hasn't been pressed and it's still in its original position, we may as well execute this code.

MouseLeftButtonDown
We set isPressed to true, as the mouse button has been pressed. We also increment the X and Y position of the button surface by 2, simulating the button being pressed.

MouseLeftButtonUp
This event holds the key to a correct click event. First we remove the transform on the button as we want it to revert back to its original position. We then check if the button isPressed and the Click event has an event handler 'wired up' to it. If these two conditions are true, we execute the click. We then set isPressed to false.

Testing the control

Within the Visual Studio solution file supplied with this article, there is the project for the actual button and also a project that allows us to test the control. This project was created using the Silverlight Project template. In order to use our new control, there are a couple of things we need to do. First we need to add a reference to our button control; within our test application, we need to right click on the References tree node and when the Add Reference dialog pops up, select the Project tab and select our button project from the list.

When the project was created, some boilerplate XAML was created for the project. This XAML needs to be amended in order to support our control. We need to add an xmlns tag to our XAML to reference the assembly of our control. This takes the form of:

xmlns:MyControls="clr-namespace:MyButton;assembly=ClientBin/MyButton.dll"

With the addition of the above line, the XAML should now look like:

<Canvas x:Name="parentCanvas"
   xmlns="http://schemas.microsoft.com/client/2007
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml
   Loaded="Page_Loaded" 
   x:Class="MyControl.Page;assembly=ClientBin/MyControl.dll"
   xmlns:MyControls="clr-namespace:MyButton;assembly=ClientBin/MyButton.dll"
   Width="640"
   Height="480"
   Background="White">  
</Canvas>

We can now add an instance of our button to the above XAML, the mark-up for our button is:

<MyControls:Button x:Name="Button1" Canvas.Left="20" Canvas.Top="200"  />

This mark-up is placed between the Canvas tag. As with our control, there is an associated C# file where we can manipulate our control programmatically. Within code, we will set the text to be displayed on the button and set its width and height. We will also wire up an event to respond to clicking the button.

Our source code for this is as follows:

Canvas cc = o as Canvas;
MyButton.Button btn = (MyButton.Button)cc.FindName("Button1");
btn.ButtonText = "Press Me!!";
btn.Width = 140;
btn.Height = 35;
btn.Click += delegate(object sender, EventArgs ea)
             {
                btn.ButtonText = "Button Pressed!";
             };

There shouldn't be a great many surprises in the code above. Basically we are setting the text, width and height of the button and wiring-up the Click event. I have wired-up the event the easy way, but it could also have been done as follows:

btn.Click += new EventHandler(btn_Click);

. . .

private void btn_Click(object sender, EventArgs ea)
{
 . . .
}

I did mention the problem with adding inherited properties to the XAML for the button. As an example, the code above sets the width to 140, if I added Width="140" to the XAML, the button would not have rendered correctly. I have blogged about this and an entry can be read on my blog with a link to where I found the information. I am sure this problem will be ironed out in future releases.

posted Jan 20, 2016 by Jdk

  Promote This Article
Facebook Share Button Twitter Share Button LinkedIn Share Button


Related Articles

Its important that when you think in terms of Silverlight controls, you always think in terms of XAML and that means thinking in terms of a Visual Tree.  Elements in the tree have parents and elements in the tree have children.  A popup control is no  different. Although it appears to look like this disassociated control floating around, it really is just another element in the Visual Tree (Unbeknownst to the naked eye).

In order to position a popup relative to an existing control, you should make it a child of the control.   If the control does not allow children, then put the control in a Grid and you can have all the children you want.  Here is an example.
 

  private void OnHoverTab(object sender, MouseEventArgs e)

  {

  var p = new Popup();

  p.DataContext = ((sender as FrameworkElement).Parent as  
            FrameworkElement).DataContext;

  p.Child = new UnderlyingUserControl();  // puts a user control in the popup

  p.VerticalOffset = 25; // this will offset us slightly from the
                          // parent

  p.HorizontalOffset = 0;

  p.IsOpen = true;

   // this is where we add the popup to a Grid we can position
   // against

  ((sender as FrameworkElement).Parent as Grid).Children.Add(p);

  }



Now once we dismiss our popup, it's important to remove it from the Grid, otherwise we'll end up with lots and lots of dead popups in our Grid tree.

I've added an OK and Cancel onto my Underlying user control to dismiss the popup, here is the code behind for the Child of the popup:
 

  private void OnOK(object sender, RoutedEventArgs e)

    {

      ((MyViewModel) DataContext).Name = NameInput.Text;

// Hide the popup and remove from the parent

      (this.Parent as Popup).IsOpen = false;

      ((this.Parent as Popup).Parent as  Grid).Children.Remove(this.Parent asPopup);

    }

 

    private void OnCancel(object sender, RoutedEventArgs e)

    {

    // Hide the popup and remove from the parent

      (this.Parent as Popup).IsOpen = false;

      ((this.Parent as Popup).Parent as Grid).Children.Remove(this.Parent as Popup);

    }

 

READ MORE

This tutorial shows you how to create an animation of a ball being thrown across the screen, landing and bouncing.

Step by Step Tutorial

A brief description of how to use the article or code. The class names, the methods and properties, any tric

  1. Create a new project in Expression Blend. 
     
  2. Draw an ellipse and name the ellipse "ball" 

    image001.jpg
     
  3. The key to creating a bounce effect is to realize that in physics the vertical motion of a ball in motion is completely independent of the horizontal motion. What we're going to do is create two separate story boards for each of these independent motions and then we're going to go into the XAML and combine them into one storyboard. 
     
  4. Create a new storyboard called "Bounce" 
     
  5. Record a keyframe at time 0 for the ball to capture the current position. Then drag the yellow timeline bar to the 1 second position. 

    image002.jpg

 

  1. Now drag the red ball directly up. And record a key frame. At the one second point. Hit play and you should see the ball move directly up at a smooth rate and then stop. 

    image003.jpg

 

  1. Now let's add some gravity. Click on the second keyframe bubble of the storyboard. Set the easing as shown below. This will make the motion slow down as the ball gets to the top of its motion. Confirm this by playing the storyboard. Once you've confirmed this close out the storyboard. 

    image004.jpg

 

  1. Create a storyboard called Horizontal. Create a keyframe at 0 seconds, and then set the timeline to 2 seconds. Drag the ball horizontally to the right and create a keyframe at the 2 second point. Close out the storyboard. 

    image005.jpg

 

  1. Now let's look at the XAML for the Bounce storyboard. Unless you drug the ball perfectly vertically you'll have two sections in the storyboard, one for animating the x direction and one for animation the y direction. You can tell which is which by looking for the line that ends TranslateTransform.Y or TranslateTransform.X. Delete the section that handles the X motion. 
     
  2. Now let's make the ball return to it's starting point. 

    Here's the XAML before hand:

    image006.jpg

    Notice it's moving the ball from a position of 0 to a position of -206 in 1 second. ControlPoint1's value of 0,1 indicates we are going to start at full speed and reach minimum speed at the end of the motion. To make the ball return back down we'll copy the second keyframe, change to time of the key to 2 seconds, change the destination of the animation to 0, and we'll reverse the sense of the easing defined by ControlPoint2. The results are as follows:

    image007.jpg

    Select the bounce storyboard and hit play. You should see the ball go up and down as if it's been thrown up and down.
     
  3. Now let's add the X motion. Take a look at second storyboard we made earlier called horizontal. Copy the DoubleAnimationUsingKeyFrames section that ends TranslateTransform.X and paste it into the Bounce storyboard. Open the bounce storyboard from the design review and hit play. You should see the ball move in a nice smooth arc as if it has been thrown. 

    image008.jpg

 

 

  1. To add a bounce we simply follow the same pattern and add additional key frames. To the DoubleAnimationUsingKeyFrames section that ends TranslateTransform.X add one more keyframe at 3 seconds by adding the following XAML: 

    <SplineDoubleKeyFrame KeyTime="00:00:03" Value="320"/>

    This XAML sets the position that the ball will move to at the end of the third second to 320 which is 22 to the right of where it was in at the end of the previous keyframe. For the vertical portion of the bounce copy the last two keyframes of the DoubleAnimationUsingKeyFrames section that ends TranslateTransform.Y. Set the keyframe time for the peak of the bounce to 2.5 seconds and a height of -20. Have the bounce return to 0 at 3 seconds. This results in the addition of the following XAML:

    <SplineDoubleKeyFrame KeyTime="00:00:02.5" Value="-20">
    <SplineDoubleKeyFrame.KeySpline>
    <KeySpline ControlPoint1="0,1" ControlPoint2="1,1"/>
    </SplineDoubleKeyFrame.KeySpline>
    </SplineDoubleKeyFrame>
    <SplineDoubleKeyFrame KeyTime="00:00:03" Value="0">
    <SplineDoubleKeyFrame.KeySpline>
    <KeySpline ControlPoint1="1,0" ControlPoint2="1,1"/>
    </SplineDoubleKeyFrame.KeySpline>
     
  2. To make the throw occur over and over add a RepeatBehavior to the Storyboard. 

    <Storyboard RepeatBehavior="Forever" x:Name="Bounce">
     
  3. Finally let's add code to start the throw on the load of the page 

    public Page() 

    // Required to initialize variables 
    InitializeComponent(); 
    Loaded += new RoutedEventHandler(PageLoaded); 


    void PageLoaded(object sender, RoutedEventArgs e) 

    Bounce.Begin(); 
    }

     
  4. That's it. Hit F5 and you should see the ball being thrown and bouncing.
READ MORE
 

The great thing about XAML is that you can easily change the foreground colour of controls, such as a TextBlock, to be exactly what you want it to be. Whether that is through the built-in colour names or a HEX colour is completely your choice.

 

However there may be times when you simply wish to change the colour of a control dependent on the value that it is displaying. In this example we will be using a TextBlock that has it's Text value assigned to it using data context binding.

 

MainPage.xaml

<Page        
    x:Class="MainPage"    
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
    xmlns:local="using:TestProject"    
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"        
    mc:Ignorable="d">    
    <Page.Resources>    
        <DataTemplate x:Key="listViewItems">    
            <StackPanel>    
                <TextBlock        
                    Margin="5,5,5,5"        
                    Text="{Binding Name}"        
                    Style="{StaticResource BaseTextBlockStyle}"/>    
                <TextBlock        
                    Margin="5,5,5,5"        
                    Text="{Binding Ripeness}"        
                    Style="{StaticResource BaseTextBlockStyle}"/>    
            </StackPanel>    
        </DataTemplate>    
    </Page.Resources>    
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">    
        <ListView        
            x:Name="listViewTest"        
            Margin="5,5,5,5"        
            VerticalAlignment="Center"        
            HorizontalAlignment="Center"        
            ItemsSource="{Binding}"        
            SelectionMode="None"        
            IsItemClickEnabled="False"        
            ItemTemplate="{StaticResource listViewItems}"        
            ContainerContentChanging="listViewUpdated"></ListView>    
        <TextBlock        
            x:Name="listViewNoItems"        
            Margin="5,5,5,5"        
            VerticalAlignment="Center"        
            HorizontalAlignment="Center"        
            Text="There are no fruits in your list to display!"        
            Style="{StaticResource BaseTextBlockStyle}"        
            Visibility="Collapsed"/>    
        <Button        
            Width="150"        
            Height="50"        
            Margin="20"        
            VerticalAlignment="Center"        
            HorizontalAlignment="Right"        
            Content="Clear fruit"        
            Click="clearFruitBasket"/>    
    </Grid>    
</Page>  

 

MainPage.xaml.cs


using System.Collections.ObjectModel;    
using Windows.UI.Xaml;    
using Windows.UI.Xaml.Controls;    
namespace CSharpCornerTestProject     
{    
    public class Fruit     
    {    
        public string Name    
        {    
            get;    
            set;    
        }    
        public string Ripeness     
        {    
            get;    
            set;    
        }    
    }    
    public sealed partial class MainPage: Page     
    {    
        private ObservableCollection < Fruit > fruitList = new ObservableCollection < Fruit > ();    
        public MainPage()     
        {    
            this.InitializeComponent();    
            fruitList.Add(new Fruit()    
            {    
                Name = "Apple", Ripeness = "Ok"    
            });    
            fruitList.Add(new Fruit()    
            {    
                Name = "Banana", Ripeness = "Bad"    
            });    
            fruitList.Add(new Fruit()    
            {    
                Name = "Kiwi", Ripeness = "Rotten"    
            });    
    
            listViewTest.ItemsSource = fruitList;    
        }    
        private void listViewUpdated(ListViewBase sender, ContainerContentChangingEventArgs args) {    
            if (listViewTest.Items.Count == 0)     
            {    
                listViewNoItems.Visibility = Visibility.Visible;    
                listViewTest.Visibility = Visibility.Collapsed;    
            }     
            else     
            {    
                listViewNoItems.Visibility = Visibility.Collapsed;    
                listViewTest.Visibility = Visibility.Visible;    
            }    
           }    
        private void clearFruitBasket(object sender, RoutedEventArgs e)    
        {    
            // clear the fruit list!        
            if (fruitList != null) fruitList.Clear();    
        }    
    }    
}

As I stated above, this is the code base that we used in my previous article about displaying a message once a ListView control no longer has any items in it. We will slightly modify this now so that the ripeness of the fruit in our fruit basket is colour-coded depending on its value.

 

The first thing we need to do is to create a convertor class for us to use when binding data to the list view. This is a very simple affair and just requires you to add a new "Class file" to your project.

 

FruitBasketConvertor.cs

using System;    
using Windows.UI;    
using Windows.UI.Xaml.Data;    
using Windows.UI.Xaml.Media;    
namespace CSharpCornerTestProject.Convertors     
{    
    public class fruitBasketRipenessForegroundConvertor: IValueConverter    
    {    
        public object Convert(object value, Type targetType, object parameter, string language)    
        {    
            string ripeness = (value as string);    
            if (ripeness == "Ok") return new SolidColorBrush(Colors.ForestGreen);    
            else if (ripeness == "Bad") return new SolidColorBrush(Colors.OrangeRed);    
            else if (ripeness == "Rotten") return new SolidColorBrush(Colors.DarkRed);    
            // default return value of lime green      
            return new SolidColorBrush(Colors.LimeGreen);    
        }    
        public object ConvertBack(object value, Type targetType, object parameter, string language)    
        {    
            throw new NotImplementedException();    
        }    
    }    
}  

That is all there is to our file, just those 30 lines. Do take note, however, that we have placed the convertors under their own namespace, CSharpCornerTestProject.Convertors.

 

Using convertors isn't all as daunting as it seems. You create your own custom class, making sure that it derives from IValueConvertor.  Then all we need are two functions.

public object Convert(object value, Type targetType, object parameter, string language)  
{  
    // your convertor code goes here    
}  
public object ConvertBack(object value, Type targetType, object parameter, string language)   
{  
    // your convert back code goes here    
}

The Convert function takes the raw value of your binding and allows you to access anything associated with that, whether it is a class, a string, or anything of your choosing.

 

The ConvertBack function is generally not used all that often and so in our example we are leaving it asthrow new NotImplementedException();. Its main use would be if you wanted to convert the value back to its original state.

 

Returning to the Convert function, this is very simple and there isn't all that much to it at all. All we do here is take the object value and store it into our string variable, ripeness.  

public object Convert(object value, Type targetType, object parameter, string language)   
{  
    string ripeness = (value as string);  
    if (ripeness == "Ok") return new SolidColorBrush(Colors.ForestGreen);  
    else if (ripeness == "Bad") return new SolidColorBrush(Colors.OrangeRed);  
    else if (ripeness == "Rotten") return new SolidColorBrush(Colors.DarkRed);  
    // default return value of lime green      
    return new SolidColorBrush(Colors.LimeGreen);  
}   

Since we have different forms of Ripeness in our Fruit class, we have three separate if statements to determine which colour we should return for our Foreground colour.

 

When converting a Foreground (or Background) XAML member, it expects a SolidColorBrush to be returned and so that is what we are giving it.

 

That is everything that we need to do for the code side of things with our convertor, the next step is much simpler and only requires us to add three new lines of code to the existing MainPage.xaml file that we have.

 

In our Page control, we need to add a new member, highlighted in bold Green.

<Page  
x:Class="MainPage"  
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
    xmlns:local="using:rTestProject"  
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
    xmlns:utils="using:TestProject.Convertors"  
mc:Ignorable="d">  

This will allow us to access the custom convertor class that we just created in FruitBasketConvertor.cs.

 

Now that we have done that, we need to add our convertor function as a page resource and provide it a key. This will allow us to access it when using the binding convertor. Once again, the addition is highlighted in bold Green.

<Page.Resources>  
    <utils:fruitBasketRipenessForegroundConvertor x:Key="ripenessConvertor"/>  
    <DataTemplate x:Key="listViewItems">  
        <StackPanel>  
            <TextBlock      
                Margin="5,5,5,5"      
                Text="{Binding Name}"      
                Style="{StaticResource BaseTextBlockStyle}"/>  
            <TextBlock      
                Margin="5,5,5,5"      
                Text="{Binding Ripeness}"      
                Style="{StaticResource BaseTextBlockStyle}"/>  
        </StackPanel>  
    </DataTemplate>  
</Page.Resources>

Now that we have given our convertor a key, we can access it anywhere in the MainPage.xaml file when we are binding items. We just have one last thing to do now, that is to add a Foreground member to the TextBlock control that is telling us how ripe our fruit is.

<TextBlock    
    Foreground="{Binding Ripeness, Converter={StaticResource ripenessConvertor}}"    
    Margin="5,5,5,5"    
    Text="{Binding Ripeness}"    
    Style="{StaticResource BaseTextBlockStyle}"/>    

That is everything that we need to do to start dynamically changing the foreground colour of our XAML controls dependent on what the value they're displaying is. If you run the app your fruit basket should now show the Ripeness of each fruit in the three different colours that we assigned earlier on whilst creating our convertor function.

 

READ MORE

Introduction:

  1. Open Visual Studio 2008 and create a new project, a WPF application and name it myWpfApplication



    Figure1
     
  2. The new WPF form called Window1 appears in addition to the XAML code editor



    Figure 2
     
  3. Expand the project node in the solution explorer and right click the references menu item, then click add reference context menu item.



    Figure 3
     
  4. Select the .Net tab then add WindowsFormsIntegration assembly reference to the solution. 



    Figure 4
     
  5. Then add another reference, it will be  our well known Windows forms assembly



    Figure 5
     
  6. Now, as the references are added, switch to the C# code by right clicking the Window1 and clicking the view code context menu item

    Do add the two namespaces 

    using System.Windows.Forms;
    using System.Windows.Forms.Integration;
     
  7. Expand the toolbox and go to the bottom, you find there an element witch called WindowsFormHost
     
  8. Drag and drop it into the WPF window or simply add this couple of lines of XAML code into the XAML editor
     

    <my:WindowsFormsHost Margin="18,20,38,73" Name="windowsFormsHost1">

              

    </my:WindowsFormsHost>
     
  9. Take a look on the XAML code, it will look like this
     

    <Window x:Class="myWpfApplication.Window1"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:wf="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"

        Title="Window1" Height="300" Width="300" xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"

             Loaded="Window_Loaded">

        <Grid>

            <WindowsFormsHost Height="100" Margin="39,27,39,0" Name="windowsFormsHost1"   VerticalAlignment="Top" >

               

            </WindowsFormsHost>

     

        </Grid>

    </Window>
     
  10. Within the WindowsFormHost tag, add those lines:
     

    <WindowsFormsHost Height="100" Margin="39,27,39,0" Name="windowsFormsHost1"VerticalAlignment="Top" >

      <wf:ElementHost BackColor="Beige">

        <Button Background="Bisque" Margin="39,27,39,27" Click="Button_Click">Click me  please!</Button>

      </wf:ElementHost>

    </WindowsFormsHost>
     
  11. Now, switch to the code behind zone, you find there the button click event handler  related stub, then implement it as follows
     

    private void Button_Click(object sender, RoutedEventArgs e)

    {

      System.Windows.Forms.MessageBox.Show("My parent is the hosted window form","Message");

    }
     
  12. Do run the application and observe

    wpf6.gif

    Figure 6
READ MORE

The ScrollViewer is an object that represents a scrollable area that contains other visible controls, it could be found within the System.Windows.Controls.  At the contrast of a ScrollBar object, the ScrollViewer is a WPF new feature. So let's discover its principal characteristics through this article.

Imagine that you host an image in your application in such way that its dimensions are bigger than the window. You can make use of a ScrollViewer to enable see the entire image without having the obligation to change the dimension of the given window. Try to host a big image within a given window. Say that the image height and width are both 1000 pixels.

<Window x:Class="myWpfApplication.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:wf="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"

    Title="Window1" Height="300" Width="300" xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"

      Loaded="Window_Loaded" >

            <Image Source="C:\myWpfApplication\myWpfApplication\image.BMP" Width="1000"Height="1000"></Image>

 

The result will be:

ScrollViewer1.gif
 
Figure 1

And even you expand the window. You couldn't get the entire image at the screen level. To prevent this problem you may use the ScrollViewer object as follow:

Replace the above XAML code by this one.

 

<Window x:Class="myWpfApplication.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:wf="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"

    Title="Window1" Height="300" Width="300" xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"

      Loaded="Window_Loaded" >

    <Grid>

    <ScrollViewer VerticalScrollBarVisibility="Visible"

                   HorizontalScrollBarVisibility="Visible">

        <Image Source="C:\myWpfApplication\myWpfApplication\image.BMP" Width="1000"Height="1000"></Image>

    </ScrollViewer></Grid>

</Window>

 

And the result will be

ScrollViewer2.gif
 
Figure  2

Then it is possible to scroll the image.

READ MORE

In a previous article, we discovered how to define and configure a Grid control using XAML. In this second article, I'll demonstrate how to do the same task using the code behind, I mean using C#.

Walkthrough:

1. To do so, create a new WPF project

Figure1

2. Right click on the window and select view code, then replace the existing code by this one

public partial class Window1 : Window

    {

        public Window1() {

            InitializeComponent();

            InitializeGrid();

        }

        private void InitializeGrid() {

            Grid oGrid = new Grid();

            oGrid.Width = 200;

            oGrid.Height = 200;

            oGrid.Background = System.Windows.Media.Brushes.Bisque;

            //Set the rows

            RowDefinition Row0 = new RowDefinition();

            RowDefinition Row1 = new RowDefinition();

            RowDefinition Row2 = new RowDefinition();

            //Set the columns

            ColumnDefinition Col0 = new ColumnDefinition();

            ColumnDefinition Col1 = new ColumnDefinition();

            ColumnDefinition Col2 = new ColumnDefinition();          

            //Add the columns and rows to the Grid control

            oGrid.ColumnDefinitions.Add(Col0);

            oGrid.ColumnDefinitions.Add(Col1);

            oGrid.ColumnDefinitions.Add(Col2);

            oGrid.RowDefinitions.Add(Row0);

            oGrid.RowDefinitions.Add(Row1);

            oGrid.RowDefinitions.Add(Row2);

            //Show the grid lines

            oGrid.ShowGridLines = true;

            this.Content = oGrid;

        }
    }


3. Run the project and observe, a window like this will appear, as you see the grid is visible now

 

The Star definition

it means that the related size could be expressed as weighted proportion of available space, for example, if a size of a given first row is double of a second given row size, then the first one will receive two units of the entire grid size, meanwhile, the second one will have one unit as size. Rows and columns sizes are expressed by this symbol * that represents a unit of size. To do so using C# code, use this code snippet. It should be copied and pasted within the scope of InitializeGrid().

private void InitializeGrid(){

            Grid oGrid = new Grid();

            oGrid.Width = 200;

            oGrid.Height = 200;

            oGrid.Background = System.Windows.Media.Brushes.Bisque;

            //Set the rows

            RowDefinition Row0 = new RowDefinition();

            RowDefinition Row1 = new RowDefinition();

            RowDefinition Row2 = new RowDefinition();

            //Set the columns

            /* This code add the star option to resize the

            First row as double of the rest of columns*/

            ColumnDefinition Col0 = new ColumnDefinition();

            Col0.Width = new GridLength(2, GridUnitType.Star);

    

            ColumnDefinition Col1 = new ColumnDefinition();

            ColumnDefinition Col2 = new ColumnDefinition();          

            //Add the columns and rows to the Grid control

            oGrid.ColumnDefinitions.Add(Col0);

            oGrid.ColumnDefinitions.Add(Col1);

            oGrid.ColumnDefinitions.Add(Col2);

            oGrid.RowDefinitions.Add(Row0);

            oGrid.RowDefinitions.Add(Row1);

            oGrid.RowDefinitions.Add(Row2);

            //Show the grid lines

            oGrid.ShowGridLines = true;

            this.Content = oGrid;

        }

Run the project and the result will be

 

The Pixel definition

It means that the size is defined in terms of pixels such as in the ASP applications. This bellow C# code illustrates how to define a dimension of a given column or row based on pixels.

private void InitializeGrid() {

            Grid oGrid = new Grid();

            oGrid.Width = 200;

            oGrid.Height = 200;

            oGrid.Background = System.Windows.Media.Brushes.Bisque;

            //Set the rows

            RowDefinition Row0 = new RowDefinition();

            RowDefinition Row1 = new RowDefinition();

            RowDefinition Row2 = new RowDefinition();

            //Set the columns

            /* This code add the pixel option to resize the

            First row as double of the rest of columns*/

            ColumnDefinition Col0 = new ColumnDefinition();

            Col0.Width = new GridLength(50, GridUnitType.Pixel);    

            ColumnDefinition Col1 = new ColumnDefinition();

            ColumnDefinition Col2 = new ColumnDefinition();          

            //Add the columns and rows to the Grid control

            oGrid.ColumnDefinitions.Add(Col0);

            oGrid.ColumnDefinitions.Add(Col1);

            oGrid.ColumnDefinitions.Add(Col2);

            oGrid.RowDefinitions.Add(Row0);

            oGrid.RowDefinitions.Add(Row1);

            oGrid.RowDefinitions.Add(Row2);

            //Show the grid lines

            oGrid.ShowGridLines = true;

            this.Content = oGrid;

        }

READ MORE

In this article, I will try to make a representation of the Grid object witch is directly derived from the Panel abstract class and we can say that is a flexible area that contains rows and columns, it plays a role of container in a given WPF window. The grid could be found in the PresentationFramework assembly. The grid control could be used to create a complex layout that gives to the application an attractive and ergonomic look. So let's discover how to configure it using XAML in this part and in second part I will illustrate how to perform the same task using the code behind, I mean C#.

At first look, when a new WPF application is defined, we have the impression that there is not controls but the window one, even if the "<Grid></Grid>" tags are presents, and the first question that one can ask is where are the grid lines if it is a grid really? 

 

Figure 1

I tell you ok try this code:

<Grid ShowGridLines="True">

        <Grid.RowDefinitions>

            <RowDefinition></RowDefinition>

            <RowDefinition></RowDefinition>

            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition></ColumnDefinition>

            <ColumnDefinition></ColumnDefinition>

            <ColumnDefinition></ColumnDefinition>

        </Grid.ColumnDefinitions>       

    </Grid>

I use the <Grid.RowDefinitions> to define a collection of rows and a<Grid.ColumnDefinitions> to define columns collection. In the other hand I use<RowDefinition> to define a row element within the grid control and <ColumnDefinition> to define a column element, and then I set ShowGridLines property to true, it is very important in order to render columns and rows visible. The result will be as follows:

Figure 2

The columns and rows definition mode could be, namely star, Auto or Pixel.

The Star definition

It means that the related size could be expressed as weighted proportion of available space, for example if a size of a given first row is double of a second given row size, then the first one will receive two units of the entire grid size, meanwhile, the second one will have one unit as size. Rows and columns sizes are expressed by this symbol * that represents a unit of size. The XAML code sample illustrates how to define a size based on star definition.

<Grid ShowGridLines="True" >

        <Grid.RowDefinitions>

            <RowDefinition></RowDefinition>

            <RowDefinition></RowDefinition>

            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="2*"></ColumnDefinition>

            <ColumnDefinition></ColumnDefinition>

            <ColumnDefinition></ColumnDefinition>

        </Grid.ColumnDefinitions>       

    </Grid>

The result of the above code is:

Figure 3

The above code sets the first column width as double of the reset of the columns.

The Pixel definition

It means that the size is defined in terms of pixels such as in the ASP applications. This bellow code illustrate how to define a dimension of a given column or row based on pixels

<Grid ShowGridLines="True" >

        <Grid.RowDefinitions>

            <RowDefinition></RowDefinition>

            <RowDefinition></RowDefinition>

            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="100px"></ColumnDefinition>

            <ColumnDefinition></ColumnDefinition>

            <ColumnDefinition></ColumnDefinition>

        </Grid.ColumnDefinitions>       

    </Grid>

And this is a presentation of what could be if such alternative is used

Figure 4

The Auto definition

It means that the size is proportional to the content object size. Once the column or the row width or height is set to auto and there is no object contained with it. It disappears from the grid but it doesn't mean that it is deleted. If you add controls within, it takes exactly the control dimension. For example, if we make a rectification of the previous code

<Grid ShowGridLines="True" >

        <Grid.RowDefinitions>

            <RowDefinition></RowDefinition>

            <RowDefinition></RowDefinition>

            <RowDefinition></RowDefinition>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="Auto"></ColumnDefinition>

            <ColumnDefinition></ColumnDefinition>

            <ColumnDefinition></ColumnDefinition>

        </Grid.ColumnDefinitions>       

    </Grid>

The grid appearance will be

Figure 5

Cut  Width="Auto"  then drag and drop a button into the grid and make sure that it is contained within the row 0 , column 0 grid cellule and this is the XAML button code.

<Button Grid.Column="0" Grid.Row="0" Width="100" Name="button1">Button</Button>

Now, paste Width="Auto" exactly in its previous place and you will observe this. As you see the button is clipped rather that scrolled.

Figure 6

 

READ MORE
...