Showing posts with label Silverlight 4. Show all posts
Showing posts with label Silverlight 4. Show all posts

Thursday, February 23, 2012

Unauthorized access exception when value set for property using Secondary Thread - Silverlight

Thinking about threading in Silverlight 4, we choose between the two options
  1. Background worker
  2. Managing thread manually
Most of the time-consuming operations will be handled using the Background worker without blocking the UI. It ultimately executes in a separate thread. The main functions and events to know in Background worker are DoWork, RunWorkerCompleted and RunWorkerAsync. As the name specifies we need to add the event handler for DoWork event for doing the background operation. Add the handler for RunWorkerCompleted to receive the operation completed notification.  RunWorkerAsync method is to start the operation. The main thing to note is that we should not access directly access the UI objects from the DoWork event.

Also there are times where we need to manage the threads manually. Since Silverlight runs in a Single threaded apartment (STA) application model and the default is the UI thread, accessing the UI objects from other thread leads to cross thread exception. Knowing this fact I worked with a secondary thread and updated a property in my ViewModel. In that scenario I got an exception and digging into the inner exception found out the cross thread exception. For understanding I've created a sample scenario that raises exception.

Snippet 1

public partial class ThreadTest : UserControl, INotifyPropertyChanged
{        
    private string textValue;
    public string TextValue
    {
        get { return textValue; }
        set
        {
            textValue = value;
            NotifyPropertyChanged("TextValue");
        }
    }

    public ThreadTest()
    {
        InitializeComponent();

        InitControls();
    }

    private void InitControls()
    {
        this.DataContext = this;
    }

    private void Direct_Click(object sender, RoutedEventArgs e)
    {
        TextValue = "direct text......";
    }

    private void UsingTask_Click(object sender, RoutedEventArgs e)
    {
        Thread secondaryThread = new Thread(SecondaryThreadWorker);
        secondaryThread.Start();
        
    }

    private void SecondaryThreadWorker()
    {
        TextValue = "thread text.......";            
    }


    #region INotifyPropertyChanged Members

    protected void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

Then examining the cause, realized that the specific property raises an property changed notification . Immediately recalled the excellent article from Pete Brown in his 10rem.net blog.

The following implementation does the trick.

Snippet 2 (Just replace the INotifyPropertyChanged implementation)

#region INotifyPropertyChanged Members

protected void NotifyPropertyChanged(string propertyName)
{
    if (PropertyChanged != null)
    {
        if (Deployment.Current.Dispatcher.CheckAccess())
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        else
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            });
        }
    }
}

public event PropertyChangedEventHandler PropertyChanged;

#endregion


When I typed "Deployment.Current.Dispatcher.", it didn't show up the "CheckAccess()" method in the intellisense. But I verified it in the object which shows the existence of the method. So I manually typed the  "CheckAccess()" method name and got complied without error.

References
http://10rem.net/blog/2012/01/10/threading-considerations-for-binding-and-change-notification-in-silverlight-5




Saturday, November 19, 2011

ScrollToBottom extension method in ScrollViewer - Silverlight 4

ScrollViewer is one among the commonly used Silverlight control. When you develop Silverlight application, at some time, you'll come across using ScrollViewer. Using ScrollViewer is straightforward in most of the cases. In some scenarios (like displaying chat history messages, stock history update), we might want to bind values to elements inside the ScrollViewer and then scroll to the bottom in order to make the latest message appear in the visible region.

ScrollToBottom() is one among the several extension methods available for ScrollViewer which helps us to achieve scrolling vertically to the end of the ScrollViewer content. While using this ScrollToBottom() method some developers won't see the ScrollViewer scrolls upto the bottom. So, why it is like that what need to be done to make it work? Let us dive into the implementation of ScrollToBottom() method and find out the solution.

Snippet 1: (ScrollToBottom() implementation)

public static void ScrollToBottom(this ScrollViewer viewer)
{
    if (viewer == null)
    {
        throw new ArgumentNullException("viewer");
    }

    viewer.ScrollToVerticalOffset(viewer.ExtentHeight);
}

As most of us might guess, it scrolls the veritical offset to the height of the content inside the ScrollViewer. Actually the values for properties like ScrollViewer.ExtentHeight, ScrollViewer.VerticalOffset are not recalculated immediately. It seems that they placed such restrictions due to performance considerations.

We can force to recalculate and update values of related properties by calling the UpdateLayout() method of the ScrollViewer. Anyhow be sure to call the UpdateLayout() only required. Please view the remarks section here at msdn documentation.

Ultimately, calling the UpdateLayout() method on the ScrollViewer before ScrollToBottom() is called will solve the obstacle.

Following is a sample snippet to help you understand the above specified scenario. Try executing the following snippet and inspect the value of ExtentHeight(and related properties) property by inserting the breakpoint in the call to UpdateLayout() method.

Snippet 2:
ScrollViewerTest.xaml

<UserControl x:Class="TestSilverlightApplication1.ScrollViewerTest"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="500" d:DesignWidth="500">
    <Grid Background="DeepSkyBlue">
        <Grid x:Name="LayoutRoot" Background="SkyBlue" Height="300" Width="400">
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="70"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="70"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <StackPanel>
                <TextBlock Text="ScrollToBottom Check" HorizontalAlignment="Center" FontWeight="Bold" ></TextBlock>

            </StackPanel>
            <TextBlock Grid.Row="1" Text="Enter multiline text here......"></TextBlock>
            <ScrollViewer Grid.Row="2">
                <TextBox AcceptsReturn="True" Text="{Binding SampleTextString, Mode=TwoWay}"></TextBox>
            </ScrollViewer>
            <Button Content="...and click here...." Click="ScrollDownCheck_Click" Width="150" Grid.Row="3" Margin="10"></Button>
            <ScrollViewer Grid.Row="4" Name="TestScrollControl">
                <TextBox AcceptsReturn="True" Name="TestTextBox" Text="{Binding AlteredTextString}"></TextBox>
            </ScrollViewer>
        </Grid>
    </Grid>
</UserControl>


ScrollViewerTest.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;

namespace TestSilverlightApplication1
{
    public partial class ScrollViewerTest : UserControl, INotifyPropertyChanged
    {
        public ScrollViewerTest()
        {
            InitializeComponent();
            InitControls();
        }

        private string sampleTextString;

        public string SampleTextString
        {
            get { return sampleTextString; }
            set
            {
                sampleTextString = value;
                NotifyPropertyChanged("SampleTextString");
            }
        }

        private string alteredTextString;

        public string AlteredTextString
        {
            get { return alteredTextString; }
            set
            {
                alteredTextString = value;
                NotifyPropertyChanged("AlteredTextString");
            }
        }
         
        private void ScrollDownCheck_Click(object sender, RoutedEventArgs e)
        {
            ManipulateScrollDownCheck();
        }

        private void InitControls()
        {
            this.DataContext = this;
        }

        private void ManipulateScrollDownCheck()
        {
            this.AlteredTextString = this.SampleTextString;
            //Insert breakpoint here and validate the value of 
            //ExtentHeight before and after the execution of UpdateLayout().
            TestScrollControl.UpdateLayout();
            TestScrollControl.ScrollToBottom();
        }

        #region INotifyPropertyChanged Members

        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}


You can infer from the above example that the call to UpdateLayout() is made before calling ScrollToBottom() and after assinging the value to the property bound to the content(UIElement contained inside the ScrollViewer) of the ScrollViewer. Since developers will face such problem only at certain workflows, call the UpdateLayout() only when you encounter that problem.

Reference
http://msdn.microsoft.com/en-us/library/system.windows.controls.scrollviewer.scrolltoverticaloffset(v=vs.95).aspx
http://msdn.microsoft.com/en-us/library/system.windows.controls.scrollviewer.scrolltobottom.aspx
https://epiinfo.svn.codeplex.com/svn/Silverlight.Controls.Toolkit/Controls.Toolkit/Common/ScrollViewerExtensions.cs

Saturday, August 6, 2011

Silverlight - Dependency property CLR wrapper setter/getter not executed

Several Silverlight developers raise this as issue when they first start implementing dependency properties in their custom controls in Silverlight. While developing custom controls when there is a need to expose a property that is target of some binding, animation ...., developers will end up in creating a dependency property of some specific type. For details on dependency properties, refer to the msdn documentation.

It is the CLR wrapper which is exposed in such a way that the values are get from or set to the dependency property identifier. The basic thumb rule for creating a dependency property is the hosting class should inherit from DependencyObject. DependencyObject is the one which stores and evaluates the value of dependency properties. DependencyObject exposes the GetValue() and SetValue() methods for storing and retrieving the values of related dependency properties. Hence the CLR wrappers will hold the GetValue() and SetValue() methods in their getter and setter respectively.

Any XAML binding expressions will be specified to the exposed CLR wrapper for binding values to the related dependency property. Ok, now think of a situation where we need to place some manipulation logic when the value of the dependency property is set or changes. When similar case arise for plain CLR properties, we'll obviously place the manipulation logic in the setter of the property. If we try to do the same in dependency property - CLR wrapper, we'll end up in the method not getting called as the CLR wrapper setter won't get executed. Actually the XAML processing engine is capable of interacting with the Silverlight property system directly and get or set the value of the related dependency property with the help of DependencyObject.

Hence if at all you want to have the logic executed when the value of dependency property changes, stuff it in the PropertyChangedCallback of the property metadata. Following is a brief sample on this.

Snippet: (Dependency property with PropertyChangedCallback)

public class MyCustomControl : Control
{
    public MyCustomControl()
    {
        this.DefaultStyleKey = typeof(MyCustomControl);
    }

    #region Dependency property with PropertyChangedCallback

    public string DisplayMessage
    {
        get
        {
            return (string)GetValue(DisplayMessageProperty);
        }
        set
        {
            SetValue(DisplayMessageProperty, value);

        }
    }

    public static readonly DependencyProperty DisplayMessageProperty =
        DependencyProperty.Register("DisplayMessage", typeof(string), typeof(MyCustomControl), new PropertyMetadata(string.Empty, OnDisplayMessageChanged));

    private static void OnDisplayMessageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // Value change manipulation logic goes here......
    }

    #endregion
}


Placing additional logic in the CLR wrappers other than GetValue() and SetValue() should be avoided to eradicate any discrepancies.

References
http://msdn.microsoft.com/en-us/library/cc221408(v=vs.95).aspx
http://msdn.microsoft.com/en-us/library/cc903933(v=vs.95).aspx

Monday, August 1, 2011

Siverlight 4 - Using DependencyObjects or INotifyPropertyChanged as data objects / ViewModel

Making conviencing decision on representing data objects as whether to derive from DependencyObject or implement from INotifyPropertyChanged can sometimes become a daunting task. When implementing MVVM pattern this question arises while representing the ViewModel.
DependencyObject provides support for handling dependency properties. It is the dependency property which is capable of handling the data binding even through XAML (markup) extensions. There is no need for the manually notify the change in the property value, since the dependency property system automatically notifies the changes in the property.

Snippet 1 (Dependency property)

public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(ParameterMapControl), null);

public string Value
{
    get
    {
        return (String)GetValue(ValueProperty);
    }
    set
    {
        SetValue(ValueProperty, value);
    }
}



Snippet 2 (INotifyPropertyChanged)

public class SampleViewModel : INotifyPropertyChanged
{
    private string reportName;

    public string ReportName
    {
        get { return reportName; }
        set
        {
            reportName = value;
            NotifyPropertyChanged("ReportName");
        }
    }


    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion
}


Ok now think of in a different perspective, if the ViewModel is derived from the DependencyObject, exposed a dependency property and it is bind to the control in UI, any change in the property will notify the control. As an alternate we can implement the ViewModel from INotifyPropertyChanged which is usually represented as Plain Old CLR Objects (POCO) and manually provide the mechanism to notify the property changed.

The evaluation of property value, usage of resources (like memory) and the handling of binding sequence are well optimised to handle by the DependencyObject. Hence using DependencyObject to build data objects is not wrong. But we should also consider other factors.

Case 1
When we use INotifyPropertyChanged (POCO model) for data objects, in general the change notification code will be placed in the setter of the specific property. Also, the property change notification can be raised whenever required. This is especially helpful for read-only properties. While developing view model, several times we might be in a situation to specify a read-only property. For example, we can specify a read-only property which holds the functionality that represents a collection in sorted order and each and every time the original collection got changed, will trigger the change notification for the related read-only property.  But dealing this situation with DependencyObject is not pretty straightforward.

Case 2
Serialization of ViewModel will be your choice lot of time when you want to persist the state of the ViewModel for cases like reverting the object to a particular/previous state. Serialization mechanisms can be achieved over POCO easily where with DependencyObject,  we can't to do so.

Case 3
Passing as parameter to other services also favors POCO.

Case 4
Code readability, maintainability and flexibility are some of the main tenet of coding. DependencyObject lacks in these items when the ViewMode / data item goes a bit complex. Hence POCO is preferable here.

Summary
From the above, we can infer that implementing INotifyPropertyChanged for data items is handy in most of the cases. Dependency properties support great if it is the target of binding, animation, styles, template binding, etc, which will be very much helpful for us when we create custom controls.

Monday, July 25, 2011

Silverlight 4 - Getting value irrespective of the animation in progress

Gone are those days where animations in Silverlight are viewed as fancy add-ons. Nowadays simple animations are becoming an essential part of the Silverlight applications. Nothing much to imagine, displaying collection as list in brief generally and then displaying the same in detail upon selecting the list item is one such scenario where animation helps us a lot in achieving it. Ok, let us drift our focus to the topic now.

In such cases when animation in progress, there are times where we require to get the value of a property when no animation is applied. When I searched for such a mechanism, I came to know the availability of GetAnimationBaseValue method which takes a dependency property as parameter. As you might guess, since it takes any dependency property as parameter, the value is returned of type Object. It is our responsibility to cast the returned Object to the respective type.

Enough with description, let us feel it in code snippet as follows.

Snippet 1

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.Resources>
        <Storyboard x:Key="RectHeightStoryBoard" >
            <DoubleAnimation From="20" To="200" Duration="00:00:3" 
            Storyboard.TargetName="AnimationTestRectangle" 
            Storyboard.TargetProperty="Height"></DoubleAnimation>
        </Storyboard>
    </Grid.Resources>

    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>

    <Rectangle x:Name="AnimationTestRectangle" MouseLeftButtonDown="AnimationTestRectangle_MouseLeftButtonDown" 
               Fill="Crimson" Width="200" Height="20" Grid.ColumnSpan="2" />
    <StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Vertical">
        <StackPanel >
            <TextBlock Text="Height"  Margin="10"/>
            <TextBlock Name="HeightValueTextBlock" Text=""  Margin="10"/>
        </StackPanel>
        <StackPanel >
            <TextBlock Text="AnimationBaseValue Height"  Margin="10"/>
            <TextBlock Name="AnimationBaseValueTextBlock" Text=""  Margin="10"/>
        </StackPanel>
        
        <Button Content="Check Height" Name="CheckHeightButton" Width="85" Click="CheckHeightButton_Click" />
    </StackPanel>

</Grid>

Snippet 2

public partial class GetAnimationBaseValueTest : UserControl
{
    public GetAnimationBaseValueTest()
    {
        InitializeComponent();
        
    }

    private void AnimationTestRectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        Storyboard rectHeightStoryBoard = (Storyboard)LayoutRoot.Resources["RectHeightStoryBoard"];
        rectHeightStoryBoard.Begin();

        ReadAnimationTestRectangleHeight();
    }

    private void CheckHeightButton_Click(object sender, RoutedEventArgs e)
    {
        ReadAnimationTestRectangleHeight();          
    }

    private void ReadAnimationTestRectangleHeight()
    {
        HeightValueTextBlock.Text = AnimationTestRectangle.Height.ToString();
        AnimationBaseValueTextBlock.Text = AnimationTestRectangle.GetAnimationBaseValue(HeightProperty).ToString();
    }
    
}


In the above snippet, I've created a storyboard targeting a rectangle for animating the height of the rectangle with some time delay. In the Click event of the CheckHeightButton, I'm calculating the height normally and then using the GetAnimationBaseValue method and displaying the values in related textblocks for verification. In the MouseLeftButtonDown event of the rectangle, I start the animation from the codebehind. Now, in order to evaluate, first click on the rectangle which triggers the animation. In due course when the animation in progress, click on the CheckHeightButton which displays the resultant values. There you can infer the use of GetAnimationBaseValue method.

Thursday, July 14, 2011

Silverlight 4 - Save UIElement as image in IsolatedStorage

One of the common feature expectation in Silverlight Application is the option to save the entire page or part of the page as image. There are pretty good articles over the web to save an UIElement as an image. One such article is posted by Victor Gaudioso here.

Our example is going to deal with saving an UIElement in Silverlight as png image in isolated storage. WriteableBitmap accepts UIElement which in turn need to be encoded for which I use Joe Stegman’s PngEncoder. Following code Snippet 1,
  • Generates the png stream with the help of PngEncoder
  • Creates the byte[] from the png stream
  • Checks for the available free space in the isolated storage and increase quota if needed
  • Save the image in png format in the isolated storage.
Snippet 1
private void SaveInIsolatedStorage()
{
    string fileName = "FileCheck1.png";
    Byte[] printBuffer;
    System.Windows.Media.Imaging.WriteableBitmap wBitmap;
    
    wBitmap = new WriteableBitmap(ElGrid, null);

    wBitmap.Invalidate();

    System.IO.Stream pngStream = Encode(wBitmap); 

    printBuffer = new Byte[pngStream.Length];
    pngStream.Read(printBuffer, 0, printBuffer.Length);
    
    if (!FileExists(fileName))
    {
        using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (isoStore.AvailableFreeSpace < pngStream.Length)
            {                        
                if (isoStore.IncreaseQuotaTo(isoStore.Quota + (pngStream.Length - isoStore.AvailableFreeSpace) + 1024))
                {
                    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.CreateNew, isoStore))
                    {
                        stream.Write(printBuffer, 0, printBuffer.Length);
                    }
                }
            }
            else
            {
                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.CreateNew, isoStore))
                {
                    stream.Write(printBuffer, 0, printBuffer.Length);
                }
            }
            
        }

    }
    
}

Snippet 2
(Encode: got from an article. Download PngEncode.cs from the above specified blogs in order to execute the line "return PngEncoder.Encode(buffer, w, h);")
public static Stream Encode(WriteableBitmap wb)
{
    int w = wb.PixelWidth;
    int h = wb.PixelHeight;
    int adr;

    int rowLength = w * 4 + 1;

    byte[] buffer = new byte[rowLength * h];

    for (int y = 0; y < h; y++)
    {
        buffer[y * rowLength] = 0; // filter byte

        for (int x = 0; x < w; x++)
        {
            adr = y * rowLength + x * 4 + 3;

            int pixel = wb.Pixels[x + y * w];

            buffer[adr--] = (byte)(pixel & 0xff); pixel >>= 8;
            buffer[adr--] = (byte)(pixel & 0xff); pixel >>= 8;
            buffer[adr--] = (byte)(pixel & 0xff); pixel >>= 8;
            buffer[adr] = (byte)(pixel & 0xff);
        }
    }

    return PngEncoder.Encode(buffer, w, h);
}

In order to verify the storage manually, follow the path "C:\Users\[USER NAME]\AppData\LocalLow\Microsoft\Silverlight\is" in windows 7.

To save the image in the database, modify the Snippet 1 by removing the isolated storage related code (probably lines after 15) and make use of the printBuffer byte[] for storage.

This is just to introduce a basic idea of saving an UIElement in image format. Different encoders need to be used with respect to the format to be saved. Libraries like http://imagetools.codeplex.com/ can help you to achieve this.

References
http://blogs.msdn.com/b/jstegman/archive/2008/04/21/dynamic-image-generation-in-silverlight.aspx
http://www.windowspresentationfoundation.com/?p=406
http://imagetools.codeplex.com/

Thursday, June 30, 2011

Silverlight 4 - Programmatically invoking command's CanExecute status

While developing Silverlight 4 applications with Model-View-ViewModel (MVVM), one of the feature that comforts developers is the command object that implements from ICommand. The ICommand interface exposes two methods Execute and CanExecute and an event CanExecuteChanged. As the name implies, the Execute method is the one to be executed when the command is invoked and CanExecute is the method that specifies the execution status - means, it influences whether the command can be executed or not. For getting core details of ICommand, please refer msdn.

Points to be considered while implementing ICommand
Upon implementing the ICommand, simply what we'll be doing is,
  • Get two delegates that matches the Execute and CanExecute methods' signatures(Action<object> and Func<object, bool> resp) as parameters in the constructor and store them in a locally in the class level scope.
  • Then invoke those delegates in the respective methods. That is Action delegate (Action<object>) in the Execute method and the function delegate (Func<object, bool>) in the CanExecute method.
  • In addition to invoking the action delegate (Action<object>), the Execute method need to call the CanExecute method.
  • In addition to invoking the function delegate (Func<object, bool>), the CanExecute method need to raise the CanExecuteChanged event.
There exists several examples in web on implementing ICommand interface and using it. One such is provided by John Papa here, which details more about commanding.

In Silverlight 4, ButtonBase and Hyperlink supports commanding.

The CanExecute method plays its role visually by enabling or disabling the control it(the command object) is bound to. That is the reason why the CanExecute method is called from the Execute method as it'll validate the execution status at the time of execution.

Now comes the core of this post: From the above explanation it is clear that the CanExecute method is called on the command action of the bound control (example: on click of the control). But in some scenarios, we might need to make a strategy somehow that the CanExecute method need to be invoked in order to reevaluate the execution status. Such scenario arises when changes from some other manipulation affects the logic we use to arrive the return value of CanExecute method. Say as a result of some manipulation your ViewModel changes a property which is used in the CanExecute method. So now you need to programmatically achieve reevaluation of the execution status.

Triggering CanExecuteChanged event will do this for you. Hence its good to have a public method in the class that implements the ICommand to raise the CanExecuteChanged event.

Snippet 1

public void RaiseCanExecuteChanged()
{
    if (CanExecuteChanged != null)
    {
        CanExecuteChanged(this, new EventArgs());
    }
}

Hence RaiseCanExecuteChanged is also one of the important point to be considered when implementing the ICommand, as such scenarios are common in applications with MVVM that uses command.

Additional Info
Prism provides this ICommand implementation through DelegateCommand class, which also exposes the RaiseCanExecuteChanged method.

References
http://msdn.microsoft.com/en-us/library/system.windows.input.icommand(v=vs.95).aspx
http://johnpapa.net/5-simple-steps-to-commanding-in-silverlight

Tuesday, June 28, 2011

Silverlight 4 Printing Centered

In one of my previous article, I've explained about printing fit to page in Silverlight 4(Silverlight4 - Printing fit to page). In this article, I'll enhance the PrintUtility(specified in the Snippet 2 of post) to print the element centered in the print area(center of the paper).

Let us recap the idea of printing fit to page. 
  1. The print element is transformed (scaled) to fit to page, when the print element size exceeds the print area - Scaled.
  2. The print element is printed as it is otherwise - Normal.
During scale transformation, the print element is scaled in such a way to maintain the aspect ratio. So it is clear that we need to handle both the scenarios (Scaled & Normal) while centering the print element.

Ok, now we need to identify how much the print element need to be positioned left and top. A simple calculation will do that for us.

Left position = ((total print area width) - (print element width)) / 2, Top position = ((total print area height) - (print element height)) / 2.

Initially I thought of setting the margin to the print element to achieve centering. But after that I got an alternate way from an article. As most of you know three primary transformations are Transformation, Rotation and Scaling. It is the translate transformation that we're going to use for centering.

Change will be there only in the DocToPrint_PrintPage handler with respective calculations and transformation included. Below is the complete code snippet of the PrintUtility.

Snippet 1

public class PrintUtility
{
    #region Class Level Variables

    private const string NullReferenceExceptionMessage = "PrintElement is null : Please specify the element to be printed.";

    private Grid parentGrid;

    private Border borderItem;

    private BusyIndicatorControl busyIndicatorControl;

    private WriteableBitmap printElementImage;

    private ImageBrush printElementImageBrush;

    #endregion

    #region Events

    #endregion

    #region Properties

    public FrameworkElement PrintElement { get; private set; }

    public string DocumentName { get; private set; }

    public FrameworkElement TabletUIElement { get; set; }

    #endregion

    #region Constructors

    public PrintUtility(FrameworkElement elementToBePrinted, string documentName)
    {
        this.PrintElement = elementToBePrinted;
        this.DocumentName = documentName;
    }

    #endregion

    #region Event Handlers

    private void DocToPrint_EndPrint(object sender, EndPrintEventArgs e)
    {
        this.PrintElement.RenderTransform = null;

        if (this.borderItem != null)
        {
            if (this.parentGrid.Children.Contains(this.borderItem))
            {
                this.parentGrid.Children.Remove(this.borderItem);
            }

            this.borderItem = null;
        }

        this.parentGrid = null;
        this.printElementImage = null;
        this.printElementImageBrush = null;
    }

    private void DocToPrint_BeginPrint(object sender, BeginPrintEventArgs e)
    {
        FrameworkElement maskElement = this.TabletUIElement ?? this.PrintElement;

        if (maskElement.Parent is Grid)
        {
            this.parentGrid = (Grid)maskElement.Parent;
            this.parentGrid.Children.Add(this.BuildBorderWithImageFill());
        }
    }

    private void DocToPrint_PrintPage(object sender, PrintPageEventArgs e)
    {
        double scale = 1;
        TransformGroup transformGroup = new TransformGroup();

        if (e.PrintableArea.Height < this.PrintElement.ActualHeight)
        {
            scale = e.PrintableArea.Height / this.PrintElement.ActualHeight;
        }

        if (e.PrintableArea.Width < this.PrintElement.ActualWidth && e.PrintableArea.Width / this.PrintElement.ActualWidth < scale)
        {
            scale = e.PrintableArea.Width / this.PrintElement.ActualWidth;
        }

        if (scale < 1)
        {
            ScaleTransform scaleTransform = new ScaleTransform();
            scaleTransform.ScaleX = scale;
            scaleTransform.ScaleY = scale;

            TranslateTransform translateTransform = new TranslateTransform();
            translateTransform.X = (e.PrintableArea.Width - (this.PrintElement.ActualWidth * scale)) / 2;
            translateTransform.Y = (e.PrintableArea.Height - (this.PrintElement.ActualHeight * scale)) / 2;

            transformGroup.Children.Add(scaleTransform);
            transformGroup.Children.Add(translateTransform);
        }
        else
        {
            TranslateTransform translateTransform = new TranslateTransform();
            translateTransform.X = (e.PrintableArea.Width - this.PrintElement.ActualWidth) / 2;
            translateTransform.Y = (e.PrintableArea.Height - this.PrintElement.ActualHeight) / 2;

            transformGroup.Children.Add(translateTransform);
        }

        this.PrintElement.RenderTransform = transformGroup;
        e.PageVisual = this.PrintElement;
    }

    #endregion

    #region Public Methods

    public void Print()
    {
        if (this.PrintElement != null)
        {
            PrintDocument docToPrint = new PrintDocument();

            docToPrint.PrintPage += new EventHandler<PrintPageEventArgs>(this.DocToPrint_PrintPage);
            docToPrint.BeginPrint += new EventHandler<BeginPrintEventArgs>(this.DocToPrint_BeginPrint);
            docToPrint.EndPrint += new EventHandler<EndPrintEventArgs>(this.DocToPrint_EndPrint);

            docToPrint.Print(this.DocumentName);
        }
        else
        {
            throw new NullReferenceException(NullReferenceExceptionMessage);
        }
    }

    #endregion

    #region Private Methods

    private BusyIndicatorControl BuildBusyIndicatorControl()
    {
        this.busyIndicatorControl = new BusyIndicatorControl();

        this.busyIndicatorControl.IsBusy = true;
        this.busyIndicatorControl.BusyContent = "Processing For Printing......";

        return this.busyIndicatorControl;
    }

    private Border BuildBorderWithImageFill()
    {
        this.printElementImageBrush = new ImageBrush();
        this.borderItem = new Border();

        this.printElementImage = new WriteableBitmap(this.TabletUIElement ?? this.PrintElement, null);
        this.printElementImageBrush.ImageSource = this.printElementImage;

        this.borderItem.Background = this.printElementImageBrush;
        this.borderItem.Child = this.BuildBusyIndicatorControl();

        return this.borderItem;
    }

    #endregion
}


Thursday, June 23, 2011

Silverlight 4 ComboBox SelectedItem vanishes on ItemsSource update

In Silverlight 4, the SelectedItem is set to null when we update / change (new instance set) the ItemsSource.

Let us take a case of having a readonly property that builds a new list(by performing operations like filtering , sortings, etc... on an existing data) each time the property is read(get).

Snippet 1
 
ObservableCollection<ICheckItem> checkItemCollection;

public ObservableCollection<ICheckItem> CheckItemCollection
{
    get
    {
        return checkItemCollection;
    }
    set
    {
        checkItemCollection = value;
        checkItemCollection.CollectionChanged += (s, e) =>
        {
            NotifyPropertyChanged("SortedCheckItemCollection");
        };
        NotifyPropertyChanged("CheckItemCollection");
        NotifyPropertyChanged("SortedCheckItemCollection");
    }
}

public List<ICheckItem> SortedCheckItemCollection
{
    get
    {
        return CheckItemCollection.OrderBy(ci => ci.Name).ToList();
    }
}
 
Also consider another property that holds the selected item.
 
Snippet 2
 
ICheckItem selectedCheckItem;
public ICheckItem SelectedCheckItem
{
    get
    {
        return selectedCheckItem;
    }
    set
    {
        selectedCheckItem = value;
        NotifyPropertyChanged("SelectedCheckItem");
    }
}
 
Now if we bind the above properties to the ComboBox, initially the ComboBox will hold the list and displays the selected item correctly, provided the SelectedItem property holds a valid object(item) from the ItemsSource(IEnumerable).
 
Snippet 3

<ComboBox ItemsSource="{Binding Path=SortedCheckItemCollection}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedCheckItem, Mode=TwoWay}" />
<br />

But after that, the next time when the property change notification for "SortedCheckItemCollection" is raised(by some means), the ItemsSource is provided with a new List instance by the "get" accessor(see Snippet 1). At this point of time, the SelectedItem will become null and no item will be displayed selected in the ComboBox.
 
To overcome this issue(in my real case), I planned to go with the custom control derived from the ComboBox. In the beginning, I thought of providing a dependency property that works in sync with the SelectedItem property and make workaround for the scenario where the issue arises. But while developing code for that, I identified(by debugging) that only after the execution of "OnItemsChanged" handler, the SelectedItem is lost.
So I revamped my logic by overriding the "OnItemsChanged".
In that I'll,
  • Persist the SelectedItem locally,
  • Call the base.OnItemsChanged and
  • Then reset the SelectedItem with the locally persisted object.

Snippet 4

/// <summary>
/// PersistenceComboBox is same as ComboBox in addition will handle the SelectedItem when the ItemSource is changed.
/// Workaround for issue: ComboBox unable to handle the SelectedItem on ItemSource change. 
/// </summary>
public class PersistenceComboBox : ComboBox
{
    /// <summary>
    /// Updates the current selected item when the <see cref="P:System.Windows.Controls.ItemsControl.Items"/> collection has changed.
    /// </summary>
    /// <param name="e">Contains data about changes in the items collection.</param>
    protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        object persistenceSelectedItem = null;

        foreach (object item in this.ItemsSource)
        {
            if (item.Equals(this.SelectedItem))
            {
                persistenceSelectedItem = item;
            }
        }

        base.OnItemsChanged(e);

        if (this.SelectedItem != persistenceSelectedItem)
        {
            this.SelectedItem = persistenceSelectedItem;
        }
    }

}

So the change in the XAML(Snippet 3) will be,
 
Snippet 5 
 
<customControl:PersistenceComboBox ItemsSource="{Binding Path=SortedCheckItemCollection}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedCheckItem, Mode=TwoWay}" />
<br /> 

Now, the PersistenceComboBox(custom control) can be used in places where we require the SelectedItem to be retained even after updating the ItemsSource.

Thursday, May 26, 2011

Silverlight 4 - Bind to a property in the level of parent or Ancestor

In Silverlight, most of us will use the MVVM pattern for which we will create a ViewModel and bind it to the respective View.

In such cases, there might arise a scenario in which we need to bind a property for an element or control which is embeded inside another control. Let us take a real case scenario in order to understand the problem clearer.
Consider that our ViewModel contains two properties (CustomCollection, ButtonVisibility) of which one of type ObservableCollection(CustomCollection) and other one of type Visibility(ButtonVisibility).

Now in the View, first we need to bind the ObservableCollection to a ListBox as follows.

Snippet 1

<Grid x:Name="LayoutRoot" Background="White">
    <ListBox ItemsSource="{Binding Path=CustomCollection}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Path=CustomName}" />
                    <Button Content="Sample Button"></Button>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>    
</Grid>

Then if i want to set the ButtonVisibility property to the button control inside the DataTemplate of the ListBox, then there should be some way to specify that the property belongs to the ancestor and not the current. Unfortunately we can't directly specify this in Silverlight 4.

In order to achieve this we can do an alternate by using ElementName property of Binding. In MVVM, we will be assigning the ViewModel's instance to the View's DataContext. Hence any root level elemnt can be made use. In our case I'll take the "LayoutRoot" element(which is created by default).

Snippet 2

<Grid x:Name="LayoutRoot" Background="White">
    <ListBox ItemsSource="{Binding Path=CustomCollection}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Path=CustomName}" />
                    <Button Content="Sample Button" Visibility="{Binding Path=DataContext.ButtonVisibility, ElementName=LayoutRoot}"></Button>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

You can use any valid element name with relevant DataContext you need for the property to bind.

Wednesday, April 27, 2011

Access/Edit files inside Silverlight XAP

While developing Silverlight applications, there were times where we might need to change the contents of a file that resides inside the Silverlight XAP from our ASP.Net hosting application. The ASP.Net (hosting application) holds the XAP file in the ClientBin folder.

One way of editing includes following steps:

  • Since XAP file is nothing but a ZIP file, we need to use any .net library for manipulating zip files. One such library is DotNetZip. Use it to retrieve the contents of XAP file.
  • Access and do related modifications of the file you need to update and save it in the application folder temporarily.
  • Remove the original file from the XAP file.
  • Add the temporary file into the XAP file.
  • Finaly, delete the temporary file.

Consider XAP file consists of xml file of format that we need to update :


<ConfigData>
  <Id>
    InitialTestId1
  </Id>
  <CategoryList>
    <Category ID="01">
      <MainCategory>Category 1</MainCategory>
      <Description>Description 1.</Description>
      <Active>true</Active>
    </Category>
  </CategoryList>
...........................
</ConfigData>


Snippet

In order to change the value of "Id" and remove all "CategoryList" element:
private void EditXAP(string xapFileName, string xmlFileToBeEdited)
{

    string clientBinPath = Server.MapPath(Request.ApplicationPath) + "/ClientBin/";
    string xapFilePath = clientBinPath + xapFileName;
    string templConfigFilePath = clientBinPath + xmlFileToBeEdited;
    Stream configXmlStream = new MemoryStream();
    ZipFile zipFile;

    zipFile = ZipFile.Read(xapFilePath);

    if (zipFile.EntryFileNames.Contains(xmlFileToBeEdited))
    {
        ZipEntry zipEntry = zipFile[xmlFileToBeEdited];
        zipEntry.Extract(configXmlStream);
        configXmlStream.Seek(0, 0);
        XDocument xDocument = XDocument.Load(configXmlStream);

        xDocument.Element("ConfigData").Element("Id").SetValue("AlteredId1");
        xDocument.Element("ConfigData").Elements("CategoryList").Remove();

        xDocument.Save(templConfigFilePath);

        zipFile.RemoveEntry(zipEntry);
        zipFile.AddFile(templConfigFilePath, "");
        zipFile.Save();

        FileInfo tempFile = new FileInfo(templConfigFilePath);
        if (tempFile.Exists)
        {
            tempFile.Delete();
        }
    }
}

Above specified snippet will update the XML file inside the Silvelight XAP.

References
http://dotnetzip.codeplex.com/ 

Thursday, March 24, 2011

Silverlight4 - Printing fit to page

RAVAGE

In my project one of the feature we need to provide is the ability to print a page which holds multiple custom widgets. Printing ability need to be provided in two stages. One for printing the individual widget and the other one for printing the entire page with multiple widgets. Initially I started with developing the provision for printing individual widgets and achieved it simply than what I expected, using the print API in Silverlight 4.

SIMPLE PRINT

SNIPPET 1

public void Print(UIElement elementToBePrinted, string documentName)
{
    PrintDocument docToPrint = new PrintDocument();

    docToPrint.PrintPage += (s, args) =>
    {
        args.PageVisual = elementToBePrinted;
    };

    docToPrint.Print(documentName);
}

I tried printing widgets of normal sizes using the above code which worked and tried the same for printing the entire page with multiple widgets where I got caught. Upon printing entire page, some part will exceed the print area based on the paper size resulting in partial area got print. Simply speaking it won't fit into print area.

We can tranform the FrameworkElement to fit the paper size but upon doing so the element will be scaled visually while printing and the user experience will not be good. Upon searching the web I found that people who experienced similar issues have done workarounds something similar to the one specified in a blog by Jacek Jura.

Workaround is hiding the scaled screen and showing a custom text like "Priniting in progress". I implemented similar workaround and still my tech lead is not satisfied. Hence, I pushed out to find a better alternate for this.

After trying with several options I compromised with one workaround. Idea is getting a snapshot of the element / page and showing the snapshot by hiding the scaled / transformed element while printing. Yes as most of might guess, its what our actors do to trick out video surveillance (in movies like MissionImpossible, Speed, etc....).

I altered the code to fit my needs. Until the completion of the printing process, the UI thread will be blocked and hence the user can't perform actions on UI till then. Hence showing snapshot at that time won't deviate the user experience.

Pros and Cons

The advantage is, user will experience the original view(visually) even when the element to be printed is scaled.
Disadvantage is, since we're showing the snapshot, it'll be slightly blur, but compromisable.

Snippet 2

public class PrintUtility
{
    #region Class Level Variables

    private const string NullReferenceExceptionMessage = "PrintElement is null : Please specify the element to be printed.";
    private Grid parentGrid;
    private Border borderItem;
    private WriteableBitmap printElementImage;
    private ImageBrush printElementImageBrush;

    #endregion

    #region Properties

    public FrameworkElement PrintElement { get; private set; }

    public string DocumentName { get; private set; }

    public FrameworkElement TabletUIElement { get; set; }

    #endregion

    #region Constructors

    public PrintUtility(FrameworkElement elementToBePrinted, string documentName)
    {
        this.PrintElement = elementToBePrinted;
        this.DocumentName = documentName;
    }

    #endregion

    #region Event Handlers

    void DocToPrint_EndPrint(object sender, EndPrintEventArgs e)
    {
        this.PrintElement.RenderTransform = null;

        if (this.borderItem != null)
        {
            if (parentGrid.Children.Contains(this.borderItem))
            {
                parentGrid.Children.Remove(this.borderItem);
            }
            this.borderItem = null;
        }

        this.parentGrid = null;
        this.printElementImage = null;
        this.printElementImageBrush = null;
    }

    void DocToPrint_BeginPrint(object sender, BeginPrintEventArgs e)
    {
        FrameworkElement maskElement = this.TabletUIElement ?? this.PrintElement;

        if (maskElement.Parent is Grid)
        {
            parentGrid = (Grid)maskElement.Parent;
            parentGrid.Children.Add(BuildBorderWithImageFill());
        }
    }

    void DocToPrint_PrintPage(object sender, PrintPageEventArgs e)
    {
        double scale = 1;

        if (e.PrintableArea.Height < this.PrintElement.ActualHeight)
        {
            scale = e.PrintableArea.Height / this.PrintElement.ActualHeight;
        }

        if (e.PrintableArea.Width < this.PrintElement.ActualWidth && e.PrintableArea.Width / this.PrintElement.ActualWidth < scale)
        {
            scale = e.PrintableArea.Width / this.PrintElement.ActualWidth;
        }

        if (scale < 1)
        {
            ScaleTransform scaleTransform = new ScaleTransform();
            scaleTransform.ScaleX = scale;
            scaleTransform.ScaleY = scale;

            this.PrintElement.RenderTransform = scaleTransform;
        }

        e.PageVisual = this.PrintElement;
    }

    #endregion

    #region Public Methods

    public void Print()
    {
        if (this.PrintElement != null)
        {
            PrintDocument docToPrint = new PrintDocument();

            docToPrint.PrintPage += new EventHandler<PrintPageEventArgs>(DocToPrint_PrintPage);
            docToPrint.BeginPrint += new EventHandler<BeginPrintEventArgs>(DocToPrint_BeginPrint);
            docToPrint.EndPrint += new EventHandler<EndPrintEventArgs>(DocToPrint_EndPrint);

            docToPrint.Print(this.DocumentName);
        }
        else
        {
            throw new NullReferenceException(NullReferenceExceptionMessage);
        }

    }

    #endregion

    #region Private Methods

    private Border BuildBorderWithImageFill()
    {
        printElementImageBrush = new ImageBrush();
        borderItem = new Border();

        printElementImage = new WriteableBitmap(this.TabletUIElement ?? this.PrintElement, null);
        printElementImageBrush.ImageSource = printElementImage;

        borderItem.Background = printElementImageBrush;
        borderItem.Child = new TextBlock() { Text = "Printing...", HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };

        return borderItem;
    }

    #endregion

}

As a prerequisite, we need a simple Grid immediately surrounding the printable element so as to place the snapshot in the Grid.

SUMMARY

Also I tried with creating an image from the printable element and scale the image to print. The resultant quality is good but not as good as printing the element directly. You can also try that if it suits for you. Snippet for creating an image of the printable element, scale the created image and then print the scaled image is specified below.

Snippet 3

public class PrintUtilityImageScaling
{
    #region Class Level Variables

    private const string NullReferenceExceptionMessage = "PrintElement is null : Please specify the element to be printed.";
    
    #endregion

    #region Properties

    public FrameworkElement PrintElement { get; private set; }

    public string DocumentName { get; private set; }

    #endregion

    #region Constructors

    public PrintUtilityImageScaling(FrameworkElement elementToBePrinted, string documentName)
    {
        this.PrintElement = elementToBePrinted;
        this.DocumentName = documentName;
    }

    #endregion

    #region Event Handlers

    void DocToPrint_PrintPage(object sender, PrintPageEventArgs e)
    {
        double scale = 1;
        WriteableBitmap writeableBitmap;

        if (e.PrintableArea.Height < this.PrintElement.ActualHeight)
        {
            scale = e.PrintableArea.Height / this.PrintElement.ActualHeight;
        }

        if (e.PrintableArea.Width < this.PrintElement.ActualWidth && e.PrintableArea.Width / this.PrintElement.ActualWidth < scale)
        {
            scale = e.PrintableArea.Width / this.PrintElement.ActualWidth;
        }

        if (scale < 1)
        {
            ScaleTransform scaleTransform = new ScaleTransform();
            scaleTransform.ScaleX = scale;
            scaleTransform.ScaleY = scale;

            writeableBitmap = new WriteableBitmap(this.PrintElement, scaleTransform);
            writeableBitmap.Invalidate();
        }
        else
        {
            writeableBitmap = new WriteableBitmap(this.PrintElement, null);
        }

        Image image = new Image();
        image.Source = writeableBitmap;

        Grid imageGrid = new Grid();
        imageGrid.Children.Add(image);

        e.PageVisual = imageGrid;
    }

    #endregion

    #region Public Methods

    public void Print()
    {
        if (this.PrintElement != null)
        {
            PrintDocument docToPrint = new PrintDocument();

            docToPrint.PrintPage += new EventHandler<PrintPageEventArgs>(DocToPrint_PrintPage);
            
            docToPrint.Print(this.DocumentName);
        }
        else
        {
            throw new NullReferenceException(NullReferenceExceptionMessage);
        }

    }

    #endregion

}

I prefer Snippet 2 over Snippet 3. But again its upto you to decide based on the scenario.

REFERENCES

http://jacekjura.blogspot.com/2010/11/silverlight-printing-fit-to-page.html

Wednesday, December 1, 2010

System.Security.SecurityException: Dialogs must be user-initiated.

The Printing API in Silverlight 4 helps us a lot like printing the entire page, printing a specific portion of a page……

In order to get a quick idea on the print API do have a look at this(A look at the Printing API in Silverlight 4) article on silverlightshow.

While implementing this print API in my project I came across the following error in some scenarios.

System.Security.SecurityException: Dialogs must be user-initiated.

This error message initially leads to lot of confusion and upon search found the cause. As all the developers do, I was debugging the code by putting breakpoint. The problem is I put the breakpoint over the line where the object initiation for PrintDocument happens. Something like……
 
 
 
So when the exception “ System.Security.SecurityException: Dialogs must be user-initiated.” got raised while using print API for Silverlight 4 in debug mode, ensure that you didn’t put breakpoint over the code that invokes the Print method.

REFERENCE

http://johnpapa.net/silverlight/printing-tip-ndash-handling-user-initiated-dialogs-exceptions/
Creative Commons License
This work by Tito is licensed under a Creative Commons Attribution 3.0 Unported License.