Sunday, March 4, 2012

Binding with StringFormat

With Silverlight, when you bind a property, you can use StringFormat to format the display.
{Binding SampleText, StringFormat='My Text: \{0\}'}

Strings

You can use StringFormat like the c# String.Format() method.

Composite Formatting

Numbers

CTo display a currency. ex: StrinFormat=C –> $300.00
NTo display a number. ex: StringFormat=N –> 33,456.56
ETo display a scientific number. ex: StringFormat=E –> 6.787653e+006
PTo display a percentage. This value must be between 0 and 1. ex: StringFormat=P –> 33.54%

Standard Numeric Format Strings
Custom Numeric Format Strings

DateTimes

FStringFormat=F –> Sunday, March 04, 2012 4:22:09 PM
GStringFormat=G –> 3/4/2012 4:22:09 PM
MStringFormat=M –> March 04

You can also use the format like “MMMM yyyy” but it must be between ‘ ex: StringFormat=’MMMM yyyy’

Standard date and Time Format Strings
Custom Date and Time Format Strings

Catch the silverlight closing event

Recently, I must catch the closing event of a silverlight application when users have not save their modifications. For this functionnality, I make a class with a boolean indicate pending changes.
public class ClosingHandler
{
    #region Properties
 
    private const string ScriptableObjectName = "OnBeforeUnload";
 
    /// <summary>
    /// Confirmation message
    /// </summary>
    public String Message { get; set; }
 
    private Boolean mHasPendingChange;
    /// <summary>
    /// Indicate pending change
    /// </summary>
    public Boolean HasPendingChange
    {
        get { return mHasPendingChange; }
        set
        {
            mHasPendingChange = value;
            if (value)
                Initialize();
            else
                Clear();
        }
    }
 
    #endregion
 
    #region Methods
 
    /// <summary>
    /// Initialization of the Hander
    /// </summary>
    public void Initialize()
    {
        //Out of Browser application
        if (Application.Current.IsRunningOutOfBrowser)
        {
            Application.Current.MainWindow.Closing +=
                new EventHandler<System.ComponentModel.ClosingEventArgs>(
                    MainWindow_Closing);
        }
        else    //In Browser application
        {
            HtmlPage.RegisterScriptableObject(ScriptableObjectName, this);
            string pluginName = HtmlPage.Plugin.Parent.Id;
 
            HtmlPage.Window.Eval(string.Format(
                @"window.onbeforeunload = function () {{
                var slApp = document.getElementById('{0}').getElementsByTagName('object')[0];
                var result = slApp.Content.{1}.OnBeforeUnload();
                if(result.length > 0)
                    return result;
                }}",
                pluginName, ScriptableObjectName)
                );
        }
    }
 
    /// <summary>
    /// Clear event handler and message
    /// </summary>
    public void Clear()
    {
        //Out of Browser application
        if (Application.Current.IsRunningOutOfBrowser)
        {
            Application.Current.MainWindow.Closing -=
                new EventHandler<System.ComponentModel.ClosingEventArgs>(
                    MainWindow_Closing);
        }
        else    //In Browser application
        {
            HtmlPage.RegisterScriptableObject(ScriptableObjectName, this);
            string pluginName = HtmlPage.Plugin.Parent.Id;
 
            HtmlPage.Window.Eval(@"window.onbeforeunload = ''");
        }
    }
 
    #endregion
 
    #region EventHandler
 
    /// <summary>
    /// MainWindow Closing event handler
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void MainWindow_Closing(object sender, System.ComponentModel.ClosingEventArgs e)
    {
        MessageBoxResult boxResult = MessageBox.Show(
                    Message, "Closing confirmation",
                    MessageBoxButton.OKCancel);
        if (boxResult == MessageBoxResult.Cancel)
            e.Cancel = true;
    }
 
    [ScriptableMember]
    public string OnBeforeUnload()
    {
        return Message;
    }
 
    #endregion
}

Source : http://mark.mymonster.nl/2011/01/30/how-to-cancel-the-closing-of-your-silverlight-application-in-browser-and-out-of-browser

Friday, March 2, 2012

DelegateCommand in Silverlight

public class DelegateCommand : ICommand
{
    /// <summary>
    /// Occurs when changes occur that affect whether the command should execute.
    /// </summary>
    public event EventHandler CanExecuteChanged;
 
    Func<objectbool> canExecute;
    Action<object> executeAction;
    bool canExecuteCache;
 
    /// <summary>
    /// Initializes a new instance of the <see cref="DelegateCommand"/> class.
    /// </summary>
    /// <param name="executeAction">The execute action.</param>
    /// <param name="canExecute">The can execute.</param>
    public DelegateCommand(Action<object> executeAction,
                            Func<objectbool> canExecute)
    {
        this.executeAction = executeAction;
        this.canExecute = canExecute;
    }
 
    /// <summary>
    /// Permet de déclencher l'evenement de modification du CanExecute
    /// </summary>
    public void OnCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
            CanExecuteChanged(thisnew EventArgs());
    }
 
    #region ICommand Members
    /// <summary>
    /// Defines the method that determines whether the command 
    /// can execute in its current state.
    /// </summary>
    /// <param name="parameter">
    /// Data used by the command. 
    /// If the command does not require data to be passed,
    /// this object can be set to null.
    /// </param>
    /// <returns>
    /// true if this command can be executed; otherwise, false.
    /// </returns>
    public bool CanExecute(object parameter)
    {
        bool tempCanExecute = canExecute(parameter);
 
        if (canExecuteCache != tempCanExecute)
        {
            canExecuteCache = tempCanExecute;
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(thisnew EventArgs());
            }
        }
 
        return canExecuteCache;
    }
 
    /// <summary>
    /// Defines the method to be called when the command is invoked.
    /// </summary>
    /// <param name="parameter">
    /// Data used by the command. 
    /// If the command does not require data to be passed, 
    /// this object can be set to null.
    /// </param>
    public void Execute(object parameter)
    {
        executeAction(parameter);
    }
    #endregion
} 

Source : http://compositewpf.codeplex.com/

Wednesday, February 29, 2012

Memory Leak with PagedCollectionView

Your silverlight application freeze when you filter or group a PagedCollectionView bind to a DataGrid ItemSource.
If you use Command in a DataGridTemplateColumn and you bind a property to the visibility of your button, you must be careful.
In fact, when you change the visibility of a button, the CanExecute method of the command is call. So if you change this visibility in the CanExecute method you make an infinite loop. The only solution is to set this value with an other method than the CanExecute.

Infinite Loop
private Boolean CanDelete(Object parameter) 
{
  YourViewModel vm = parameter as YourViewModel;
  if (vm != null)
  {
     if (vm.CanDelete)
     {
        vm.DeleteVisibility = Visibility.Visible;
        return true;
     }
     else
     {
        vm.DeleteVisibility = Visibility.Collapsed;
        return false;
      }
  }
 
  return false; 
}

Best Practice
private Boolean CanDelete(Object parameter) 
{
  YourViewModel vm = parameter as YourViewModel;
  if (vm != null)
  {
     return vm.CanDelete;
  }
 
  return false; 
}

private void Initialize()
{
  YourViewModel vm = new YourViewModel();
  vm.PropertyChanged += 
    new PropertyChangedEventHandler(
    vm_PropertyChanged);
}
 
void vm_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
  if (e.PropertyName == "CanDelete")
  {
    YourViewModel vm = sender as YourViewModel;
    if (vm != null)
    {
      vm.DeleteVisibility = vm.CanDelete ?
        Visibility.Visible : Visibility.Collapsed;
      //If you want call canExecute method to disbale button
      (DeleteCommand as DelegateCommand).OnCanExecuteChanged();
    }
  }
}

You also can use a BooleanToVisibility converter in your XAML and bind the property CanDelete. But you don't change the CanDelete value in the CanExecute method of your command.

I use the DelegateCommand for my command, you can find it to this url : http://spaeda.blogspot.com/2012/03/delegatecommand-in-silverlight.html

Saturday, February 11, 2012

Silverlight 4 ChildWindow leaves parent disabled after closing

A Silverlight 4 childWindow will close correctly at the first time, but in a second time it closes but leaves the UI parent disabled. Don’t be afraid, it’s a known issue.

While Microsoft don’t resolve it, you can enable the RootVisual in the OnClosed method of your childWindow.

protected override void OnClosed(EventArgs e)
{
     base.OnClosed(e);
     Application.Current.RootVisual.SetValue(Control.IsEnabledProperty, true);
}

Saturday, January 28, 2012

Make a XAML content localizable

  • Create a new resource file (see How to: Add Resources to a Silverlight-based Application) or reuse an existing one. You will later create additional resource files for each language/culture to which you are localizing your application, so you may want to create a folder for the resource files.
  • Open the resource file. At the top of the resource file window, make sure that AccessModifier is set to Public.
  • Add a Class item to your project, and give it an appropriate name (such as DisplayText in this example). Define a class with a property that points to the resources, as in the following example. In this example, SilverlightApp is the namespace that contains the resource file, and Resource1 is the name of the resource file
    public class DisplayText
    {
        /// <summary>
        /// Resources Dictionary
        /// </summary>
        public DisplayTextResources Resources { get; private set; }
    
    
        /// <summary>
        /// Constructor
        /// </summary>
        public DisplayText()
        {
            Resources = new DisplayTextResources();
        }
    }
  • Make sure that the class, its class constructor, and the property that returns the resource are public; otherwise, you won't be able to use it in XAML.
  • If you have multiple resource files in your project (for example, Resource1 and Resource2), you can have a single LocalizedStrings class with multiple properties, each of which returns a particular resource.
  • Open your App.xaml file and add the following to the <Application.Resources> section:
    <Application.Resources>
       <loc:DisplayText xmlns:loc="clr-namespace:appNamespace" 
                        x:Key="LocalizedStrings" />
    </Application.Resources>
  • where DisplayText is the name of the class with the property that returns your resource file, and appNamespace is the namespace that contains the LocalizedStrings class. The x:Key attribute defines the name by which you refer to a DisplayText instance in code.
  • Open a XAML file (such as MainPage.xaml) and find the individual strings in it that you want to localize.
  • To make a string that is assigned to an attribute localizable, replace the string value with the following:
    "{Binding Path=Resources.resourceName, Source={StaticResource LocalizedStrings}}"
    
    
  • where resourceName is the name of the localizable resource, Resources is the name of the resource file that contains resourceName, and LocalizedStrings is the name assigned to an instance of the class that returns the resource. For example, if the original XAML is the following:
    <Button Content="Submit" />
    you might change it to:
    <Button Content="{Binding Path=Resources.Submit, Source={StaticResource LocalizedStrings }}"/>
  • Repeat the previous step for all the strings that you want to make localizable in each XAML file in your application that contains localizable content.

User profile Synchronisation service is not provisioned

  • Login as farm account
  • Backup the User Profile DB and the User Profile Sync DB
  • Stop the SharePoint 2010 Timer service
  • Delete the data in the Sync DB using the following PowerShell commands (This is not a script. So please cut and paste each of these commands one by one):

Get-SPDatabase (Copy the GUID associated with the User Profile Sync DB)

$syncdb=Get-SPDatabase –Id <GUID>

$syncdb.Unprovision()

$syncdb.Status='Offline'

Get-SPServiceApplication (Copy the GUID associated with the User Profile Service)

$upa=Get-SPServiceApplication –Id <GUID>

$upa.ResetSynchronizationMachine()

$upa.ResetSynchronizationDatabase()

  • Provision the Sync DB:

$syncdb.Provision()

  • Add the User Profile Synchronization service account (farm account) as the dbowner on the Sync DB (using SQL Server Management Studio).
  • Start the SharePoint 2010 Timer service
  • Start the User Profile Synchronization Service in the Central Administration UI.
  • After the User Profile Synchronization Service is started, reset IIS.
  • Create connections to data sources in the Central Administration UI.