Rajnish Noonia

Year: 2010

  • Silverlight 4.0 with WCF Ria (2008)

    Visual studio 2010 comes with nice Silverlight designer, But for LOB applications you always need data which can be pumped only via WCF RIA service (assuming you want to finish the project ASAP). Lot of programmers have still issues with WCF RIA 1.0 (for Vs2010) in terms of publishing the application on shared hosting domain. Actually this problem is because of not having correct version of .net framework on shared hosting domains. Example – my hosting provider has .net version 4.0.2xxx installed on web server. With 4.0.2 i got error saying Unrecognized attribute ‘multipleSiteBindingsEnabled’ where as on local machine i am having 4.0.3, and hosting provider will not install .net version on shared hosting domain until it get stable and they get some confidence ..So till than are we going to use Silverlight 3 ??

    Well in my previous post i have tried to fix issues with WCF RIA on shared hosting domain which is working fine. Note that this fix is for WCF RIA Beta 1 which is compiled for Vs 2008. There is no fix available which could be applied to WCF RIA 1.0 (for 2010) in similar way. What we are going to do here is use best out of what we have i.e SL 4.0 + Vs2010 and WCF RIA + Vs2008.

    Jumping directly to the point : How to work with Silverlight 4.0 (VS 2010) and WCF RIA (VS 2008)..

    What you required:

    1. Vs 2008 with WCF RIA Beta
    2. Vs 2010 with Silverlight 4.0

    How to build:

    1. Create WCF RIA Service Library using Visual Studio 2008. –
      1. Above step will create two libraries -one for silverlight project (client) and another for web server project.
    2. Create another Silverlight business app using Visual Studio 2008
      1. Add above assemblies to both projects (Sl+Web).- test it.
      2. Now delete the SL project created in step 2. we will only need wcf-web project from step 2.
    3. Now Open Vs 2010 and open the web project (existing) created in step 2 above.This will migrate you project from VS 2008 to 2010.
    4. Add new silverlight project to above solution.
    5. Go to properties of web project and link it with silverlight project in the group.

    And that it !

    For silverlight application you will use VS 2010 (framework 3.5) and for Ria service you need to launch Vs 2008 (project in step 1).

    While you try to publish app on shared hosting domain,the fix which is provided in my previous articles can be applied. The WCF RIA libraries generated in step 1 could be migrated to WCF RIA 1.0 if in future issues with WCF got resolved and you need not to change you silverlight app.

    I still need to test the solution mentioned above (althought i had quick test before writting this article) to ensure that we are not lossing any thing..

    Let me know if template project is required for this, i will be glad to help..

    So what you are thinking now go-ahead….

     You may need to refer fix2 to catch exceptions from server..

  • Network Indicator

    Silverlight application can be designed in a way to work even in offline mode. Essentially Silverlight application is desktop based application running on client machine once downloaded from web server. Silverlight is capable to save data into local isolated storage area or upload data to WCF RIA service.
    This control provide nice 3d led (Red and Green) and transitioning from red to green or vice-vera will occur when network status is changed.
    The live application is available here : Live network indicator

    The demo application also shows the smartkey (shortcut keys) navigation for silverlight, which i will post in Separate article alone with source code.

    Xaml for the control is :

    <Grid x:Name="LayoutRoot" Background="Transparent" >
    <VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="CommonState">
    <VisualState x:Name="OnlineState">
    	<Storyboard>
    		<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="OnlineElement" Storyboard.TargetProperty="(UIElement.Opacity)">
    			<EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    			<EasingDoubleKeyFrame KeyTime="00:00:01" Value="1"/>
    		</DoubleAnimationUsingKeyFrames>
    		<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="OfflineElement" Storyboard.TargetProperty="(UIElement.Opacity)">
    			<EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    			<EasingDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
    		</DoubleAnimationUsingKeyFrames>
    		<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="OfflineElement" Storyboard.TargetProperty="(UIElement.Visibility)">
    			<DiscreteObjectKeyFrame KeyTime="00:00:00">
    				<DiscreteObjectKeyFrame.Value>
    					<Visibility>Visible</Visibility>
    				</DiscreteObjectKeyFrame.Value>
    			</DiscreteObjectKeyFrame>
    			<DiscreteObjectKeyFrame KeyTime="00:00:01">
    				<DiscreteObjectKeyFrame.Value>
    					<Visibility>Collapsed</Visibility>
    				</DiscreteObjectKeyFrame.Value>
    			</DiscreteObjectKeyFrame>
    		</ObjectAnimationUsingKeyFrames>
    		<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="OnlineElement" Storyboard.TargetProperty="(UIElement.Visibility)">
    			<DiscreteObjectKeyFrame KeyTime="00:00:00">
    				<DiscreteObjectKeyFrame.Value>
    					<Visibility>Collapsed</Visibility>
    				</DiscreteObjectKeyFrame.Value>
    			</DiscreteObjectKeyFrame>
    			<DiscreteObjectKeyFrame KeyTime="00:00:0.005">
    			<DiscreteObjectKeyFrame.Value>
    				<Visibility>Visible</Visibility>
    			</DiscreteObjectKeyFrame.Value>
    			</DiscreteObjectKeyFrame>
    		</ObjectAnimationUsingKeyFrames>
    	</Storyboard>
    </VisualState>
    <VisualState x:Name="OfflineState">
    	<Storyboard>
    		<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="OnlineElement" Storyboard.TargetProperty="(UIElement.Visibility)">
    			<DiscreteObjectKeyFrame KeyTime="00:00:00">
    				<DiscreteObjectKeyFrame.Value>
    					<Visibility>Visible</Visibility>
    				</DiscreteObjectKeyFrame.Value>
    			</DiscreteObjectKeyFrame>
    			<DiscreteObjectKeyFrame KeyTime="00:00:01">
    				<DiscreteObjectKeyFrame.Value>
    					<Visibility>Collapsed</Visibility>
    				</DiscreteObjectKeyFrame.Value>
    			</DiscreteObjectKeyFrame>
    		</ObjectAnimationUsingKeyFrames>
    		<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="OnlineElement" Storyboard.TargetProperty="(UIElement.Opacity)">
    			<EasingDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    			<EasingDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
    		</DoubleAnimationUsingKeyFrames>
    		<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="OfflineElement" Storyboard.TargetProperty="(UIElement.Opacity)">
    			<EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    			<EasingDoubleKeyFrame KeyTime="00:00:01" Value="1"/>
    		</DoubleAnimationUsingKeyFrames>
    		<ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="OfflineElement" Storyboard.TargetProperty="(UIElement.Visibility)">
    			<DiscreteObjectKeyFrame KeyTime="00:00:00">
    			<DiscreteObjectKeyFrame.Value>
    				<Visibility>Collapsed</Visibility>
    			</DiscreteObjectKeyFrame.Value>
    	</DiscreteObjectKeyFrame>
    	<DiscreteObjectKeyFrame KeyTime="00:00:00.005">
    		<DiscreteObjectKeyFrame.Value>
    			<Visibility>Visible</Visibility>
    		</DiscreteObjectKeyFrame.Value>
    	</DiscreteObjectKeyFrame>
    	</ObjectAnimationUsingKeyFrames>
    	</Storyboard>
    </VisualState>
    </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    
    <StackPanel x:Name="OnlineElement" Orientation="Horizontal">
    	<Ellipse Margin="5" Height="15" Width="15" HorizontalAlignment="Left" VerticalAlignment="Center" >
    		<Ellipse.Effect>
    			<DropShadowEffect BlurRadius="8" Color="Black" ShadowDepth="0" />
    		</Ellipse.Effect>
    		<Ellipse.Fill>
    			<RadialGradientBrush>
    				<GradientStop Color="#DB005400" Offset="0.977" />
    				<GradientStop Color="#E700FF00" Offset="0" />
    				<GradientStop Color="#FF275B00" Offset="0.773" />
    			</RadialGradientBrush>
    		</Ellipse.Fill>
    	</Ellipse>
    
    	<TextBlock Text="Online" Foreground="White" FontWeight="Bold" VerticalAlignment="Center" Margin="2" Width="50">
    		<TextBlock.Effect >
    			<DropShadowEffect BlurRadius="8" Color="White" ShadowDepth="2"/>
    		</TextBlock.Effect>
    	</TextBlock>
    </StackPanel>
    
    <StackPanel Visibility="Collapsed" x:Name="OfflineElement" Orientation="Horizontal">
    	<Ellipse Margin="5" Height="15" Width="15" VerticalAlignment="Center" >
    		<Ellipse.Effect>
    			<DropShadowEffect BlurRadius="8" Color="Black" ShadowDepth="0" />
    		</Ellipse.Effect>
    		<Ellipse.Fill>
    			<RadialGradientBrush>
    				<GradientStop Color="#D5440000" Offset="1" />
    				<GradientStop Color="#E7FF0000" Offset="0" />
    				<GradientStop Color="#D07F0000" Offset="0.82" />
    			</RadialGradientBrush>
    		</Ellipse.Fill>
    	</Ellipse>
    
    	<TextBlock Text="Offline" Foreground="White" FontWeight="Bold" VerticalAlignment="Center" Margin="2" Width="50">
    		<TextBlock.Effect >
    			<DropShadowEffect BlurRadius="8" Color="White" ShadowDepth="2"/>
    		</TextBlock.Effect>
    	</TextBlock>
    
    </StackPanel>
    </Grid>

    Code behind for the control is :

    public partial class NetworkIndicator : UserControl
    {
    	public NetworkIndicator()
    	{
    		InitializeComponent();
    		this.Loaded += new RoutedEventHandler(NetworkIndicator_Loaded);
    	}
    	void NetworkIndicator_Loaded(object sender, RoutedEventArgs e)
    	{
    		ResetNetworkStatus();
    		NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
    	}	
    
    	void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
    	{
    		ResetNetworkStatus();
    	}
    
    	private void ResetNetworkStatus()
    	{
    		if (NetworkInterface.GetIsNetworkAvailable())
    		{
    				VisualStateManager.GoToState(this, "OnlineState", true);
    			}
    			else
    			{
    				VisualStateManager.GoToState(this, "OfflineState", true);
    			}
    		}
    	}
    }

    The code can be further improved by using template based control and write an event to be raised when network status changes.

  • Button Click Event

    Here is small code to trigger button’s Click event using automation peer from source code :

    if (button is Button)
    {
    ButtonAutomationPeer peer = new ButtonAutomationPeer((Button)button);

    IInvokeProvider ip = (IInvokeProvider)peer;
    ip.Invoke();
    }

    Trick will be used in upcoming article “Smart shortcut keys” for adding accessibility to silverlight applications.

  • Web FTP

     In most of the organizations FTP is not open and sometime client sends some documents via their FTP sites. The purpose of Web FTP is to bypass proxy and working principle is quite simple. The ASP.Net application takes user input and renders UI. The actual FTP client command execute on central web server. The documents are first download or uploaded to central web server and web application from there route it to ftp server. I find very interesting project known as Vista Web FTP on sourceforge written in ASP.Net and have hosted the tool on my web server which can be accessed at /rajnish/webftp.

     Passwords are only stored in sessions and are not logged anywhere in the application. Make sure to click on exit button when finished your ftp session, this will delete any downloaded or uploaded files on the web server (tested).

     The solution is hosted as is and only some minor changes in css (to make the fast UI) are done. (Use this at your own risk)

     Special thanks to kmanpro (author) for sharing nice tool…

  • Silverlight Hot Keys

    Hot keys like available in windows based application where you specify using caption like &print is not available in Silverlight.There are two ways to capture keydown or key up when silverlight is running inside web browser.The first way is the HTML Bridge to capture HTML event KeyUp on HTML document.This is fired when focus is not captured by silverlight application.Another way is to handle event in silverlight itself,since silverlight events are routed events i.e you need to capture hot / shortcut keys on root element i.e RootVisual.

    * Check for update in the bottom  of this article for simplified version of hot key library..

    There is limitation on keys like F1,F3 etc. which are handled by browser before they reach to the contents of web browser.These keys however can be used when running out of browser as HTML Bridge will be disabled while running out of browser.

    The code presented here in this article can be used in two ways.

    • Global Hot keys
    • Page Specific hot keys.

    Global Hot keys will be available throught the application life cycle where as page hot keys will be only available when specific page is active.

    To use global hot keys use below mentioned code.Where you need to specify ModifierKeys,Keys and EventHandler to the callback function.

    App.GlobalHotKeyHandler.RegisterShortcut(System.Windows.Input.ModifierKeys.Control,
                   System.Windows.Input.Key.D9, new KeyDownHandler(LogOff));
    
    void LogOff(object sender, System.EventArgs e)
            {
                LoginRegistrationWindow loginWindow = new LoginRegistrationWindow();
                loginWindow.Show();
            }

    Singleton Pattern is used to provide single instance of HotKeyHandler class throughout application.Normally GlobalHotKeyHandler code will be writen under either App.xaml.cs or MainPage.xaml.cs in your Silverlight business application.

    In case of shortcut keys for specific page use below mentioned code inside specific silverlight page.

    //Create module level variable in page
     HotKeyHandler hkeyHandler = new HotKeyHandler();
    
    //On Page_Loaded use Register and RegisterShortcut functions
    hkeyHandler.Register();
    hkeyHandler.RegisterShortcut(System.Windows.Input.ModifierKeys.None,
                      System.Windows.Input.Key.F1, new KeyDownHandler(LogOff));
    
    //On Page__Unloaded call Unregister
    hkeyHandler.Unregister();

    Note that the above code while running in out of browser silverlight application will behave properly.In case of web browser mode you need to avoid using shortcut keys assigned to browser.

    Here is the full code to add HotKey feature to your application.Add file HotKeyHandler.cs to your silverlight business application and paste the code for here…

    public partial class App : Application
    {
        public static HotKeyHandler GlobalHotKeyHandler { get; private set; }
        internal static Dictionary< Key,int> KeyCodeLookUp = new Dictionary();
        static App()
        {
            //start thread here to process this from backend
    
            GlobalHotKeyHandler = new HotKeyHandler();
    
            //  KeyCodeLookUp.Add(Key.D1,49);
            //Digits
            for (int i = (int)Key.D0; i <= (int)Key.D9;i++ )
                KeyCodeLookUp.Add((Key)i, i+28);
            //Chars
            for (int i = (int)Key.A; i <= (int)Key.Z; i++)
                KeyCodeLookUp.Add((Key)i, i + 35);
    
            //functional Key
            for (int i = (int)Key.F1; i <= (int)Key.F12; i++)             KeyCodeLookUp.Add((Key)i, i + 65);         KeyCodeLookUp.Add(Key.Escape, 1);     } } public delegate void KeyUpHandler(object sender,EventArgs e); public sealed class HotKeyHandler {     private List<Shortcut> shortcuts = new List<Shortcut>();
        public HotKeyHandler() {  }
        private bool isRegistered = false;
        public void Register()
        {
            if (this.isRegistered == false)
            {
                try
                {
                    App.Current.RootVisual.KeyUp += new System.Windows.Input.KeyEventHandler(RootVisual_KeyUp);
                    HtmlDocument document = HtmlPage.Document;
                    EventHandler<HtmlEventArgs> KeyDownHandler;
                    KeyDownHandler = new EventHandler<HtmlEventArgs>(OnBodyKeyUp);
                    bool b = document.AttachEvent("onkeyup", KeyDownHandler);
                }
                catch (Exception ex) { }
                finally
                {
                    this.isRegistered = true;
                }
            }
        }
    
        public void Unregister()
        {
            if (this.isRegistered)
            {
                try
                {
                    App.Current.RootVisual.KeyUp -= RootVisual_KeyUp;
                    HtmlDocument document = HtmlPage.Document;
                    EventHandler<HtmlEventArgs> KeyDownHandler;
                    KeyDownHandler = new EventHandler<HtmlEventArgs>(OnBodyKeyUp);
                    document.DetachEvent("onkeyup", KeyDownHandler);
                }
                catch (Exception ex) { }
                finally
                {
                    this.isRegistered = false;
                }
            }
        }
    
        private void RaiseOnKeyUp(ModifierKeys modKey,int keyCode,System.Windows.Input.KeyEventArgs ke,HtmlEventArgs he)
        {
            var handlers = (from h in this.shortcuts
                            where h.ModKeys == modKey &&
                            (ke!= null? h.Key == ke.Key : h.KeyCode==he.KeyCode)
                            select h);
            foreach (Shortcut s in handlers)
            {
                s.Handler(this, null);
            }
        }
    
        public void RegisterShortcut(ModifierKeys ModKeys, Key key, KeyUpHandler handler)
        {
            var shortAlready = from s in shortcuts
                                where s.ModKeys == ModKeys &&
                                s.Key == key && s.Handler.Method.Equals(handler.Method)
                                select s;
            if (shortAlready.Count() == 0)
            {
                Shortcut shortcut = new Shortcut { ModKeys = ModKeys, Key = key, Handler = handler };
                shortcuts.Add(shortcut);
            }
        }
    
        private void OnBodyKeyUp(object sender, HtmlEventArgs e)
        {
            RaiseOnKeyUp(GetModKey(e), e.KeyCode,null,e);
    
        }
    
        private ModifierKeys GetModKey(HtmlEventArgs e)
        {
            ModifierKeys modKey = ModifierKeys.None;
            if (e.CtrlKey) modKey = modKey | ModifierKeys.Control;
            if (e.AltKey) modKey = modKey | ModifierKeys.Alt;
            if (e.ShiftKey) modKey = modKey | ModifierKeys.Shift;
    
            return modKey;
        }
    
        void RootVisual_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
        {
    
            RaiseOnKeyUp(Keyboard.Modifiers,e.PlatformKeyCode,e,null);
        }
    
        private class Shortcut
        {
            public KeyUpHandler Handler { get; set; }
            public ModifierKeys ModKeys { get; set; }
            Key key;
            public Key Key
            {
                get { return key; }
                set {key=value;
                    KeyCode = App.KeyCodeLookUp[value]; }
            }
            public int KeyCode { get; set; }
        }
    }

    Note that the code maintains the relationship beetwen HTML KeyCode and Silverlight Keys Enum.This is not required when you run in out of browser mode.The above code can be optimized by checking the out of browser mode at run time.

    You may even develop system wide hot keys which will work even if you silverlight application is not in focus. This can be achived by using the system32 api’s to register the system wide hooks.The logic needs to be developed in some COM based component which needs to be deployed on client machine and can be communicated via COM bridge available in Silverlight 4. No doubt this will add very nice feature but the cost is more.. like it can be used only on windows system, it needs to be run as out of browser. That all realy depends on your requirements.

    Code is available at : link /rajnish/uploads/code/HotKeyHandler.cs.txt

    include the cs file in your project and update appropriate name space.

    in you silverlight page use following code to register shortcut and define call back function

     public partial class MainPage : UserControl
        {
            HotKeyHandler hkeyHandler = new HotKeyHandler();
    
            public void RegisterShortcuts()
            {
                hkeyHandler.Register();
    	    hkeyHandler.RegisterShortcut(System.Windows.Input.ModifierKeys.Control,
                   System.Windows.Input.Key.D9, new KeyUpHandler(Logout));
            }
    
            void Logout(object sender, EventArgsKeyUp e)
            {
                App.RootActivity.ActiveContent = "Logging out...";
                App.RootActivity.IsActive = true;
    
                WebContext.Current.Authentication.Logout(false).Completed += new EventHandler(Logout_Completed);
            }
        }

    off-course you need to call RegisterShortcuts function on page load.

    /***************************************************************************************/

    Update 1.0 : Nov 2010

    Another simplified version of Hot Key library which can be used in XAML (without c# code) with just below mentioned two line. Hot key is exposed as attachable property.

    xmlns:hkey="clr-namespace:Silverlight.Controls.HotKeys;assembly=Silverlight.Controls.HotKeys"
    <Button Click="BtnAClick"   Grid.Column="0" Grid.Row="0" Height="25" Content="Button A"  >
     <hkey:HotKeyService.HotKey >
      <hkey:HotKey Shortcut="A" Click="BtnAClick" />
     </hkey:HotKeyService.HotKey>
    </Button>

    or with XAML code

    xmlns:hkey="clr-namespace:Silverlight.Controls.HotKeys;assembly=Silverlight.Controls.HotKeys"
    <Button Click="BtnAClick"   Grid.Column="0" Grid.Row="0" Height="25" Content="Button A" hkey:HotKeyService.HotKey="A" />

    Source code (Vs2010,Sl 4.0) is available here. This library can be used to provide office xp like shortcut navigation in your silverlight application.

    /***************************************************************************************/