Wednesday, January 18, 2012

Run WPF application without App.xaml

Delete the existing App.xaml file and write a new class file(lets call it StartUp.cs) that looks like below:
    public class StartUp : Application
    {
        [System.STAThreadAttribute()]
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public static void Main()
        {
            StartUp app = new StartUp();
            app.InitializeComponent();
            app.Run();
        }
        public void InitializeComponent()
        {
            this.StartupUri = new Uri("MainWindow.xaml", System.UriKind.Relative);
        }
    }

Note that this class inherits System.Windows.Application

Tuesday, January 10, 2012

Wire any WPF Event to Command on ViewModel in MVVM

In the last post I explained how to write a behaviour to hook a commmand to an event. That works well but a new behaviour is needed to written for each event. I tried a generic approach to have a single behaviour that can be used to wire any event to a command. It comes witha little performance penalty as reflection is used to get the event and attached a delegate to that event. Below is the code:

using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Windows.Controls;
using System.Reflection;
using System.Diagnostics;

public class CommandExecuter
{
public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(CommandExecuter), new PropertyMetadata(CommandPropertyChangedCallback));

public static readonly DependencyProperty OnEventProperty = DependencyProperty.RegisterAttached("OnEvent", typeof(string), typeof(CommandExecuter));

public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(CommandExecuter));

public static void CommandPropertyChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs args)
{
  string onEvent = (string)depObj.GetValue(OnEventProperty);
  Debug.Assert(onEvent != null, "OnEvent must be set.");
  var eventInfo = depObj.GetType().GetEvent(onEvent);
  if (eventInfo != null)
  {
    var mInfo = typeof(CommandExecuter).GetMethod("OnRoutedEvent", BindingFlags.NonPublic | BindingFlags.Static);
    eventInfo.GetAddMethod().Invoke(depObj, new object[] { Delegate.CreateDelegate(eventInfo.EventHandlerType, mInfo) });
  }
  else
  {
    Debug.Fail(string.Format("{0} is not found on object {1}", onEvent, depObj.GetType()));

}

}
public static ICommand GetCommand(UIElement element)
{
   return (ICommand)element.GetValue(CommandProperty);
}
public static void SetCommand(UIElement element, ICommand command)
{
   element.SetValue(CommandProperty, command);
}
public static string GetOnEvent(UIElement element)
{
return (string)element.GetValue(OnEventProperty);
}
public static void SetOnEvent(UIElement element, string evnt)
{
   element.SetValue(OnEventProperty, evnt);
}
public static object GetCommandParameter(UIElement element)
{
  return (object)element.GetValue(CommandParameterProperty);
}
public static void SetCommandParameter(UIElement element, object commandParam)
{
   element.SetValue(CommandParameterProperty, commandParam);
}
private static void OnRoutedEvent(object sender, RoutedEventArgs e)
{
  UIElement element = (UIElement)sender;
  if (element != null)
  {    ICommand command = element.GetValue(CommandProperty) as ICommand;
    if (command != null && command.CanExecute(element.GetValue(CommandParameterProperty)))
    {
      command.Execute(element.GetValue(CommandParameterProperty));
    }
  }
}
}


Below code shows how to set the command on the controls for any event:   (local: is namespace prefix)
<ComboBox local:CommandExecuter.Command="{Binding CommandImpl}" local:CommandExecuter.OnEvent="SelectionChanged" ></ComboBox>

<Button local:CommandExecuter.Command="{Binding AnotherCommandImpl}" local:CommandExecuter.OnEvent="MouseEnter" local:CommandExecuter.CommandParameter="{x:Static null}"></Button>


Monday, January 9, 2012

Execute Command on ComboBox Selection changed

If you are developing WPF application MVVM way you might have noticed that Button Provide a Command property that can be set to a ICommand instance and the command will be executed when button is clicked. There is no inbuilt way to set a Command that can be executed when ComboBox selection is changed. I have coded a behaviour that can be used to achieve this. Below is the code for the behaviour.

using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Windows.Controls;
public class SelectionChangedBehaviour
{
 
public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand),
  typeof(SelectionChangedBehaviour), new PropertyMetadata(PropertyChangedCallback));

  public static void PropertyChangedCallback(DependencyObject depObj, DependencyPropertyChangedEventArgs args)
  {
   
Selector selector = (Selector)depObj;
    if (selector != null)
    {
      selector.SelectionChanged +=
new SelectionChangedEventHandler(SelectionChanged);
    }
  }


 
public static ICommand GetCommand(UIElement element)
  {
   
return (ICommand)element.GetValue(CommandProperty);
  }

 
public static void SetCommand(UIElement element, ICommand command)
  {
    element.SetValue(CommandProperty, command);
  }

  private static void SelectionChanged(object sender, SelectionChangedEventArgs e)
  {
   
Selector selector = (Selector)sender;
    if (selector != null)
    {
     
ICommand command = selector.GetValue(CommandProperty) as ICommand;
      if (command != null)
      {
        command.Execute(selector.SelectedItem);
      }
    }
  }
}


Set the command in xaml as shown below:

<ComboBox SelectionChangedBehaviour.Command="{Binding CommandImpl}">ComboBox>

This can be used for ListBox and ListView as well.

Type based templating

            <DataTemplate DataType="{x:Type vm:SampleViewModel}">                 <DataTemplate.Resources>       ...