Tuesday, November 30, 2010

WPF - Background Worker Exception Model

In this post, let us discuss about special exception handling mechanism for BackgroundWorker.

Let us create an application with a view with single button. The button click causes some time consuming operation. During this operation, some exception is generated. The XAML definition of the view is as follows:

<Window x:Class="BackgroundWorkerExceptionHandling.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BackgroundWorkerExceptionHandling"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Button Content="Start Work!" Height="97"
HorizontalAlignment="Left" Margin="70,109,0,0"
Name="button1" VerticalAlignment="Top" Width="372"
Command = "{Binding StartWorkCommand}"/>
</Grid>
</Window>

The above view is expecting a class named MainWindowViewModel and using that as its DataContext. It is also expecting that this view model has an ICommand property, StartWorkCommand. We are defining StartWorkCommand as RelayCommand. When this command is executed, we start a BackgroundWorker. Before that we specify handlers for DoWork and RunWorkerCompleted events.

class MainWindowViewModel : DependencyObject
{
[DebuggerNonUserCode]
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}

[DebuggerNonUserCode]
void worker_DoWork(object sender, DoWorkEventArgs e)
{
throw new NotImplementedException();
}

private BackgroundWorker worker;

RelayCommand _startWorkCommand;
public ICommand StartWorkCommand
{
get
{
if (_startWorkCommand == null)
{
_startWorkCommand = new RelayCommand(param => this.StartWork(),
param => this.CanStartWork);
}
return _startWorkCommand;
}
}

public void StartWork()
{
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}

bool CanStartWork
{
get { return true; }
}
}

You can get RelayCommand definition from Josh Smith’s article:

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

Clicking the button, we expect that the application would crash as we have thrown exception in the DoWork. What happened? Let us try to understand! We try to see if we are able to catch the exception using Application’s DispatcherUnhandledException AppDomain’s UnhandledException event. AppDomain’s exception handler makes sense as BackgroundWorker executes in a background thread. From msdn:

“The BackgroundWorker class allows you to run an operation on a separate, dedicated thread.”

[ http://msdn.microsoft.com/en-us/library/4852et58.aspx ]

public partial class MainWindow : Window
{

public MainWindow()
{
InitializeComponent();

Application.Current.DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(Current_DispatcherUnhandledException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}

void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show(string.Format("CurrentDomain_UnhandledException : {0}", e.ExceptionObject.ToString()));
//MessageBox.Show(e.ExceptionObject.ToString());
}

void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
MessageBox.Show(string.Format("Current_DispatcherUnhandledException: {0}", e.Exception.Message));
e.Handled = true;
}
}

Now run the application. Still we are not able to catch it. What is going on? This seems weird as application is also not crashing which happens when there is an exception which is not handled in the application. This makes us belief application is handled somewhere. But where?

I think I have created enough suspense for light hearted ones J. Let me reveal now what is going on. Basically BackgroundWorker handles all exception in DoWork’s handler and provide the details in the handler for RunWorkerCompleted in the argument for RunWorkerCompletedEventArgs. Let us update our example as follows to get the exception in DoWork. Let us update handler for RunWorkerCompleted as follows:

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(string.Format("worker_RunWorkerCompleted: {0}", e.Error.Message));
}
}

Now when we run the application and click the button we get this message box.



As we have seen that RunWorkerCompleted gets raised if DoWork is done execution as a result of completion of work, exception or cancellation from user. If it is raised for any reason other than completion of work then accessing result from RunWorkerCompletedEventArgs.Result would raise a new exception. If we don’t want to handle this exception here then we can just rethrow this exception as below. Then it would be caught by Application.DispatcherUnhandledException ‘s handler.

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
throw e.Error;
}
}

This results in this message box:


In the handler for DispatcherUandledException, we have set Handled as true. If we don’t do it then it would be caught by AppDomain’s exception handler for any thread. The following messagebox is displayed. In this handler, we can no longer stop application from shutting down.



If we are running it outside Visual Studio then generalized OS error message is also displayed:

Monday, November 29, 2010

WPF - Dispatcher.Invoke is an overkill

In this post we discuss that executing a synchronous operation on UI threads can be an overkill. It should only be used with care. As we know, we can use Invoke and BeginInvoke on Dispatcher to execute a synchronous and asynchronous operation on UI thread respectively. Calling Invoke is an overkill.

In order to discuss this point. Let us use both, Invoke and BeginInvoke, in a sample WPF application. The following is a WPF window with two text boxes and a button.

<Window x:Class="WpfDispatcher_OperationInvocation.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="451">
<Grid>
<TextBox Height="30" Margin="175,24,30,0" Name="textBoxInvoke" VerticalAlignment="Top" />
<TextBox Height="30" Margin="175,79,30,0" Name="textBoxBeginInvoke" VerticalAlignment="Top" />
<Label Margin="14,24,0,0" Name="label1" Height="24" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="133">Updated Through Invoke</Label>
<Label Height="32" HorizontalAlignment="Left" Margin="9,77,0,0" Name="label2"
VerticalAlignment="Top" Width="165">Updated Through Begin Invoke</Label>
<Button Height="32" Margin="128,0,146,82" Name="button1" VerticalAlignment="Bottom"
Click="button1_Click" >Update Text</Button>
</Grid>
</Window>

As you can see above, we have two textboxes and a button. We have also specified button1_Click as the Click handler for button1. We are using Invoke for one operation on UI thread and BeginInvoke for other. In both these operations, we are updating the text of one of the text boxes.

public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}

void button1_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(
() =>
{
textBoxInvoke.Dispatcher.Invoke(
new Action(() => textBoxInvoke.Text = "Updated"));

textBoxBeginInvoke.Dispatcher.BeginInvoke(
new Action(() => textBoxBeginInvoke.Text = "Updated"));
});

t.IsBackground = true;
t.Start();
}
}

Whenever we call Invoke or BeginInvoke on a Dispatcher, we are introducing a new work item in the dispatcher queue of the dispatcher. So what is the difference between the two? The answer is that Invoke is a synchronous operation and BeginInvoke is an asynchronous operation.

When we call BeginInvoke on a Dispatcher, it pushes the work item on the queue and returns (1 in above figure) DispatcherOperation which can be used to keep on eye on the status of the execution of the delegate. The calling thread wouldn't wait for anything and goes on any other tasks (2 in above figure). On the other side, Invoke causes the work item to be pushed on the queue. It is pushed based on its DispatcherPriority. Now the calling thread is waiting for this operation to be completed. The work item keeps waiting on the Dispatcher queue when there comes her turn of execution by Dispatcher. The dispatcher executes it. Now the result is returned to the calling thread. There might be many work items in the dispatcher queue with same or greater priority values. Calling an operation like this is lethal for the calling thread cause it could be waiting for a long time.


But there might be certainly situations when you can not go without going synchronous. In the following example, we need the text entered in a text box and show it in a MessageBox.

string enteredText = "";

textBox1.Dispatcher.Invoke(new Action(() => enteredText = textBox1.Text), null);
MessageBox.Show(enteredText);

If we don't call this synchronously then we by the time we reach MessageBox.Show this item hasn't been executed by textBox1's Dispatcher so the text is not yet copied to winTitle so would be showing an empty MessageBox.

We can still wait on work item introduced in Dispatcher using BeginInvoke. Basically BeginInvoke does not have a corresponding “EndInvoke”. Many a times we need to find out when an operation ended before starting another dependent work item. BeginInvoke returns a DispatcherOperation. We can use Status property of DispatcherOperation to find this out. If it is Completed then the dispatcher is done executing this operation and we can go ahead with executing the dependent work item. We can also call Wait() on DispatcherOperation which makes this operation as synchronous which is similar to calling Invoke on Dispatcher. We need to be careful as this can lead to the same issue of deadlock as Invoke when UI and worker thread are waiting for some resource which one is needing and the other has it. DispatcherOperation also supports aborting a work item. When we abort it then it is removed from dispatcher’s queue. It’s state is set as Aborted.
DispatcherOperation dispatcherOperation = 
textBoxBeginInvoke.Dispatcher.BeginInvoke(
new Action(() => textBoxBeginInvoke.Text = "Updated"));

//Any other Task(s)

if (dispatcherOperation.Status != DispatcherOperationStatus.Completed)
{
dispatcherOperation.Wait();
}


Now the last words! Avoid using Invoke on Dispatcher when we are absolutely not sure that we need it, otherwise, use BeginInvoke if it wouldn't be making any difference.

Thursday, November 25, 2010

WPF - Windows' forceful release of mouse capture

In this post, let us discuss about forceful release of mouse capture by Windows in WPF application. We will also be discussing how to get notified about such occurences.

Let us define a Window with two textboxes. We will be updating the two textboxes based on the values of X and Y coordinates of Mouse if it is captured.

<Window x:Class="MouseCaptureExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TextBox Height="25" HorizontalAlignment="Left" Margin="57,12,0,0"
Name="textBoxX" VerticalAlignment="Top" Width="73" />
<TextBox Height="25" HorizontalAlignment="Left" Margin="57,43,0,0"
Name="textBoxY" VerticalAlignment="Top" Width="73" />
<Label Height="25" HorizontalAlignment="Left" Margin="8,10,0,0"
Name="label1" VerticalAlignment="Top" Width="43">X Pos</Label>
<Label Height="25" HorizontalAlignment="Left" Margin="8,41,0,0"
Name="label2" VerticalAlignment="Top" Width="43">Y Pos</Label>
</Grid>
</Window>

Let us override two methods OnMouseUp and OnMouseDown available in Window [Inherited]. We maintain a variable isMouseCaptured to have an idea if mouse is still captured. Initially, we keep it set as false. As user push the mouse button down OnMouseDown() method gets called which sets isMouseCaptured as true. Releasing mouse causes OnMouseUp() method to get called. We are also overriding OnMouseMove(). Here we check if mouse is still captured. If yes, then update the two text boxes with X and Y position of the mouse.

public partial class Window1 : Window
{
private bool isMouseCaptured = false;

public Window1()
{
InitializeComponent();
}

protected override void OnMouseDown(MouseButtonEventArgs e)
{
Mouse.Capture(this);
this.isMouseCaptured = true;

base.OnMouseDown(e);
}

protected override void OnMouseMove(MouseEventArgs e)
{
if (isMouseCaptured)
{
Point mousePosition = Mouse.GetPosition(this);

this.textBoxX.Text = mousePosition.X.ToString();
this.textBoxY.Text = mousePosition.Y.ToString();
}

base.OnMouseMove(e);
}

protected override void OnMouseUp(MouseButtonEventArgs e)
{
Mouse.Capture(null);
this.isMouseCaptured = false;
base.OnMouseUp(e);
}
}

Now click mouse and move keeping the mouse button pressed. On keyboard hit ALT + TAB and select some other application. Leave mouse button this other application. Go back to our wpf application and notice the text boxes still being updated. Since we have release mouse button, we are expecting that mouse move should not cause updating the text boxes values.

Let me explain what has happened. After Hitting ALT + TAB, Windows has forcefully claimed mouse capture from the element. Since it is not capturing mouse anymore so it can not receive mouse events outside itself. That is why releasing mouse outside has not cause OnMouseUp overriden method to be called.

Now this could cause major problem for the application. Some drag operation might still be in progress which could resume as the mouse pointer enters the application.
Some drawing might be drawn and might cause havoc by this mouse enter. So this is a big issue for some applications.

How to fix it?
Luckily when windows claims mouse capture forcefully, WPF notifies the element about this event if the element subscribes with LostMouseCapture attached event. We should be updating our code like this:
public Window1()
{
InitializeComponent();

Mouse.AddLostMouseCaptureHandler(this, Window1_LostMouseCapture);
}

void Window1_LostMouseCapture(object sender, MouseEventArgs e)
{
this.isMouseCaptured = false;
}

In the above code, as the mouse capture is lost by the element, Window1_LostMouseCapture event is raised which sets isMouseCaptured as false. Alternatively, we could subscribe this event like this:
this.LostMouseCapture += new MouseEventHandler(Window1_LostMouseCapture);

This would stop the updates in the text boxes. When we run our application and drag the mouse the window keeps updating itself as follows:

Tuesday, November 23, 2010

WPF - Binding Radio Buttons

In this post we will be discussing how we can bind radio buttons to some property in the view model. Generally one property is bound to one control e.g. string property bound to the Text property of a control. The unique thing with binding RadioButton is that one property is needed to be bound a number of times to the corresponding radio buttons. Most of the times, we have enumeration or boolean based properties in View models which we need to bind to radio buttons.

In order to understand this, let us consider an example form. In this form, we are entering information of sales staff. We have divided our market in three different region. These regions are North, Central and South. A sales staff might belong to any of these regions. If Commission status is turned on for a staff then he will be getting a fixed commission of each transaction brought by him to the company.

In WPF, we can assign radio buttons to different groups. In any group, at most, only one radio button can be checked at a single time. We create two groups, one for region of operation and the other to specify whether it is a commission based staff or not. Let's see the view containing these two groups with radio buttons.
<Window x:Class="WPF_RadioButtonBinding.SalesStaffView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF_RadioButtonBinding"
Title="Window1" Height="354" Width="481">
<Window.DataContext>
<local:SalesStaffViewModel />
</Window.DataContext>
<Window.Resources>
<local:AreaOfOperationConverter x:Key="ConverterAreaOfOperation" />
<local:CommissionStatusConverter x:Key="ConverterCommissionStatus" />
</Window.Resources>
<Grid>
<RadioButton Height="19" HorizontalAlignment="Left" Margin="25,82,0,0" Name="AreaOfOperationNorth"
IsChecked="{Binding Path=StaffAreaOfOperation, ConverterParameter=North, Converter={StaticResource ConverterAreaOfOperation}}"
GroupName="AreaOfOperation" VerticalAlignment="Top" Width="192">North Region</RadioButton>
<RadioButton Height="19" HorizontalAlignment="Left" Margin="25,107,0,0" Name="AreaOfOperationCentral"
IsChecked="{Binding Path=StaffAreaOfOperation, ConverterParameter=Central, Converter={StaticResource ConverterAreaOfOperation}}"
GroupName="AreaOfOperation" VerticalAlignment="Top" Width="192">Central Region</RadioButton>
<RadioButton Height="19" HorizontalAlignment="Left" Margin="25,132,0,0" Name="AreaOfOperationSouth"
IsChecked="{Binding Path=StaffAreaOfOperation, ConverterParameter=South, Converter={StaticResource ConverterAreaOfOperation}}"
GroupName="AreaOfOperation" VerticalAlignment="Top" Width="192">South Region</RadioButton>
<RadioButton HorizontalAlignment="Left" Margin="25,0,0,113" Name="CommisionStatusActive" Width="192" Height="19"
IsChecked="{Binding Path=StaffCommissionStatus, ConverterParameter=true, Converter={StaticResource ConverterCommissionStatus}}"
GroupName="CommissionStatus" VerticalAlignment="Bottom">Active</RadioButton>
<RadioButton HorizontalAlignment="Left" Margin="25,0,0,88" Name="CommissionStatusInactive" Width="192" Height="19"
IsChecked="{Binding Path=StaffCommissionStatus, ConverterParameter=false, Converter={StaticResource ConverterCommissionStatus}}"
GroupName="CommissionStatus" VerticalAlignment="Bottom">Inactive</RadioButton>
<TextBlock Height="21" HorizontalAlignment="Left" Margin="25,55,0,0" Name="textBlock1"
VerticalAlignment="Top" Width="151" Text="Area of Operation:" FontSize="13" FontWeight="Bold" />
<TextBlock FontSize="13" FontWeight="Bold" HorizontalAlignment="Left" Margin="25,0,0,138"
Name="textBlock2" Text="Commission Status" Width="151" Height="21" VerticalAlignment="Bottom" />
<TextBlock Height="36" Margin="84,9,76,0" Name="textBlock3" VerticalAlignment="Top"
Text="Sales Staff" FontSize="20" HorizontalAlignment="Center" FontWeight="Bold" />
</Grid>
</Window>

The above view is expecting its view model to have two properties, StaffAreaOfOperation and CommissionStatus. As you can see that we have bound the same property with all radio buttons within the same group. We are registering these properties as DependencyProperty with specified default values.
class SalesStaffViewModel : DependencyObject
{
public static DependencyProperty StaffAreaOfOperationProperty =
DependencyProperty.Register("StaffAreaOfOperation", typeof(EnumAreaOfOperation),
typeof(SalesStaffViewModel),
new PropertyMetadata(EnumAreaOfOperation.North));

public EnumAreaOfOperation StaffAreaOfOperation
{
get { return (EnumAreaOfOperation)GetValue(StaffAreaOfOperationProperty); }
set { SetValue(StaffAreaOfOperationProperty, value); }
}

public static DependencyProperty StaffCommissionStatusProperty =
DependencyProperty.Register("StaffCommissionStatus", typeof(bool),
typeof(SalesStaffViewModel), new PropertyMetadata(false));

public bool StaffCommissionStatus
{
get { return (bool)GetValue(StaffCommissionStatusProperty); }
set { SetValue(StaffCommissionStatusProperty, value); }
}
}

The view discussed above is also expecting two converters in the same assembly. The first converter would be used by Area of operations group of radio buttons. This converter would be deciding which value is to be assigned to the DataContext's property based on ConverterParameter specified with binding. These parameters are passed to Converter to be used during conversion logic.
public class AreaOfOperationConverter : IValueConverter
{
#region IValueConverter Members

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
EnumAreaOfOperation param = (EnumAreaOfOperation)Enum.Parse(typeof(EnumAreaOfOperation), (string)parameter);
EnumAreaOfOperation valueToSet = (EnumAreaOfOperation)value;

return (param == valueToSet);
}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Enum.Parse(targetType, (string)parameter);
}

#endregion
}

Below is second converter. This converts the value to a boolean and assigns between view and view models using Convert and ConvertBack methods. This is also using Binding's ConverterParameter.
public class CommissionStatusConverter : IValueConverter
{

#region IValueConverter Members

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (bool.Parse((string)parameter) == (bool)value);
}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (bool.Parse((string)parameter) == (bool)value);
}

#endregion
}

The enumeration for Area of operations is as follows:
public enum EnumAreaOfOperation
{
North,
Central,
South
}

When we run the application, it appears as follows:



You can see that default values are selected in both groups of radio buttons. When you start using this form by selecting these buttons the values are updated in the view models.

Sunday, November 21, 2010

WPF - Modal Dialog missing Keyboard messages

I have noticed a weird behavior with Modal windows in WPF. As we know a modal window is supposed to implement its own message loop. Once this is displayed, all user navigation mouse and keyboard messages targeted to any other window is ignored by main message loop of the application. WPF seems to have issues with keyboard messages and it still seems not to block the keyboard messages under certain scenario. Let me explain this through an example. Let us create a window. We call this WindowModalOwner. This would suppose to be the window opening a modal window. The XAML of the window is as follows:
<Window x:Class="MultiBinding_DifferentVMs.WindowModalOwner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowModelOwner" Height="300" Width="463">
<Grid>
<TextBlock Height="30" Margin="70,10,82,0" Name="textBlock1" VerticalAlignment="Top" Text="Modal Owner Window"
FontFamily="Arial" FontSize="20" HorizontalAlignment="Center" />
<Button Height="54" Margin="71,0,91,53"
Name="btnModal" VerticalAlignment="Bottom" Click="button1_Click">Button</Button>
<TextBox Height="29" Margin="71,49,85,0" Name="textBox1" VerticalAlignment="Top" />
<TextBox Height="31" Margin="71,93,83,0" Name="textBox2" VerticalAlignment="Top" />
</Grid>
</Window>

At the button click, we want to display a Modal Dialog. The code behind is as follows:
public partial class WindowModalOwner : Window
{
public WindowModalOwner()
{
InitializeComponent();
}

private void button1_Click(object sender, RoutedEventArgs e)
{
var wnd = new WindowModalChild();
wnd.ShowDialog();
}
}

The child window is as follows:
<Window x:Class="MultiBinding_DifferentVMs.WindowModalChild"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowModalChild" Height="300" Width="481">
<Grid>
<TextBlock FontFamily="Arial" FontSize="20" Height="30"
Margin="159,63,105,0" Name="textBlock1" Text="Modal Dialog" VerticalAlignment="Top" />
<Button Margin="111,123,69,85" Name="btnTest">Button</Button>
</Grid>
</Window>

Now run the application, it shows the application as follows:



Click the button and chil window would display as follows. Try clicking back the WindowModalOwner window. Since this is a modal dialog, you would not be able to do anything and would just get a beep.


Now experience the weird thing now. Since we have not explicitly set ShowInTaskBar property, the default value is set, which is True. Both window are shown in the taskbar as follows:



Now the weird thing happens. Select WindowModalOwner from taskbar and this would show the window pushing its modal child on the back. You would not be able to click on it and still you just hear the beep. This is expected. Now start navigating through Keyboard using Tab, Ctrl + Tab and space bar. All navigation still works on the owner window. If you set the focus on a button and hit space bar then click also works. What!!!

This is certainly an issue. Now is there a fix for this? There is certainly. Just update the code which shows the child window as follows:
private void button1_Click(object sender, RoutedEventArgs e)
{
var wnd = new WindowModalChild();
wnd.Owner = this;
wnd.ShowDialog();
}

We just have to set the owner of the child window as the current window and everything works now. If you are launching this dialog as a modal window from a Windows form then you can use WindowInteropHelper to set the Winform's parent windows's handle as the owner of this modal window. This is kind of similar issue which is presented here. But he was noticing a slightly different issue but the cause is same.

http://blogs.msdn.com/b/mhendersblog/archive/2005/10/04/476921.aspx

Friday, November 19, 2010

WPF - Passing Parameters to the Page loaded in the Child Frame

WPF supports frame based navigation. We might need to pass some arguments to the page loaded in the frame. In this post, we will be discussing how we can pass arguments to the page being loaded.

This seems to be very common scenario so it must have some common solution. We know that pages are navigated using Navigate() method of NavigationService of the frame. If we look at various overloads of Navigate(), a few overloads seems to be fulfilling our requirement. These overloads are as follows:

1 - NavigationService.Navigate Method (Object, Object)
2 - NavigationService.Navigate Method (Uri, Object)
3- NavigationService.Navigate Method (Uri, Object, Boolean)

The second argument of all the above three methods seems to be passing state to the page being loaded which seems to be available for the page being loaded.
"an object containing navigation state for processing during navigation"

Now we have no overload of Navigate which supports this. Since the problem is presented now, let us discuss one solution to pass parameters to the page being loaded. Let us look at the the lifetime of NavigationService.

1- Navigating
2- NavigationProgress
3- Navigated
4- LoadCompleted

Of these events, LoadCompleted seems to be the one we need. It also makes the argument, passed in NavigationState parameter of Navigate method, available in ExtraData property of NavigationEventArgs of NavigationService.LoadCompleted event. But the thing is that, NavigationService has not been instantiated and not available in the Page constructor. Additionally NavigationService.LoadCompleted event is raised before Loaded event of Page. So we can not subscribe to LoadCompleted in the Page. This timing issue makes our life difficult. Still we need to pass some arguments to the page, but how???



Let us add a page to our project. The XAML of page is as follows:

<Page x:Class="MultiBinding_DifferentVMs.PageNavigation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext ="{Binding RelativeSource={RelativeSource Self}}"
Title="PageNavigation">
<Grid>
<TextBlock Height="43" Margin="12,94,11,0" x:Name="textBlock1" VerticalAlignment="Top"
Text="{Binding MessageFromCallingWindow}"/>
</Grid>
</Page>

So it expects its DataContext to have a property named MessageFromCallingWindow to bind to the Text property of the text block. To keep the example simple, the DataContext is itself. So we need to define a dependency property in the same page. The code behind of the page is as follows:

public partial class PageNavigation : Page
{
public static DependencyProperty MessageFromCallingWindowProperty =
DependencyProperty.Register("MessageFromCallingWindow", typeof(string), typeof(PageNavigation));

public string MessageFromCallingWindow
{
get { return (string)GetValue(MessageFromCallingWindowProperty); }
set { SetValue(MessageFromCallingWindowProperty, value); }
}

public PageNavigation()
{
InitializeComponent();
}
}

Now let us come to the window which would need to navigate to the above page through the frame hosted within. The good thing is that this window can subscribe a handler for the LoadCompleted event of the frame's navigation service.

<Window x:Class="MultiBinding_DifferentVMs.Window_Navigation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window_Navigation" Height="394" Width="501">
<Grid>
<Frame Margin="12,41,12,12" Name="frame1" />
<TextBox Height="27" Margin="0,8,168,0" Name="textBox1" VerticalAlignment="Top"
HorizontalAlignment="Right" Width="244" />
<Label Height="25" HorizontalAlignment="Left" Margin="8,10,0,0" Name="label1"
VerticalAlignment="Top" Width="62">Parameter</Label>
<Button Height="26" HorizontalAlignment="Right" Margin="0,9,55,0"
x:Name="btnNavigate" VerticalAlignment="Top" Width="107" Click="btnNavigate_Click">Navigate</Button>
</Grid>
</Window>

The code behind of the window is as follows:

public partial class Window_Navigation : Window
{
public Window_Navigation()
{
InitializeComponent();
}

private void btnNavigate_Click(object sender, RoutedEventArgs e)
{
this.frame1.NavigationService.Navigate(new Uri("PageNavigation.xaml", UriKind.Relative),
"Hi from calling window!");

this.frame1.NavigationService.LoadCompleted +=
new System.Windows.Navigation.LoadCompletedEventHandler(NavigationService_LoadCompleted);
}

void NavigationService_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
((PageNavigation)e.Content).MessageFromCallingWindow = (string)e.ExtraData;
}
}

When we run the project, the view is displayed as follows:



Clicking the Navigate button navigates to the Page. As the page is loaded and being rendered, LoadCompleted event of navigation service of frame1 is raised. This copies the data passed in object state to the MessageFromCallingWindow property. As discussed above, this data was made available through ExtraData property of EventArgs.



Note:
If we need to pass some values back to the calling window then we can use similar approach of defining some event on the Page and subscribe the handler in the calling window.

If you are a silverlight developer, then you should also be looking at NavigationContext. This allows to pass values to the page through query parameters. You can have a look at here for this:

http://msdn.microsoft.com/en-us/library/system.windows.navigation.navigationcontext.querystring(VS.95).aspx

Thursday, November 18, 2010

WPF - Simulating Key Press using InputSimulator

In Windows Forms, We are used to using SendKeys to simulate key press on our forms. Most of the times I have seen people simulating key press for Print Screen Key. This is available in WindowsForms assembly. So it is not a WPF thing.

http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.aspx

The question is, do we have anything like that available for WPF built in the framework. If not, does somebody has a solution for this. The answer to the first question is “No” (with all the limitations of my knowledge about WPF). The answer to second question is Yes. Michael Noonan has created this solution for WPF community. This still uses Win32’s SendInput method but provides a simpler interface for developers. It is available with Ms-PL license. You can find it here.

http://inputsimulator.codeplex.com/

Let us see this in practice in a sample WPF application. In this example, we are creating a Window with two buttons. Let’s call them “Capture Screen shot” and “Process Screen Shot”. When user clicks “Capture Screen Shot” then it should take a screen shot. “Process Screen Shot” should not be enabled if there is no image in the clipboard. As soon as the image becomes available, it should automatically be enabled. For “Screen Capture”, we will be simulating “PRINT SCREEN” key press through InputSimulator. For enabling the “Process Screen Shot” button, we will be using a RelayCommand with the button. You can find RelayCommand in this amazing Josh Smith’s article. (This is Copy and Paste type of re-usability :))

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

First and foremost, let’s add a reference of InputSimulator assembly to our project.


We define our view as follows:
<Window x:Class="WpfApplication4.ScreenShotProcessorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Title="ScreenShotProcessorView" Height="300" Width="472">
<Window.DataContext>
<local:ScreenShotProcessViewModel />
</Window.DataContext>
<Grid>
<Button Content="Capture Screen Shot" Height="65"
HorizontalAlignment="Left" Margin="92,66,0,0" x:Name="btnCaptureScreenShot"
VerticalAlignment="Top" Width="257" Command="{Binding ScreenShotCaptureCommand}" />
<Button Content="Process Screen Shot" Height="65" HorizontalAlignment="Left"
Margin="94,163,0,0" VerticalAlignment="Top" Width="259"
x:Name="btnProcessScreenShot" Command="{Binding ScreenShotProcessCommand}"
/>
</Grid>
</Window>

The view needs two commands from the DataContext. They are ScreenShotCaptureCommand and ScreenShotProcessCommand. ScreenShotProcessCommand should check if there is an Image in the Clipboard to process. If yes, then just return true. This would enable “Process Screen Shot” button. Since we always have to keep “Capture Screen Shot” button enabled, CanExecute of ScreenShotCaptureCommand always returns true. We define the View Model for the DataContext of our view as follows:

public class ScreenShotProcessViewModel
{
public ScreenShotProcessViewModel()
{
Clipboard.Clear();
}

RelayCommand _screenShotCaptureCommand;
public ICommand ScreenShotCaptureCommand
{
get
{
if (_screenShotCaptureCommand == null)
{
_screenShotCaptureCommand = new RelayCommand(param => this.CaptureScreen(),
param => { return true; });
}
return _screenShotCaptureCommand;
}
}


private void CaptureScreen()
{
InputSimulator.SimulateKeyPress(VirtualKeyCode.SNAPSHOT);
}

RelayCommand _screenShotProcessCommand;
public ICommand ScreenShotProcessCommand
{
get
{
if (_screenShotProcessCommand == null)
{
_screenShotProcessCommand = new RelayCommand(param => this.ProcessCapturedScreenShot(),
param => CanProcess);
}
return _screenShotProcessCommand;
}
}

bool CanProcess
{
get { return (Clipboard.GetImage() != null); }
}


private void ProcessCapturedScreenShot()
{

}
}

As you have seen above, we have cleared the Clipboard when View Model is instantiated. When we run this the view is displayed as follows:


Just click the “Capture Screen Shot” button. Clicking this would send a Key Press of “Print Screen” Command. Now we have an image in the clipboard. This enables the “Process Screen Shot” button.


For the list of Key Codes, you can refer to the following:

http://msdn.microsoft.com/en-us/library/ms927178.aspx

There are other methods in InputSimulator too which can simulate KeyDown, KeyUp for regular or modified keys (CTRL, ALT etc.). It doesn’t use the exact names but you would figure out what to look for simulation of a particular key. Like for PRINT SCREEN, it defines SNAPSHOT instead of VK_SNAPSHOT as in the above table.

Sunday, November 14, 2010

WPF - Supporting Multiple DataSources for same View

I have been asked so many times about supporting multiple datasources for a single view. I have decided to write a separate post about it so that I could refer for the community. The issue is that WPF supports just one DataContext. Many a times we need to show data from different sources to the view.

Some purists might want to say that there should be one view models to the view. All these different datasources should be handled by the View models. The view should just know about its DataContext and bind its control with this DataContext. I agree to this view mostly but there are, sometimes, requirements in which we have to support multiple view models. So how should we bind these different View models to our views.

Since I have made a point now about the severity of the issue, I think that I can jump on the example of doing that. We are creating an example of a simple view in which we have to show CourseName and StudentName in a single TextBox. CourseNmae and StudentName would be from CourseVM and StudentVM respectively. As I discussed above that there can only be one DataContext, so we should be assigning one to the DataContext (CourseVM). We are instantiating the other as a resource to the View (StudentVM)

The definition of two view models are as follows:

CourseVM:
class CourseVM : DependencyObject
{
public static DependencyProperty CourseNameProperty =
DependencyProperty.Register("CourseName", typeof(string), typeof(CourseVM));
public string CourseName
{
get { return (string)GetValue(CourseNameProperty); }
set { SetValue(CourseNameProperty, value); }
}
}

StudentVM:
class StudentVM : DependencyObject
{
public static DependencyProperty StudentNameProperty =
DependencyProperty.Register("StudentName", typeof(string), typeof(CourseVM));
public string StudentName
{
get { return (string)GetValue(StudentNameProperty); }
set { SetValue(StudentNameProperty, value); }
}
}

We also define a Converter for combining StudentName and CourseName. This would be used for MultiBinding so we are defining it as MultiValueConverter. It has to implement IMultiValueConverter from System.Windows.Data namespace.

class CourseStudentConverter : IMultiValueConverter
{

#region IMultiValueConverter Members

public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
string CourseName = (string)values[0];
string StudentName = (string)values[1];

return string.Format("{0} : {1}", CourseName, StudentName);
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}

#endregion
}

In the following view, we are binding using the Converter defined above. We are also binding using StringFormat.
<Window x:Class="MultiBinding_DifferentVMs.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:MultiBinding_DifferentVMs"
Title="Window1" Height="300" Width="300">
<Window.DataContext>
<local:CourseVM CourseName="Neural Networks" />
</Window.DataContext>
<Window.Resources>
<local:StudentVM x:Key="Student" StudentName="Muhammad" />
<local:CourseStudentConverter x:Key="CSConverter" />
</Window.Resources>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Using StringFormat " />
<TextBox>
<TextBox.Text>
<MultiBinding StringFormat="{}{0} : {1}" >
<Binding Path="CourseName" />
<Binding Source="{StaticResource Student}" Path="StudentName" />
</MultiBinding>
</TextBox.Text>
</TextBox>
</StackPanel>
<Border Height="24" />
<StackPanel Orientation="Horizontal">
<Label Content="Using Converter " />
<TextBox>
<TextBox.Text>
<MultiBinding Converter="{StaticResource CSConverter}" >
<Binding Path="CourseName" />
<Binding Source="{StaticResource Student}" Path="StudentName" />
</MultiBinding>
</TextBox.Text>
</TextBox>
</StackPanel>
</StackPanel>
</Window>

When we run the application, the windows is loaded as follows:

Wednesday, November 3, 2010

WPF - Accessing assembly Resources in XAML

In this post, we will be discussing how to access elements from assembly resources. We will be using Pack Uri syntax to access a resource from assembly. Lets use this image as a resource for our first example.


You would have to add this image to the project in order to make it an assembly resource. After adding it, just right click it and specify Build Action as Resource after taking its properties.


In this post, I want to discuss how we can access assembly resources. We would be defining an image as "Resource" and access it in XAML. In the following example, we are accessing the same image as added above. You can see that we can use pack uri syntax to access assembly resources. To display image, we have used Image element. Although most people still call it a Control out of habit but technically Image is not a control in WPF, it is rather FrameworkElement. It is funny because msdn also has this description about it:

"Represents a control that displays an image."
<Window x:Class="WpfApplication4.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" Height="400" Width="500">
<StackPanel>
<Image Source="pack://application:,,/1.jpg" />
</StackPanel>
</Window>

When we run the application, it appears as follows. You can see that it has successfully loaded the image in the Image



Accessing items from other assemblies:
Now we want to discuss how to access items from other assemblies. Lets create a separate project, add an image as Resource in this. Reference this project to the first project. Lets use the image of Mohatta Palace museum at Karachi.


Add this to a new project and specify Build Action as Resource. We update the view in the first project as follows:
<Window x:Class="WpfApplication4.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" Width="500" Height="500">
<StackPanel>
<Image Source="pack://application:,,/1.jpg" Height="250" />
<Image Source="pack://application:,,,/WpfApplication5;component/4.jpg" />
</StackPanel>
</Window>

Please pay special attention to the pack uri syntax used to access resource from other assembly. It is roughly as follows:

pack://application:,,,/OTHER_ASSEMBLY;component/OTHER_RESOURCE.RESOURCE_EXTENSION

When we run this, it appears as follows: