Friday, 20 May 2011

Silverlight Wizard Custom Control for sharing

I created a lightweight Silverlight Wizard Custom Control, you can download the dll here:
I also provide a sample project showing you how to use the Wizard dll in your real project, you can download the demo project here:

You can view the live Demo here:

If you want to introduce this control to someone else, please reference my Blog post

Now I briefly introduce how to use this control,
First: you have to reference this Wizard.dll to your project;
Second: you have to host the Wizard in some container, either in a Child Window or just a User Control. I prefer Child Window.
I assuming you are hosting the Wizard in a Child Window

Third: add the following XML namespace: to the Child Window's XAML file:
xmlns:wizard="clr-namespace:Wizard;assembly=Wizard"

Delete the OK and Cancel button, rewrite the XAML codes like this and be careful the core parameters need to be set are
ImagePathUri
TitleText

<Grid x:Name="LayoutRoot" Margin="2">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<wizard:ChunXuWizard
x:Name="createUserWizard"
Grid.Row="0"
Margin="0,-2,0,0"
ImagePathUri="/SilverlightApplication18;component/Images/people.png"
TitleText="Add a new student"
Loaded="createUserWizard_Loaded"
/>
</Grid>

please make sure the image /SilverlightApplication18;component/Images/people.png exist in the Image folder, otherwise Wizard will not show anything in the image block(it's not a big deal, isn't it?)

than in the code-behind event method ... you have to insert the pages which the Wizard would like to slide, I created 4 UserControls and I list the codes here:
ObservableCollection<Control> t = new ObservableCollection<Control>();
t.Add(new StudentDataInputBasicInfomation());
t.Add(new StudentDataInputBasicInfomation2());
t.Add(new StudentDataInputBasicInfomation3());
t.Add(new StudentDataInputBasicInfomation4());
this.createUserWizard.NormalControls = t;
Fourth, Create a new Child Window in your code and show the window, you can see the cool slide Wizard living in your screen, like these screen shot:

Click Next Button




The page will slide to the Next page, and by clicking the Back Button, you can go to previous page, the data will be kept.

Next time, I will introduce some detail of how to use the control.

Enjoy the silverlight

Thursday, 19 May 2011

Telerik Silverlight RadGridView ComboBox Column data binding problem

I am using telerik Silverlight GridView control, one of the cool features is that it has a ComboBox Column, which can enable the developer embad a ComboBox in GridView's column
like this:









While of course you can embad such a ComboBox in regular DataGridView(i mean, in micorsoft silverlight toolkit), but Telerik makes things much eazier..

But if you try to bind data through ViewMode to the ComboBox Column of the RadGridView, you will encounter some serious problem.

Let's design a lightweight project to test this cool features of Telerik(this has be existing for long time, I don;t know why Telerik guys doesn't fix it for so long time)

suppose you have two set of entities, People and Country, like this

public class People
{
public int CountryID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}

public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}

and we has two set of collections which will be used to bind with the RadGridView and ComboBox column in the GridView

private ObservableCollection<People> peoples = new ObservableCollection<People>();
public ObservableCollection<People> Peoples
{
get { return peoples; }
set { peoples = value; }
}

private ObservableCollection<Country> countries = new ObservableCollection<Country>();
public ObservableCollection<Country> Countries
{
get { return countries; }
set { countries = value; }
}

than we assign some value to the two collections


foreach(var x in
new People[] {
new People { CountryID = 0, FirstName = "Sebastain", LastName = "Vettel" },
new People { CountryID = 1, FirstName = "Fernando", LastName = "Alonso" },
new People { CountryID = 2, FirstName = "James", LastName = "Button" }
})
{
Peoples.Add(x);
}


foreach(var x in
new Country[] {
new Country { Id = 0, Name = "Germany" },
new Country { Id = 1, Name = "Spain" },
new Country { Id = 2, Name = "UK" }
})
{
Countries.Add(x);
}

now the Peoples and Countris are ready to be binded to the XAML objects. Bind the DataContext

this.DataContext = this;

let's see the View XAML codes, the RadGridView like this:

<controls:ChildWindow

<telerik:RadGridView x:Name="radGridView"
AutoGenerateColumns="False" ItemsSource="{Binding Peoples}">
<telerik:RadGridView.Columns>
<telerik:GridViewComboBoxColumn
DataMemberBinding="{Binding CountryID}"
UniqueName="Country"
SelectedValueMemberPath="Id"
DisplayMemberPath="Name"
ItemsSource="{Binding Countries}"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding FirstName}" UniqueName="First Name"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding LastName}" UniqueName="Last Name"/>
</telerik:RadGridView.Columns>
</telerik:RadGridView>


Simple and straightforward, and let see the result, like this:









everything is fine. Now let's click the FirstName column, what you will see is like this:







the ComboBox column's content is empty, what's wrong? Is there anything coding problem?

The answer is nothing wrong, this is one of the Telerik Silverlight GridView's  famous bug.

What you have to do is to remove the ItemsSource binding in the XAML side and move the binding in the code-behind, this is ugly, meaning if you have to use MVVM you have to pass some parameters to the ViewMode(at lest the ComboBox object) and breaking the graceful of MVVM.

Let's do some change to meet Telerik's behaviour, remove the ComboBox Binding
<telerik:GridViewComboBoxColumn
DataMemberBinding="{Binding CountryID}"
UniqueName="Country"
SelectedValueMemberPath="Id"
DisplayMemberPath="Name"
ItemsSource="{Binding Countries}"/>
and add this to the code-behind:
((GridViewComboBoxColumn)this.radGridView.Columns["Country"]).ItemsSource = Countries;

Now run the application, everything is as expected.


Monday, 2 May 2011

How to create a borderless window which can be drag and move in Silverlight Out Of Browser Model?

In out of browser model, if you choose Borderless style, the TitleBar will disappear and you can't drag and move the whole window, to solve this problem there are several solution, one of them is to use
Application.Current.MainWindow.DragMove(); method,

Ok, let's create a small application to test this:

Create a Silverlight Application, make sure it will be running in out of browser model. In the MainPage UserControl's LayoutRoot Grid, add two rows and a Rectangle, fill the Rectangle's content with some solid color(here I cheese Blue) like this:
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="10*" />
</Grid.RowDefinitions>
<Rectangle Name="rectangle1" Stroke="Black" StrokeThickness="1" Fill="Blue"/>
</Grid>
The blue Rectangle will be our new TitleBar which could be used to drag and move the whole window. Let's add the core code behind.
Add a MouseLeftButtonDown Event to the Rectangle, like this:
<Rectangle Name="rectangle1" Stroke="Black" StrokeThickness="1" Fill="Blue" MouseLeftButtonDown="rectangle1_MouseLeftButtonDown"/>

Implement the event's code behind:
private void rectangle1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Application.Current.MainWindow.DragMove();
}
Now run the application(make sure it's running in out of browser and Bordless Model), you can see a bordless window with a big blue TitleBar, use mouse to drag and move the title bar, it works just as we expected

one thing I have to mention, to make the Rectangle drag and move, you have to Fill this Rectangle with something, ether you fill with some Color or some other Control. Otherwise, it will not react to the mouse click.

Now, the window could be drag and move, but how to close it? How to maxim it? Minim it? Well the answer are all in the Application.Current.MainWindow.WindowState Property The corresponding method are:
Application.Current.MainWindow.WindowState = WindowState.Maximized;
Application.Current.MainWindow.WindowState = WindowState.Minimized;
Application.Current.MainWindow.WindowState = WindowState.Normal;

Now let's add a content menu to the Blue Rectangle and add Maxim, Minim and Normal command, Like this:

<Rectangle Name="rectangle1" Stroke="Black" StrokeThickness="1" Fill="Blue" MouseLeftButtonDown="rectangle1_MouseLeftButtonDown">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem x:Name="menuMaxin" Header="Maxim" Click="menuMaxin_Click"/>
<toolkit:MenuItem x:Name="menuMinim" Header="Minim" Click="menuMinim_Click"/>
<toolkit:MenuItem x:Name="menuNormal" Header="Normal" Click="menuNormal_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</Rectangle>

To use the Content Menu, You have to add System.Windows.Controls.Input.Toolkit to your project's Reference

let's fill the code behind:
private void menuMaxin_Click(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow.WindowState = WindowState.Maximized;
}

private void menuMinim_Click(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow.WindowState = WindowState.Minimized;
}

private void menuNormal_Click(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow.WindowState = WindowState.Normal;
}


that's, when running the application, you can Maxim, Minim and resume by clicking the content menu

this application is not looked nice, it just telling you how to control Windows behaviour in Out of Browser model, you and add some Icon on the Top-Right corner to make the application more reasonable.