In this article we will take this proof of concept and demonstrate how through the use of commanding and binding we can virtually eliminate all code behind and implement to a strong MVVM architectural pattern. For more information about silverlight 4 hosting, visit http://www.asphostdirectory. At ASPHostDirectory, we guarantee you will get the best price at an affordable price. Only $ 3.99/month, you will get Silverlight 4 hosting.
Getting Started
We think few would argue with the value of a strong separation of concerns within the design of an application. Over the last year the MVVM pattern has gained popularity in the Silverlight development community. One of the challenges that developers faced in previous versions of the framework was the lack of commanding support in Silverlight. Without commanding many developers had to write there own attached properties, or worse yet, resort to event handling in their code behind, just to deal with responding to a button being clicked. Today both the button and HyperlinkButton support commanding.
Model-View-ViewModel
Even though our sample application will only be a single page, we will still implement the MVVM pattern to eliminate any code in code behind of our MainPage.xaml. MVVM requires that for every View we have a corresponding ModelView (MV) class. Our View will set its DataContext equal to this class and bind all of the views data through public properties.
using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.ComponentModel;
namespace VideoCaptureExample
{
public class MainPageViewModel : INotifyPropertyChanged
{
. . . . .
}
}
In our mainPage.xaml we will initialize our ViewModel class and set our LayoutRoot DataContext to this resource. If our ViewModel required additional context or possibly aservices be injected into its constructor we would opts to use a ViewModel locator that has been stored as a ApplicationResource.
<UserControl x:Class="VideoCaptureExample.MainPage"
. . . .
d:DesignHeight="360" d:DesignWidth="610">
<UserControl.Resources>
<local:MainPageViewModel x:Key="MainViewModel"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource MainViewModel}}">
. . . . . .
</Grid>
</UserControl>
SaveCommand
One of the great advantages to commanding is encapsulation. When an application has a function like “Save” its very likely that more then one action can trigger this behavior. In our example we intend to allow the save to be triggered from a button, right click context menu as well a something being dragged to a specific location on the screen. Creating a command has two parts. First we need to write a class that implements the ICommand interface and second expose it through our view model.. The following is the general format of such a class. When we create commands in Silverlight we like to inject our ViewModel in the event we need to check the state of our view before executing the command.
using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Input;
namespace VideoCaptureExample
{
public class SaveCommand : ICommand
{
private MainPageViewModel _viewModel;
public SaveCommand(MainPageViewModel viewModel)
{
_viewModel = viewModel;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return (_viewModel.SelectedCapture != null) ? true : false;
}
public void Execute(object parameter)
{
Capture capture = parameter as Capture;
if (capture != null)
{
. . . . .
}
}
protected virtual void OnCanExecuteChanged(EventArgs e)
{
var canExecuteChanged = CanExecuteChanged;
if (canExecuteChanged != null)
canExecuteChanged(this, e);
}
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged(EventArgs.Empty);
}
}
}
In the above snippet there are three requirements when implementing the ICommand interface. First we need to define a function called CanExecute. This will be called to determine if a buttons enabled state is set to true or false. What is great about CanExecute is that it eliminates custom business logic to determine if a command can be fired. The second is an Execute method that is called when the user clicks a button referenced by the command. All of our “Save” logic will be placed inside of this method. A argument is passed to this method that allows data to be injected into the call. Setting CommandParameter on a Button will define what gets passed during the execute. The last requirement is the CanExecuteChanged event. We can fire this event anytime we want buttons that are bound to this command to re-evaluate there enabled state.
To implement this command in our ViewModel, we need to expose the class as a property.
private SaveCommand _saveCommand;
public SaveCommand Save
{
get
{
if (_saveCommand == null)
_saveCommand = new SaveCommand(this);
return _saveCommand;
}
}
Once exposed, we can reference the SaveCommand through simple binding applied to the Button’s Command property and CommandParameter. Now each time that a user clicks the “Save” button our command will be fired.
<Button x:Name="saveBtn" Content="Save"
Width="70" Height="22" Margin="10,0,0,0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Command="{Binding Save}"
CommandParameter="{Binding ElementName=listImages, Path=SelectedItem}"/>
DelegateCommand
More often than not our command is not needed outside of the context of a single view. If this is the case, we can delegate the implementation of the CanExecute and Execute to the ViewModel. Lets say for example you have a command like “StartCapture” that is only appropriate for a single View. In this scenario its a lot easier to have the business logic directly in the ViewModel than in a separate class.
Using the same ICommand interface, we can create a reusable class that delegates both of these methods. The following is the most popular approach.
using System;
using System.Windows.Input;
namespace VideoCaptureExample
{
public class DelegateCommand : ICommand
{
private Predicate<object> _canExecute;
private Action<object> _method;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> method)
: this(method, null)
{
}
public DelegateCommand(Action<object> method, Predicate<object> canExecute)
{
_method = method;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_method.Invoke(parameter);
}
protected virtual void OnCanExecuteChanged(EventArgs e)
{
var canExecuteChanged = CanExecuteChanged;
if (canExecuteChanged != null)
canExecuteChanged(this, e);
}
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged(EventArgs.Empty);
}
}
}
To implement this DelegateCommand class we do the following in our ViewModel. Notice how our constructor gets passed two delegates, one for CanExecute and one for Execute. Calling this command from XAML is identical to our SaveCommand class.
private DelegateCommand _captureCommand;
public DelegateCommand Capture
{
get
{
if (_captureCommand == null)
_captureCommand = new DelegateCommand(OnCapture, CaptureCanExecute);
return _captureCommand;
}
}
. . . .
private void OnCapture(object parameter)
{
UIElement element = parameter as UIElement;
if (this.CaptureSource != null)
{
. . . .
}
}
. . . .
private bool CaptureCanExecute(object parameter)
{
return (_isCapturingVideo) ? true : false;
}
Using Binding to Avoid Commanding
One of the things that we think a lot developers forget is that TwoWay binding can be a great way to avoid having to create a command or event handler to respond to a user click. Commands are great, but if you don’t need them don’t use them.
If we examine the code below, you will see a bunch of bindings. First, our ListBox.ItemSource is bound to an ObservableCollection<Effect> of effects. This allows us to add effects to the ListBox by simply updating our collection. Second, our ListBox.IsEnabled is bound to a property in our ViewModel. Notice the use of TargetNullValue and FallbackValue. These new properties on the binding extension method allow us to override what gets used in the event the property we are binding to is NULL value. In this example we have a ViewModel property that stores a reference to a capture that has been selected in the ListBox of captures. If nothing is selected, the property is null. Since a null is not a boolean, we use TargetNullValue and FallbackValue to ensure we have a true/false response.
<ListBox Height="50" Name="listEffects" Width="Auto" HorizontalAlignment="Stretch"
ItemsSource="{Binding Path=Effects}"
IsEnabled="{Binding TargetNullValue=true, FallbackValue=false, Path=SelectedCapture}"
ItemTemplate="{StaticResource EffectItemTemplate}"
ItemsPanel="{StaticResource WrapItemPanel}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto" >
</ListBox>
Another place we use binding is in the DataTemplate of this list box. Here we will bind both the Effect of the rectangle and its Fill. Our Effect will get bound to the ShaderEffect property of this item being rendered , while the Fill will navigate back to the main DataContext and bind to a property called Brush located within our MainPageViewModel. This property might be a SolidBrush, VideoBrush or even an ImageBrush of an existing capture.
<DataTemplate x:Key="EffectItemTemplate">
<Border BorderThickness="1" BorderBrush="Black" CornerRadius="2"
HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0,3,0">
<Rectangle Width="48" Height="36" Stretch="Fill"
Effect="{Binding ShaderEffect}"
Fill="{Binding Source={StaticResource MainViewModel}, Path=Brush}" />
</Border>
</DataTemplate>
So that ensures that our list of effects looks correct, but how exactly does our rectangle displaying our live webcam video with the correct ShaderEffect applied?
Again we lean on Binding to avoid any procedural code. using ElementName binding we bind the styled buttons Effect property to the SelectedItem of our ListBox of effects. Now each time a user clicks on an item in our list of effects the rectangles will change immediately.
<Button Name="rectVideo"
Style="{StaticResource RectangleButtonStyle}"
Width="320" Height="240"
Effect="{Binding ElementName=listEffects, Path=SelectedItem.ShaderEffect, Mode=TwoWay}"
Command="{Binding Capture}"
CommandParameter="{Binding ElementName=rectVideo}"/>
What is so SPECIAL on ASPHostDirectory.com Silverlight Hosting?
We know that finding a cheap, reliable web host is not a simple task so we’ve put all the information you need in one place to help you make your decision. At ASPHostDirectory, we pride ourselves in our commitment to our customers and want to make sure they have all the details they need before making that big decision.
We will work tirelessly to provide a refreshing and friendly level of customer service. We believe in creativity, innovation, and a competitive spirit in all that we do. We are sound, honest company who feels that business is more than just the bottom line. We consider every business opportunity a chance to engage and interact with our customers and our community. Neither our clients nor our employees are a commodity. They are part of our family.
The followings are the top 10 reasons you should trust your online business and hosting needs to us:
- FREE domain for Life - ASPHostDirectory gives you your own free domain name for life with our Professional Hosting Plan and 3 free domains with any of Reseller Hosting Plan! There’s no need to panic about renewing your domain as ASPHostDirectory will automatically do this for you to ensure you never lose the all important identity of your site
- 99,9% Uptime Guarantee - ASPHostDirectory promises it’s customers 99.9% network uptime! We are so concerned about uptime that we set up our own company to monitor people’s uptime for them called ASPHostDirectory Uptime
- 24/7-based Support - We never fall asleep and we run a service that is opening 24/7 a year. Even everyone is on holiday during Easter or Christmast/New Year, we are always behind our desk serving our customers
- Customer Tailored Support - if you compare our hosting plans to others you will see that we are offering a much better deal in every aspect; performance, disk quotas, bandwidth allocation, databases, security, control panel features, e-mail services, real-time stats, and service
- Money Back Guarantee - ASPHostDirectory offers a ‘no questions asked’ money back guarantee with all our plans for any cancellations made within the first 30 days of ordering. Our cancellation policy is very simple - if you cancel your account within 30 days of first signing up we will provide you with a full refund
- Experts in Silverlight Hosting - Given the scale of our environment, we have recruited and developed some of the best talent in the hosting technology that you are using. Our team is strong because of the experience and talents of the individuals who make up ASPHostDirectory
- Daily Backup Service - We realise that your website is very important to your business and hence, we never ever forget to create a daily backup. Your database and website are backup every night into a permanent remote tape drive to ensure that they are always safe and secure. The backup is always ready and available anytime you need it
- Easy Site Administration - With our powerful control panel, you can always administer most of your site features easily without even needing to contact for our Support Team. Additionally, you can also install more than 100 FREE applications directly via our Control Panel in 1 minute!
Happy Hosting!