Tuesday, February 4, 2014

Async Command Call in WPF MVVM


Something Like below. this is straightforward, and I am not going to explain in details:


    public class MainWindowViewModel:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public ICommand AddCommand { get; set; }
        private ObservableCollection < Trade> trades=new ObservableCollection < Trade>();
        public ObservableCollection < Trade> Trades
        {
            get { return this.trades; }
            set
            {
                this.trades = value;
                NotifyPropertyChanged("Trades");
            }
        }
        public MainWindowViewModel()
        {
            this.AddCommand=new AsynAddCommand(this);
        }
        public bool CanAdd()
        {
            return true;
        }
        public async Task Add()
        {
            for (int i = 1; i <=10; i++)
            {
                Trades.Add(await  NewTrade(i));
            }
        }
        public async Task < Trade> NewTrade(int i)
        {
            await Task.Delay(1000);
            return new Trade() {TradeId = i.ToString(), Price = 100*i, Volume = 20*i};
        }
        private void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                this.PropertyChanged(this,new PropertyChangedEventArgs(info));
            }
        }
    }
    public class AsynAddCommand : ICommand
    {
        private MainWindowViewModel _vm;
        public AsynAddCommand(MainWindowViewModel vm)
        {
            _vm = vm;
        }
        public bool CanExecute(object parameter)
        {
            return _vm.CanAdd();
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        public async void Execute(object parameter)
        {
            _vm.Add();
        }
    }

Monday, September 30, 2013

async/await Related

When the Main() method returns, the program usually ends, so the async keyword is not allowed to add before the Main entry.

The await keyword is placed in an async method. The async keyword indicates the method may contain async code. async Method can Return Task< TResult>, Task or void. By Lucian Wischik's blog(http://blogs.msdn.com/b/lucian/archive/2013/02/18/talk-the-new-async-design-patterns.aspx), Async void is a "fire-and-forget" mechanism: the caller is unable to know when an async void has finished, and the caller is unable to catch any exceptions from it. The only case where this kind of fire-and-forget is appropriate is in top-level event-handlers. Every other async method in your code should return "async Task". (or Task< TResult>)

For the eventhandlers called method, it can have async keyword: For example:

private async void Button1_Click(object sender, EventArgs args)
{
Textbox1.Text=await Task.Run(()=>SomeLongtimeWorktoGetText());
}

//notice for the async void Method, it is not able to do try/cath exception and as the return is void,
//it is not awaitable(e.g. Task has GetAwaiter() method) so it is not able to be used in other async/await block

In the Console application, we can do the samething writing async/await pattern:

class Program
{
static void Main(string[] args)
{

Task task=TestAsync();

//....

//notice if we want to synchronize the task we cannot use await task, and also the task is in the
//Status "Running", we cannot use Start() method to start it again.

task.Wait();

//...
}
}

public static async Task TestAsync()
{
Task t=Task.Run(()=>SomeLongtimeWork());

Console.WriteLine(await t);

}

public static int SomeLongtimeWork()
{
//...
return 1;
}


A bit more code added here:

class Program
{
static void Main(string[] args)
{

Task< int> task=TestAsync2(5);

//...
//notice that only the task is in a Status of "RantoCompletion" can we get the Result property,
// so the code to use task.Result will make our code synchronous as well,

Console.WriteLine(task.Result);
//...
}
}

public static async Task< int> TestAsync2(int i)
{
return await Task.Run(()=>SomeLongtimeWork2(i));

}

public static int SomeLongtimeWork2(int i)
{
//...
return i;
}



Friday, July 6, 2012

Async WCF Service

1. Service Contracts

[ServiceContract]
public interface ITestService
{

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginCallTestProcedure(int i,AsyncCallback asyncCallback, Object state);


int EndCallTestProcedure(IAsyncResult result);
}

2. Service Implementation:

public class TestService:ITestService
{
public IAsyncResult BeginCallTestProcedure(int i, AsyncCallback asyncCallback, object state)
{
Func invokeOperation=(x) => new ProcedureWorker().CallTestProcedure(x);
return invokeOperation.BeginInvoke(i, asyncCallback, state);
}


public int EndCallTestProcedure(IAsyncResult iAsyncResult)
{
var asynResult = (System.Runtime.Remoting.Messaging.AsyncResult)iAsyncResult;
var func = (Func)asynResult.AsyncDelegate;
return func.EndInvoke(iAsyncResult);
}
}


public class ProcedureWorker
{
public int CallTestProcedure(int i)
{
for (int j = 0; j < 3; j++)
{
Console.WriteLine(j);
Thread.Sleep(1000);
}
return i+1;
}
}

3. Client Side Invoke:

var wcfClient=....
var result= wcfClient.BeginCallTestProcedure(3,null,null);
Console.WriteLine(wcfClient.EndCallTestProcedure(result));

Friday, October 28, 2011

Write a Glass Window Behavior



The following effect can be achieved using WPF Shell Integration Library and WPF Customizable Window, the purpose of this article is to use the behavior and dwmapi to manager forms.

There are glass behavior in the Expression Gallery. See Link and Link.

By read his code, the author uses the ShaderEffectLibrary.

By reading this artile, we knows how to create a glass window. And by reading the discussion here, we know how to hide the close/max/min button in a form.

In this case my this article will talking about writing a behavior which can make a glass window, Like the following picture.





For .Net 4.0, we can use the code:

var window=new Window();

var handle=new WindowInteropHelper(window).EnsureHandle();

to make sure that the handle will be created. See the discussion here. So if it is .Net 4.0, to create the behavior is pretty simple.

You can download my code here.

or below:

namespace GlassWindowBehaviorTest

{ using System;

using System.Runtime.InteropServices;

using System.Windows;

using System.Windows.Interactivity;

using System.Windows.Interop;

using System.Windows.Media;

///

/// TODO: Update summary.

///

public class GlassWindowBehavior : Behavior<Window>

{

#region Constants and Fields

///

/// The gw l_ style.

///

private const int GWL_STYLE = -16;

///

/// The w s_ sysmenu.

///

private const int WS_SYSMENU = 0x80000;

#endregion

#region Public Methods

///

/// The create glass window.

///

///

/// The window.

///

public void CreateGlassWindow(Window window)

{

window.Background = new SolidColorBrush(Colors.Transparent);

IntPtr windowInteropHelper = new WindowInteropHelper(window).EnsureHandle();

IntPtr myHwnd = windowInteropHelper;

SetWindowLong(myHwnd, GWL_STYLE, GetWindowLong(myHwnd, GWL_STYLE) & ~WS_SYSMENU);

HwndSource mainWindowSrc = HwndSource.FromHwnd(myHwnd);

mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);

var margins = new Margins { cxLeftWidth = -1, cxRightWidth = -1, cyTopHeight = -1, cyBottomHeight = -1 };

DwmExtendFrameIntoClientArea(myHwnd, ref margins);

}

#endregion

#region Methods

///

/// The on attached.

///

protected override void OnAttached()

{

Window window = this.AssociatedObject;

this.AssociatedObject.Loaded += (s, e) => this.CreateGlassWindow(window);

base.OnAttached();

}

///

/// The on detaching.

///

protected override void OnDetaching()

{

base.OnDetaching();

}

///

/// The dwm extend frame into client area.

///

///

/// The hwnd.

///

///

/// The p mar inset.

///

///

/// The dwm extend frame into client area.

///

[DllImport("DwmApi.dll")]

private static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref Margins pMarInset);

///

/// The get window long.

///

///

/// The hwnd.

///

///

/// The n index.

///

///

/// The get window long.

///

[DllImport("user32.dll", SetLastError = true)]

private static extern int GetWindowLong(IntPtr hwnd, int nIndex);

///

/// The set window long.

///

///

/// The hwnd.

///

///

/// The n index.

///

///

/// The dw new long.

///

///

/// The set window long.

///

[DllImport("user32.dll")]

private static extern int SetWindowLong(IntPtr hwnd, int nIndex, int dwNewLong);

#endregion

///

/// The margins.

///

[StructLayout(LayoutKind.Sequential)]

private struct Margins

{

///

/// The cx left width.

///

public int cxLeftWidth;

///

/// The cx right width.

///

public int cxRightWidth;

///

/// The cy top height.

///

public int cyTopHeight;

///

/// The cy bottom height.

///

public int cyBottomHeight;

}

}

}

The problem is for the .net 3.5 or earlier version, there is no EnsureHandle method, WPF guru Pete Brown has a blog on this. I am going to follow his artile to re write my behavior class so that the behavior can be used in .net 3.5 version.


And on msdn,Alexander Yudakov wrote the extension method for EnsureHandle using reflection, this is very cool. So if we have .net 3.5 application, another way to make sure the handle is created, we can use his extension method.

using System.Reflection;
namespace System.Windows.Interop
{
///
/// Provides NetFX 4.0 EnsureHandle method for
/// NetFX 3.5 WindowInteropHelper class.
///

public static class WindowInteropHelperExtensions
{
///
/// Creates the HWND of the window if the HWND has not been created yet.
///

/// An instance of WindowInteropHelper class.
/// An IntPtr that represents the HWND.
/// Use the EnsureHandle method when you want to separate
/// window handle (HWND) creation from the
/// actual showing of the managed Window.

public static IntPtr EnsureHandle(this WindowInteropHelper helper)
{
if (helper == null)
throw new ArgumentNullException("helper");
if (helper.Handle == IntPtr.Zero)
{
var window = (Window)typeof(WindowInteropHelper).InvokeMember("_window",
BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic,
null, helper, null);
typeof(Window).InvokeMember("SafeCreateWindow",
BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
null, window, null);
}
return helper.Handle;
}
}
}
Finally what I built a photo frame like this:




Thursday, October 20, 2011

Apply Themes to WPF applications


NuGet command:
PM> Install-Package wpfthemes
As the WPF.Themes is built in Environment .Net 4.0, if we are building our application for .Net 4.0 above version, we can apply themes simply like below:
using WPF.Themes;     

namespace UseNuGetApplyThemes 
{          /// Interaction logic for MainWindow.xaml           public partial class MainWindow : Window     
      {         
          public MainWindow()         
         {             
             InitializeComponent();             
             this.ApplyTheme("WhistlerBlue");         
         }     
     } 
} 
The Themes names can be:
  • ExpressionDark
  • ExpressionLight
  • Rainier
  • RainierPurple
  • RainierOrange
  • RainierRadialBlue
  • Shiny
  • ShinyDarkGreen
  • ShinyDarkTeal
  • ShinyDarkPurple
  • ShinyBlue
  • ShinyRed
  • Bureau
  • BureauBlack
  • BureauBlue
  • Whistler
  • WhistlerBlue
  • DavesGlossyControls
  • DavesGlossyControls
  • UXMusing
  • UXMusingRed
  • UXMusingGreen
  • UXMusingRough
  • UXMusingRoughGreen
  • UXMusingRoughRed
  • UXMusingBubbly
  • UXMusingBubblyBlue
Let's use ILSpy to analyze the WPF.Themes.dll assembly, we w
ill see it use ThemeManager class extension method to apply themes, it is merge the theme to app resources dictionary, so if not .net 4.0 application, like .net 3.5, we can use its ThemeManager class, sometimes we don't want all the themes files included in the assemblies or use other themes not in the above list, we can use its method to apply themes too. Let's post it below:
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
namespace WPF.Themes
{
 public static class ThemeManager
 {
  public static readonly DependencyProperty ThemeProperty = DependencyProperty.RegisterAttached("Theme", typeof(string), typeof(ThemeManager), new FrameworkPropertyMetadata(string.Empty, new PropertyChangedCallback(ThemeManager.OnThemeChanged)));
  public static ResourceDictionary GetThemeResourceDictionary(string theme)
  {
   ResourceDictionary result;
   if (theme != null)
   {
    Assembly assembly = Assembly.LoadFrom("WPF.Themes.dll");
    string uriString = string.Format("/WPF.Themes;component/{0}/Theme.xaml", theme);
    result = (Application.LoadComponent(new Uri(uriString, UriKind.Relative)) as ResourceDictionary);
   }
   else
   {
    result = null;
   }
   return result;
  }
  public static string[] GetThemes()
  {
   return new string[]
   {
    "ExpressionDark", 
    "ExpressionLight", 
    "ShinyBlue", 
    "ShinyRed", 
    "DavesGlossyControls", 
    "WhistlerBlue", 
    "BureauBlack", 
    "BureauBlue", 
    "BubbleCreme", 
    "TwilightBlue", 
    "UXMusingsRed", 
    "UXMusingsGreen", 
    "UXMusingsBubblyBlue"
   };
  }
  public static void ApplyTheme(this Application app, string theme)
  {
   ResourceDictionary themeResourceDictionary = ThemeManager.GetThemeResourceDictionary(theme);
   if (themeResourceDictionary != null)
   {
    app.Resources.MergedDictionaries.Clear();
    app.Resources.MergedDictionaries.Add(themeResourceDictionary);
   }
  }
  public static void ApplyTheme(this ContentControl control, string theme)
  {
   ResourceDictionary themeResourceDictionary = ThemeManager.GetThemeResourceDictionary(theme);
   if (themeResourceDictionary != null)
   {
    control.Resources.MergedDictionaries.Clear();
    control.Resources.MergedDictionaries.Add(themeResourceDictionary);
   }
  }
  public static string GetTheme(DependencyObject d)
  {
   return (string)d.GetValue(ThemeManager.ThemeProperty);
  }
  public static void SetTheme(DependencyObject d, string value)
  {
   d.SetValue(ThemeManager.ThemeProperty, value);
  }
  private static void OnThemeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
   string text = e.NewValue as string;
   if (!(text == string.Empty))
   {
    ContentControl contentControl = d as ContentControl;
    if (contentControl != null)
    {
     contentControl.ApplyTheme(text);
    }
   }
  }
 }
}