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.

Monday, 25 April 2011

How to load and bind Image in MVVM (2)

Now, In the ImageLoadViewModel.cs file, add Interface INotifyPropertyChanged and a public void OnPropertyChanged(string propertyName) method, code like this:


   1:   using System.ComponentModel;

   2:   

   3:   public class ImageLoadViewModel : INotifyPropertyChanged 

   4:   {
   5:   
   6:       public event PropertyChangedEventHandler PropertyChanged;
   7:       public void OnPropertyChanged(string propertyName)
   8:       {
   9:           if (PropertyChanged != null)
  10:           {
  11:               PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  12:           }
  13:       }
  14:   }


Next, Create a folder called Command and add a GenericCommand class in that folder, like the screenshot:









inherit ICommand interface and implement the codes like this:



   1:  public class GenericCommand : ICommand
   2:  {
   3:      private readonly Action<object> _executeAction;
   4:      private readonly Predicate<object> _canExecute;        
   5:   
   6:      public GenericCommand(Action<object> executeAction, Predicate<object> canExecute)
   7:      {
   8:          if (executeAction == null)
   9:              throw new ArgumentNullException("executeAction");
  10:   
  11:          _executeAction = executeAction;
  12:          _canExecute = canExecute;
  13:      }
  14:   
  15:      public void OnCanExecuteChanged()
  16:      {
  17:          if (CanExecuteChanged != null)
  18:              CanExecuteChanged(this, EventArgs.Empty);
  19:      }
  20:   
  21:      public bool CanExecute(object parameter)
  22:      {
  23:          if (_canExecute == null) return true;
  24:          return _canExecute(parameter);
  25:      }
  26:   
  27:      public event EventHandler CanExecuteChanged;
  28:   
  29:      public void Execute(object parameter)
  30:      {
  31:          _executeAction(parameter);
  32:      }
  33:  }


this is a Generic Command, so we can use it quite freely

Because we are going to bind a Image and a Command to the ViewModel, we have to create an Image and Command Property in ViewModel, add these two properties in ImageLoadViewModel.cs, code like these:


   1:  ICommand imageLoadCommand;

   2:  public ICommand ImageLoadCommand

   3:  {
   4:      get { return imageLoadCommand; }
   5:      set { imageLoadCommand = value; OnPropertyChanged("ImageLoadCommand"); }

   6:  }
   1:  private Image image = new Image();
   2:  public Image MyImage
   3:  {
   4:      get { return image; }
   5:      set { image = value; OnPropertyChanged("MyImage"); }
   6:  }

Next, assign imageLoadCommand the values in the constructor fonction:

   1:  public ImageLoadViewModel()
   2:  {
   3:      ImageLoadCommand = new GenericCommand(loadImage, s => true);
   4:  }
you can see there is a method called loadImage, the code is:

   1:  private void loadImage(object obj)
   2:  {
   3:      if (Application.Current.IsRunningOutOfBrowser)
   4:      {
   5:          string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
   6:          OpenFileDialog openFileDialog = new OpenFileDialog();
   7:          openFileDialog.Filter = "PNG Files (*.png;*.png)|*.png;*.png | All Files (*.*)|*.*";
   8:          openFileDialog.FilterIndex = 1;
   9:   
  10:          if (true == openFileDialog.ShowDialog())
  11:          {
  12:              System.IO.Stream stream = openFileDialog.File.OpenRead();
  13:              BitmapImage bi = new BitmapImage();
  14:              bi.SetSource(stream);
  15:              image.Source = bi;
  16:              stream.Close();
  17:   
  18:              OnPropertyChanged("MyImage");
  19:          }
  20:      }
  21:      else
  22:      {
  23:          MessageBox.Show("please choose photo from disk in Out Of Browser Model");
  24:      }
  25:  }

To select a file from the disk, you have to make sure you are in Out Of Browser model, this is Silverlight's limitation. So I add such a condition;

    3:      if (Application.Current.IsRunningOutOfBrowser)

Now, go to the LoadImage.xaml page and update the content there, 
add a static resource for the user control

   1:   <UserControl.Resources>
   2:       <vm:ImageLoadViewModel x:Key="imageLoadViewModel"/>
   3:   </UserControl.Resources>

Bind ImageLoadCommand and MyImage to the Button and the Image Content of the button

   1:  <Button Grid.Column="1" Grid.Row="1" Name="button1" Command="{Binding ImageLoadCommand}">
   2:      <Image Source="{Binding MyImage.Source}" />
   3:  </Button>

Bind Grid's DataContent to the Static Resource we just created

1:  <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource imageLoadViewModel}">

now the XAML should look like this:

   1:  <UserControl x:Class="ImageLoadDemo.View.ImageLoad"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:      mc:Ignorable="d"
   7:      d:DesignHeight="300" d:DesignWidth="400"
   8:      xmlns:vm="clr-namespace:ImageLoadDemo.ViewModel">
   9:      
  10:      <UserControl.Resources>
  11:          <vm:ImageLoadViewModel x:Key="imageLoadViewModel"/>
  12:      </UserControl.Resources>
  13:   
  14:      <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource imageLoadViewModel}">
  15:          <Grid.ColumnDefinitions>
  16:              <ColumnDefinition Width="90*" />
  17:              <ColumnDefinition Width="230*" />
  18:              <ColumnDefinition Width="80*" />
  19:          </Grid.ColumnDefinitions>
  20:          <Grid.RowDefinitions>
  21:              <RowDefinition Height="79*" />
  22:              <RowDefinition Height="146*" />
  23:              <RowDefinition Height="75*" />
  24:          </Grid.RowDefinitions>
  25:          <Button Grid.Column="1" Grid.Row="1" Name="button1" Command="{Binding ImageLoadCommand}">
  26:              <Image Source="{Binding MyImage.Source}" />
  27:          </Button>
  28:      </Grid>
  29:  </UserControl>

Before running the application, you have to set the ImageLoadDemo as the "StartUp Project", because our demo only works in Out Of Browser model, screen sot like this:


















Now run the application, and click the button, a pop up window will appear asking you to choose picture, by selecting the picture, the content of the Button will become the picture you just selected.

I hope this small project will help you understand how to assign an Image's value in runtime and some basic Command, MVVM concept

thanks for reading, 

you can download the demo project here:

Thursday, 21 April 2011

How to load and bind Image in MVVM (1)

In last post, I briefly described how to load image in run time and bind it to the ViewMode, now I will explain in detail how to do it.


  1. Create a Silverlight Application name it "ImageLoadDemo", see the screen shot:














  2. Create two folders in ImageLoadDemo project, naming them View and ViewModel
    1. In View folder, add a user control named ImageLoad.xaml
    2. inViewModel folder, add a class called ImageLoadViewModel.cs, see the screen shot:










  3. Open the ImageLoad.xaml user control in Visual Studio 2010 and add 3 Rows and 3 Columns to the Grid "LayoutRoot", and put a button in the middle cell, setting its width and length to be full, code like this:

       1:  <UserControl x:Class="ImageLoadDemo.View.ImageLoad"
       2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       4:      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       5:      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       6:      mc:Ignorable="d"
       7:      d:DesignHeight="300" d:DesignWidth="400">
       8:      
       9:      <Grid x:Name="LayoutRoot" Background="White">
      10:          <Grid.ColumnDefinitions>
      11:              <ColumnDefinition Width="90*" />
      12:              <ColumnDefinition Width="230*" />
      13:              <ColumnDefinition Width="80*" />
      14:          </Grid.ColumnDefinitions>
      15:          <Grid.RowDefinitions>
      16:              <RowDefinition Height="79*" />
      17:              <RowDefinition Height="146*" />
      18:              <RowDefinition Height="75*" />
      19:          </Grid.RowDefinitions>
      20:          <Button Content="Button" Grid.Column="1" Grid.Row="1" Name="button1" />
      21:      </Grid>
      22:  </UserControl>

Tuesday, 19 April 2011

How to load and bind Image in MVVM?

I was getting overwhelmed today by a little issue, very little, but enough to waste you several hours, -- the problem is, I have an application  using MVVM, and I have an Image binded to the ViewModel, codes is here:

XAML:

   1:  <Button Height="119" Width="128" BorderBrush="#FFF51B1B" BorderThickness="2" Canvas.Left="413" Command="{Binding ChoosePhotoCommand}" Background="White">
   2:      <Image x:Name="imgPhoto" Source="{Binding MyImage}" />
   3:  </Button>

In the ViewMode, I have a Property MyImage like this:


   1:   Image myImage;
   2:   public Image MyImage
   3:   {
   4:       get { return myImage; }
   5:       set { myImage = value; RaisePropertyChanged("MyImage"); }
   6:   }

The ChoosePhotoCommand Command's code is like this:



   1:  private RelayCommand choosePhotoCommand;
   2:  public RelayCommand ChoosePhotoCommand
   3:  {
   4:      get { return choosePhotoCommand; }
   5:      set
   6:      {
   7:          choosePhotoCommand = value;
   8:          RaisePropertyChanged("ChoosePhotoCommand");
   9:      }
  10:  }

you can see that I am using RelayCommand which is MVVMLight framework, but it's really the same as the normal .net ICommand onject

so in construction, i assign the value for this command, like this:


   1:   public MyViewModel()
   2:   {
   3:       ChoosePhotoCommand = new RelayCommand(choosePhoto, canExecuteChoosePhoto);
   4:   }



   1:  private Image thePhoto = new Image();
   2:  private void choosePhoto()
   3:  {
   4:   
   5:      if (Application.Current.IsRunningOutOfBrowser)
   6:      {
   7:          string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
   8:          OpenFileDialog ofd = new OpenFileDialog();
   9:          ofd.Filter = "PNG Files (*.png;*.png)|*.png;*.png | All Files (*.*)|*.*";
  10:          ofd.FilterIndex = 1;
  11:   
  12:          if (true == ofd.ShowDialog())
  13:          {
  14:              System.IO.Stream stream = ofd.File.OpenRead();
  15:              BitmapImage bi = new BitmapImage();
  16:              bi.SetSource(stream);
  17:              thePhoto.Source = bi;
  18:              stream.Close();
  19:   
  20:              MyImage = thePhoto;
  21:          }
  22:      }
  23:      else
  24:      {
  25:          MessageBox.Show("please choose photo from disk in Out Of Browser Model");
  26:      }
  27:  }  


OK, now if I select any photo from disk(first you have to make sure you are running in Out of Browser model), the binded Image doesn't change, it keep blank, what's wrong?

the problem is here:

2:      <Image x:Name="imgPhoto" Source="{Binding MyImage}" />

You can't bind an Image's Source property to another Image object, that doesn't make sense, you have to bind the Source to another Source, modify the code like this:

2:      <Image x:Name="imgPhoto" Source="{Binding MyImage.Source}" />
this time, the binding is ok. run the application, and everything is as expected

Tuesday, 12 April 2011

I am going to teach you how to create a Silverlight Wizard Control

I created a Wizard Customer Control by using Silverlight 4, the procedure is quite interesting, I have decided to write it down, to teach you step by step how to build an Applied Wizard Control using Silverlight

the screenshot is like this



As I know so far, there is no such control in Silverlight Toolkit or Telerik Controls

I will continue this post this evening....