Using the Infragistics Control Persistence Framework with XamGrid

This article describes how to use the Infragistics Control Persistence Framework with XamGrid.

There are many cases when customers want to go back to the saved state of the application layout or to save the state of the Silverlight application when they close it and use it again next way when they start this application.

 Persistence Framework provides possibility to serialize and deserialize the state of the specified control or group of controls.

Most of Infragistics Line of Business and Microsoft Silverlight components works with the Control Persistence Framework. It is possible to control which of the component properties should be persistable and which shouldn't be.

For custom controls you need to maintain properties, which state will be saved or not implementing IProvidePropertyPersistenceSettings interface.

 public interface IProvidePropertyPersistenceSettings

{

       /// <summary>

       /// Gets a List of properties that shouldn't be saved when the PersistenceManager goes to save them.

       /// </summary>

       List<string> PropertiesToIgnore { get; }

 

       /// <summary>

       /// Gets a List of properties that should be applied, before even trying to look at any other property on the object.

        /// </summary>

        List<string> PriorityProperties { get; }

 

        /// <summary>

        /// Allows an object to perform an operation, after it's been loaded.

        /// </summary>

        void FinishedLoadingPersistence();

}

 

For property, that are ignored in this implementation you need to add a custom implementation of the persistence support.

This article demonstrates the mentioned above cases with the Infragistics Control Persistence Framework and XamGrid.

Demo application is based on created in the part 1 and part 2 of article "Using the Infragistics XamGrid and XamDataChart with Hierarchical Data and WCF RIA Services".

 

 In this application are used XamGrid and XamDataChart with WCF RIA Services. There is implementation of the XamGrid filtering.

When select specified bar from the chart

void XamDataChartSeriesMouseLeftButtonDown(object sender, Infragistics.Controls.Charts.DataChartMouseButtonEventArgs e)

{

    Customer customer = e.Item as Customer;

    if (customer == null)

    {

        return;

    }

 

    string value = customer.CustomerID;

 

    Shape x = e.OriginalSource as Shape;

    if (x != null)

    {

        _origBrush = x.Fill;

        _isChanged = true;

        x.Fill = new SolidColorBrush(Colors.Cyan);

    }

     Column col = customerXamGrid.Columns.DataColumns["CustomerID"];

    RowsFilter rf = new RowsFilter(typeof(string), col);

     if (ChkLowerFilter.IsChecked == true)

    {

        rf.Conditions.Add(new ComparisonCondition() { Operator = ComparisonOperator.GreaterThan, FilterValue = value});

    }

    else if (ChkUpperFilter.IsChecked == true)

    {

        rf.Conditions.Add(new ComparisonCondition() { Operator = ComparisonOperator.LessThan, FilterValue = value});

    }

    else

    {

        return;

    }

     customerXamGrid.FilteringSettings.RowFiltersCollection.Add(rf);

 }

 

In this sample will be added Persistence Framework support to save the XamGrid layout and filtering settings. XamGrid don't persist some of properties like Rows, ActiveCell, SelectedCells, SelectedRows. It persist XamGrid layout - position and sizes of the columns , visible rows etc.

Developers can still save these properties by adding them to the PropertySettings collection.

Requirements:

You need to install trial version of NetAdvantage for Silverlight Line of Business 10.2 . Demo sample includes also XamDataChart from  NetAdvantage for Silverlight Data Visualization 10.2 - it is not required when use an Infragistics Control Persistence Framework.

 

Create a Silverlight application with XamGrid and Persistence Framework:

  1. Create a Silverlight application, hosted in an ASP.Net application (demo application also uses WCF RIA Services).
  2. Create a Silverlight client with XamGrid and appropriate data (demo application data via RIA Services).
  3. Reference the InfragisticsSL4.Persistence.v10.2 assembly
  4.  Implement save and load functionalities for XamGrid settings
  5. Maintain additional controls with Persistence Framework via PersistenceGroup objects.

 Steps to create a Silverlight application are described in the in the part 1 and part 2 of article "Using the Infragistics XamGrid and XamDataChart with Hierarchical Data and WCF RIA Services".

  • Reference the InfragisticsSL4.Persistence.v10.2 assembly

 

 

  • Implement Save and Load setting for XamGrid:

Add buttons to save and restore the XamGrid state:

<Button x:Name="BtnSaveState" Content="Save State" Click="BtnSaveState_Click"/>

<Button x:Name="BtnRestoreState" Content="Restore State" Click="BtnRestoreState_Click" />

Add member variables

private MemoryStream _memoryStream = new MemoryStream();

private PersistenceGroup _persistenceGroup = new PersistenceGroup();

Implement Save and Load in the event handlers:

 

 

private void BtnSaveState_Click(object sender, RoutedEventArgs e)

{

    // Saves persisted object

 

    _memoryStream = PersistenceManager.Save(customerXamGrid);

}

private void BtnRestoreState_Click(object sender, RoutedEventArgs e)

{

    _memoryStream.Position = 0;

    // Load persisted object

    PersistenceManager.Load(customerXamGrid, _memoryStream);

}

Start the application and check Lower Limits CheckBox and select the bar with "FAMIA" CustomerID to set filtering options to XamGrid.  Only Customers with CutomerID , greater than "FAMIA" will be appeared in the XamGrid.

Layout of the grid is saved, but filtering options will not:

 Layout when save the XamGrid settings

 

 Layout after reset the settings and load the saved one with Persistence Framework.

The reason to lose the filtering settings is that XamGrid don't persist some of properties like Rows, ActiveCell, SelectedCells, FilteringSettings by default.

 

  • Change the Filtering Settings

We will save FilteringSettings by adding them to the PropertySettings collection

<ig:XamGrid Grid.Row="1" Grid.Column="1"  AutoGenerateColumns="False" HorizontalAlignment="Left"  ItemsSource="{Binding ElementName=customerDomainDataSource, Path=Data}" Margin="20" Name="customerXamGrid" VerticalAlignment="Top">

    <ig:PersistenceManager.Settings>

        <ig:PersistenceSettings SavePersistenceOptions="AllButIgnored" >

            <ig:PersistenceSettings.PropertySettings>

                <ig:PropertyNamePersistenceInfo PropertyName="FilteringSettings"/>

            </ig:PersistenceSettings.PropertySettings>

        </ig:PersistenceSettings>

    </ig:PersistenceManager.Settings>

    <ig:XamGrid.FilteringSettings>

        <ig:FilteringSettings>

            <ig:PersistenceManager.Settings>

                <ig:PersistenceSettings SavePersistenceOptions="AllButIgnored" >

                    <ig:PersistenceSettings.PropertySettings>

                        <ig:PropertyNamePersistenceInfo PropertyName="RowFiltersCollection"/>

                    </ig:PersistenceSettings.PropertySettings>

                </ig:PersistenceSettings>

            </ig:PersistenceManager.Settings>

        </ig:FilteringSettings>                   

    </ig:XamGrid.FilteringSettings>

…..

</ig:XamGrid>

 

The grid layout and filtering settings are the same when save the settings  and when load it after reset to default layout:

 

Layout when save the XamGrid settings

 

 

Layout after reset the settings and load the saved one with Persistence Framework.

  • Persist the state of more controls using the PersistenceGroup object.

Add a PersistanceGroup object to resources:

 <UserControl.Resources>

    <ig:PersistenceGroup x:Key="igPG" />

</UserControl.Resources>

Set the attached property PersistenceManager.PersistenceGroup to XamGrid:

<ig:XamGrid Grid.Row="1" Grid.Column="1"  AutoGenerateColumns="False" HorizontalAlignment="Left"

    ItemsSource="{Binding ElementName=customerDomainDataSource, Path=Data}" Margin="20" Name="customerXamGrid"

            VerticalAlignment="Top" ig:PersistenceManager.PersistenceGroup="{StaticResource igPG}"

            Loaded="customerXamGrid_Loaded">

<ig:XamGrid>

 Set the attached property PersistenceManager.PersistenceGroup to the TextBox controls, placed in the Grid with the detail data:

 <Grid DataContext="{Binding ElementName=customerDomainDataSource1, Path=Data}" Grid.Row="1" HorizontalAlignment="Left" Margin="3"

        Name="grid1" VerticalAlignment="Top">

….

    <TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="addressTextBox" Text="{Binding Path=Address, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" ig:PersistenceManager.PersistenceGroup="{StaticResource igPG}"/>

    <TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="cityTextBox" Text="{Binding Path=City, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" ig:PersistenceManager.PersistenceGroup="{StaticResource igPG}"/>

</Grid>

 Add a PersistaceGroup object to the application:

private bool _isSaveCompleted = false;

private PersistenceGroup _persistenceGroup = new PersistenceGroup();

public MainPage()

{

    InitializeComponent();

….

    this.customerXamGrid.SelectedRowsCollectionChanged += new EventHandler<SelectionCollectionChangedEventArgs<SelectedRowsCollection>>(CustomerXamGrid_SelectedRowsCollectionChanged);

    _persistenceGroup = this.Resources[Group] as PersistenceGroup;

    if (_persistenceGroup != null)

    {

        _persistenceGroup.Events.PersistenceSaved += new EventHandler<PersistenceSavedEventArgs>(PersistenceSaved);

    } 

}

 Load and save setting for all controls from the group via PersistenceSettings object:

private void BtnSaveState_Click(object sender, RoutedEventArgs e)

{

    // Saves persisted group

    _memoryStream = PersistenceManager.Save(_persistenceGroup);

}

 

private void PersistenceSaved(object sender, PersistenceSavedEventArgs e)

{

    // Flag for Save process completion

    this._isSaveCompleted = true;

}

 

private void BtnRestoreState_Click(object sender, RoutedEventArgs e)

{

    _memoryStream.Position = 0;   

    if (_isSaveCompleted)

    {

        PersistenceManager.Load(_persistenceGroup, _memoryStream);

    }

}

Layout when save the PersistenceGroup members settings

 

Layout after reset the settings and load the saved one with Persistence Framework.

 

  • Save state to isolated storage and load it when starts the application:

 

private void SaveIntoISO(PersistenceGroup grp, string fileName)

{

    this._memoryStream = PersistenceManager.Save(grp);

 

    long requestedQuotaSize = this._memoryStream.Length + 524288;

 

    using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())

    {

        if (iso.Quota < requestedQuotaSize)

        {

 

            MessageBox.Show("Storage is not enough! Increase it to " + requestedQuotaSize.ToString());

 

            TxtQuota.Text = requestedQuotaSize.ToString();

            BtnIncreaseQuota.Focus();

 

            return;

        }

 

        if (iso.FileExists(fileName))

            iso.DeleteFile(fileName);

 

        using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, iso))

        {

            stream.Write(this._memoryStream.ToArray(), 0, (int)this._memoryStream.Length);

        }

    }

}

                               

private void LoadFromISO(PersistenceGroup grp, string fileName)

{

    using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())

    {

        if (iso.FileExists(fileName))

        {

            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, iso))

            {

                if (stream.Length > 0)

                {

                    try

                    {

                        PersistenceManager.Load(grp, stream);

                    }

                    catch (Exception)

                    {

                    }

                }

                       

            }

        }

    }

}

 

private void BtnSaveState_Click(object sender, RoutedEventArgs e)

{

// Saves customerIDTextBox1 TextBox

_memoryStream2 = PersistenceManager.Save(customerIDTextBox1);

   

// Saves persisted group

    this.SaveIntoISO(_persistenceGroup, IsoFile);

}

 

private void BtnRestoreState_Click(object sender, RoutedEventArgs e)

{

    _memoryStream.Position = 0;

    _memoryStream2.Position = 0;

           

 

    if (_isSaveCompleted)

    {

        // Loads persistence group from MemoryStream

        PersistenceManager.Load(_persistenceGroup, _memoryStream);

        // Load customerIDTextBox1 TextBox

        PersistenceManager.Load(customerIDTextBox1, _memoryStream2);

    }

}

 

An event handler is added to the Loaded event of the XanGrid

 

private void customerXamGrid_Loaded(object sender, RoutedEventArgs e)

{

    this.LoadFromISO(_persistenceGroup, IsoFile);

}

 

<ig:XamGrid Grid.Row="1" Grid.Column="1"  AutoGenerateColumns="False" HorizontalAlignment="Left"

    ItemsSource="{Binding ElementName=customerDomainDataSource, Path=Data}" Margin="20" Name="customerXamGrid" VerticalAlignment="Top" ig:PersistenceManager.PersistenceGroup="{StaticResource igPG}"

            Loaded="customerXamGrid_Loaded">

…..

</ig:XamGrid>

 

Controls, bound with TwoWay mode to DomainDataSource can't load saved values when the application starts because their source is null. Controls , bound with OneWay mode can.

To keep the same behavior for all controls we will persist these controls in a separate MemoryStream that  will not saved  into an IsolatedStorage .

<TextBox Grid.Column="1" Grid.Row="5" Height="23" HorizontalAlignment="Left" Margin="3" Name="countryTextBox" Text="{Binding Path=Country, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, TargetNullValue=''}" VerticalAlignment="Center" Width="120" ig:PersistenceManager.PersistenceGroup="{StaticResource igPG}"/>

<TextBox Grid.Column="1" Grid.Row="6" Height="23" HorizontalAlignment="Left" Margin="3" Name="customerIDTextBox1" Text="{Binding Path=CustomerID, Mode=OneWay}" VerticalAlignment="Center" Width="120" ig:PersistenceManager.PersistenceGroup="{StaticResource igPG}"/>

 

 

 

When there an IsolatedStorage quota is not enough code to increase the quota is added.

Changing of the quota must be user initialized - code is added in the event handler of the Button.Click event.

 

private void BtnIncreaseQuota_Click(object sender, RoutedEventArgs e)

{

    if (!this.TxtQuota.Text.Equals(String.Empty))

    {

        try

        {

            long quota = System.Convert.ToInt64(this.TxtQuota.Text);

            IncreaseStorage(quota);

        }

        catch (FormatException ex)

        {

 

            MessageBox.Show(ex.Message);

        }

        this.TxtQuota.Text = "";

    }

}

 

private void IncreaseStorage(long spaceRequest)

{

    using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())

    {

        try

        {

            if (true == isf.IncreaseQuotaTo(spaceRequest))

            {

                Results.Text = "Isolated Strorage Quota is " + isf.Quota.ToString();

            }

            else

            {

                Results.Text = "Insufficient Quota :" + isf.Quota.ToString();

            }

        }

        catch (Exception e)

        {

            Results.Text = "An error occured: " + e.Message;

        }

    }

}

 

A XamGrid layout when save the settings of the PersistenceGroup members.

A XamGrid layout after reset the settings and load the saved one with Persistence Framework.

A XamGrid layout when the application is started and the settings are loaded from the Persistence Framework.

Source code of the demo application you could find here:CustomerOrdersRiaApp.PersistenceFramework.zip