Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Section

Remarks

UXGridView provides a flexible way to display a collection of data in rows and columns. The built-in column types include a text box column, a check box column, combo box column and template column for hosting custom content. The built-in row type includes a drop-down details section that you can use to display additional content below the cell values.

To bind UXGridView to data, set the ItemsSource property to an object that implements IEnumerable. Each row in the UXGridView is bound to an object in the data source, and each column in the UXGridView is bound to a property of the data object. In order for the UXGridView user interface to update automatically when items are added to or removed from the source data, UXGridView must be bound to a collection that implements INotifyCollectionChanged, such as an ObservableCollection<T>. In addition, for the user interface to automatically reflect property changes, the objects in the source collection must implement the INotifyPropertyChanged interface.

The following code shows a simple UXGridView with data binding in XAML.

Code Block
titleXAML
languagexml
<Intersoft:UXGridView ItemsSource="{Binding Products}"/>

For more information about UXGridView, see UXGridView Overview.

Example

The following code shows a simple UXGridView with data binding in XAML.

Code Block
titleXAML
languagexml
<Intersoft:UXGridView ItemsSource="{Binding Products}"/>

Working with AutoGenerateColumns Property and Columns Property

By default, the UXGridView control generates columns automatically when you set the ItemsSource property. The generated columns are of type UXGridViewCheckBoxColumn for bound Boolean (and nullable Boolean) properties, and of type UXGridViewTextColumn for all other properties. If a property does not have a string or numeric value type, the generated text box columns are read-only and display the data object's ToString value.

You can prevent automatic column generation by setting the AutoGenerateColumns property to false. This is useful when you want to create and configure all columns explicitly. Alternatively, you can let the data grid generate the columns, but handle the AutoGeneratingColumn event to customize columns after they are instantiated. To rearrange the display order of the columns, you can set the DisplayIndex property to the desired value for each individual column.

Generated columns recognize the DisplayAttribute if it is present on the source object. The DisplayAttribute.ShortName property is used to specify column header text. The DisplayAttribute.Order property is used to specify the order in which columns appear. The DisplayAttribute.AutoGenerateField property is used to specify whether the field has a column generated for it.

Regardless of how you generate the columns, you can access the Columns collection to programmatically add, insert, remove, and change any columns in the control at run time. Alternatively, you can specify columns in XAML, in which case you should set AutoGenerateColumns to false. Creating your own columns enables you to use additional column types, such as the UXGridViewCheckBoxColumn, UXGridViewExpanderColumn, UXGridViewSelectColumn, UXGridViewTemplateColumn or other custom column type that inherited from UXGridViewColumn.

The following list describes the built-in column types available in UXGridView.

  • UXGridViewCheckBoxColumn type provides an easy way to enable editing using combo box. You can provide the data for the editing combo box through the provided ValueListSource property, and determine the DisplayMemberPath and ValueMemberPath for the display and value object respectively.

    Code Block
    titleXAML
    languagexml
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewComboBoxColumn Header="Category ID"
    										DisplayMemberPath="CategoryName"
    										ValueMemberPath="CategoryID" Width="120"
                                            Binding="{Binding CategoryID,
    											Converter={StaticResource CategoryConverter}}"
                                            ValueListSource="{Binding Categories,
    											Source={StaticResource CategoriesViewModel}}"/>
    </Intersoft:UXGridView.Columns>

  • UXGridViewExpanderColumn type provides an easy way to expand and collapse a row details if you enable row details in UXGridView.

    Code Block
    titleXAML
    languagexml
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewExpanderColumn />
        <Intersoft:UXGridViewTextColumn Header="Customer ID" Binding="{Binding CustomerID}"/>
        <Intersoft:UXGridViewTextColumn Header="Contact Name" Binding="{Binding ContactName}"/>
        <Intersoft:UXGridViewTextColumn Header="Contact Title" Binding="{Binding ContactTitle}"/>
        <Intersoft:UXGridViewTextColumn Header="CompanyName" Binding="{Binding CompanyName}"/>
    </Intersoft:UXGridView.Columns>

  • UXGridViewSelectColumn type provides an easy way to enable selector column which allows you to check or uncheck a row in UXGridView. The checked items are accessible in theCheckedItems property. This column type also automatically adds a checkbox in the column header, allowing users to easily toggle the checked state of all the rows in the view.

    Code Block
    titleXAML
    languagexml
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewSelectColumn/>
        <Intersoft:UXGridViewTextColumn Header="Customer ID" Binding="{Binding CustomerID}"/>
        <Intersoft:UXGridViewTextColumn Header="Contact Name" Binding="{Binding ContactName}"/>
        <Intersoft:UXGridViewTextColumn Header="Contact Title" Binding="{Binding ContactTitle}"/>
        <Intersoft:UXGridViewTextColumn Header="CompanyName" Binding="{Binding CompanyName}"/>
    </Intersoft:UXGridView.Columns>

  • UXGridViewTemplateColumn type provides full flexibility to create custom columns with specific behaviors that meet your application's requirements. The CellTemplate and CellEditingTemplate properties enable you to specify the content templates for both display and editing mode.

    Code Block
    titleXAML
    languagexml
    <Intersoft:UXGridViewTextColumn Header="Birth Date"
    		Binding="{Binding BirthDate, StringFormat=MM/dd/yyyy}">
        <Intersoft:UXGridViewTextColumn.CellEditingTemplate>
            <DataTemplate>
                <Grid Background="White" Margin="1">
                    <Intersoft:UXDateTimePicker
    					Value="{Binding BirthDate, Mode=TwoWay}"
    					EditMask="MM/dd/yyyy" BorderThickness="0"
    					UseEditMaskAsDisplayMask="True"
    					VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
                </Grid>
            </DataTemplate>
        </Intersoft:UXGridViewTextColumn.CellEditingTemplate>
    </Intersoft:UXGridViewTextColumn>

    Modern note

    TheCellTemplate and CellEditingTemplate properties are also available in all built-in column types, allowing you to change the display and editing template for the desired columns.

Working with CanUserAddRows Property, CanUserDeleteRows Property and CanUserEditRows Property

Data editing in UXGridView involves three fundamental processes, Create, Update and Delete (CUD). You can enable each editing feature by setting the property CanUserAddRowsCanUserEditRows and CanUserDeleteRows respectively.

Code Block
titleExample Title
languagexml
<Intersoft:UXGridView CanUserAddRows="True" CanUserDeleteRows="True" CanUserEditRows="True"/>

A NewRow element will appear in the top of the UXGridView user interface when you set the CanUserAddRows property to true, such as shown in the following illustration.

In addition, you can also delete and edit the selected item by setting both the CanUserEditRows and CanUserDeleteRows properties to true.

Working with CanUserExport Property

To enable data exporting in UXGridView, you simply set the CanUserExport property of UXGridView to true.

When enabled, an Export dropdown button will appear in the status bar element of UXGridView.

You can also select the format of the exported results from the context menu as shown in the figure above. The supported export format are:

  • HTML
  • Excel
  • CSV
  • Text

Furthermore, you can also customize which element to export through the provided ExportOptions property. The following code shows how to include column footers and group footers in the data export results.

Modern note

IncludeColumnFooters and IncludeGroupFooters are only applicable for HTML format.

Code Block
titleXAML
languagexml
<Intersoft:UXGridView CanUserExport="{Binding CanUserExport}">
    <Intersoft:UXGridView.ExportOptions>
        <Intersoft:UXGridViewExportOptions IncludeColumnFooters="True"
			IncludeColumnHeaders="True" IncludeGroupFooters="True" />
    </Intersoft:UXGridView.ExportOptions>
</Intersoft:UXGridView>

Working with CanUserGroupColumns Property

Code Block
titleXAML
languagexml
<Intersoft:UXGridView CanUserGroupColumns="False">
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewTextColumn Header="Customer ID"
			Binding="{Binding CustomerID}"/>
        <Intersoft:UXGridViewTextColumn Header="Contact Name"
			Binding="{Binding ContactName}"/>
        <Intersoft:UXGridViewTextColumn Header="Contact Title"
			Binding="{Binding ContactTitle}" CanUserGroup="True"/>
        <Intersoft:UXGridViewTextColumn Header="CompanyName"
			Binding="{Binding CompanyName}"/>
    </Intersoft:UXGridView.Columns>
</Intersoft:UXGridView>

Working with CanUserPage Property

To enable data sorting in UXGridView, you set the CanUserPage property to true and the PageSize property to the number of records per page in UXGridView.

Code Block
titleXAML
languagexml
<Intersoft:UXGridView CanUserPage="True" PageSize="30"/>

When enabled, a data pager user interface will appear in the status bar element of UXGridView.

Depending on the QueryOperation property, the data paging can be handled in either client or server side.

Working with CanUserSortColumns Property

To enable data sorting in UXGridView, you set the CanUserSortColumns property of UXGridView to true. If you prefer to enable sorting only on certain columns, set the CanUserSort property of the UXGridColumn to true.

Code Block
titleXAML
languagexml
<Intersoft:UXGridView CanUserSortColumns="True">
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewTextColumn Header="Customer ID"
			Binding="{Binding CustomerID}" CanUserSort="False"/>
        <Intersoft:UXGridViewTextColumn Header="Contact Name"
			Binding="{Binding ContactName}"/>
        <Intersoft:UXGridViewTextColumn Header="Contact Title"
			Binding="{Binding ContactTitle}"/>
        <Intersoft:UXGridViewTextColumn Header="CompanyName"
			Binding="{Binding CompanyName}"/>
    </Intersoft:UXGridView.Columns>
</Intersoft:UXGridView>

Depending on the value of the QueryOperation property, the data sorting can be handled in either client or server side.

Working with CellEditingTemplateSelector Property

A rather unique scenario is where the users would like to have different editing control for the same column that depends on the data that currently being edited. This can be achieved elegantly in UXGridView by using CellEditingTemplateSelector. It works similarly to any other template selectors.

The following code shows how to create the editing template selector and used it in UXGridView.

Code Block
titleCell Editing Template Selector
languagec#
using System.Windows;
using Intersoft.Client.Framework;
using Intersoft.Client.UI.Data;

namespace UXGridView.Samples.Selectors
{
    public class CellEditingSelector: DataTemplateSelector
    {
        public DataTemplate NumericEditor { get; set; }
        public DataTemplate SliderEditor { get; set; }

        public override DataTemplate SelectTemplate(object item,
                 DependencyObject container)
        {
            UXGridViewCell cell = container as UXGridViewCell;
            UXGridViewRowBase rowBase = cell.OwningRowBase;
            UXGridViewRow row = rowBase as UXGridViewRow;

            switch (cell.OwningColumn.PropertyName)
            {
                case "UnitsInStock":
                    if (rowBase.IsNewRow || (row != null && row.Index % 2 != 0))
                        return this.SliderEditor;
                    else
                        return this.NumericEditor;
            }

            return null;
        }
    }
}
Code Block
titleView
languagexml
<Grid.Resources>
    <DataTemplate x:Key="NumericEditor">
        <Intersoft:UXNumericUpDown Maximum="100" Value="{Binding UnitsInStock, Mode=TwoWay}"
                                      HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
 </DataTemplate>
    <DataTemplate x:Key="SliderEditor">
        <Intersoft:UXSliderBar Value="{Binding UnitsInStock, Mode=TwoWay}"
                                  SmallChange="10" LargeChange="20" Maximum="100"/>
    </DataTemplate> 
    <Selectors:CellEditingSelector x:Key="CellEditingSelector"
               NumericEditor="{StaticResource NumericEditor}"
               SliderEditor="{StaticResource SliderEditor}"/>
</Grid.Resources>

<Intersoft:UXGridView CellEditingTemplateSelector="{StaticResource CellEditingSelector}">

Working with ColumnFooterVisibility Property

Code Block
titleXAML
languagexml
<Intersoft:UXGridView ColumnFooterVisibility="Visible" ItemsSource="{Binding Products}" >
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewTextColumn Header="Category ID" Binding="{Binding CategoryID}"/>
        <Intersoft:UXGridViewTextColumn Header="Product ID" Binding="{Binding ProductID}"
			Aggregate="Count" FooterFormatString="Count = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Product Name" Binding="{Binding ProductName}"/>
        <Intersoft:UXGridViewTextColumn Header="Units In Stock" Binding="{Binding UnitsInStock}"
			Aggregate="Max" FooterFormatString="Max = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Unit Price" Binding="{Binding UnitPrice}"
			Aggregate="Avg" FooterFormatString="Avg = {0:n2}"/>
        <Intersoft:UXGridViewTextColumn Header="Units On Order" Binding="{Binding UnitsOnOrder}"
			Aggregate="Min" FooterFormatString="Min = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Quantity Per Unit"
			Binding="{Binding QuantityPerUnit}"/>
    </Intersoft:UXGridView.Columns>
</Intersoft:UXGridView>

Working with DeleteRowCommand Property, InsertRowCommand Property, PrepareNewRowCommand Property, RejectChangesCommand Property, RejectRowCommand Property, SaveChangesCommand Property, UpdateCellCommand Property, UpdateRowCommand Property and ValidateRowCommand Property

To handle the CUD operation, UXGridView provides several command-related properties that you can bind to your ViewModel to execute a method depending on the actions. These command-related properties are listed as follows:

  • PrepareNewRowCommand
    Called when you begin edit at the NewRow element. Used to initialized the NewItem.
  • ValidateRowCommand
    Validate the row before the row is committed.
  • InsertRowCommand
    Called when a new row is committed. You can directly save the changes and/or refresh the UXGridView if necessary.
  • UpdateCellCommand
    Called when the cell is committed.
  • UpdateRowCommand
    Called when an existing row is committed. You can directly save the changes and/or refresh the UXGridView if necessary.
  • DeleteRowCommand
    Called when a row is deleted. You can directly save the changes and / or refresh the UXGridView if necessary.
  • RejectRowCommand
    Called when the changes in the row is cancelled. This command is used to reject the changes in the data entity if required (such as in DevForce).
  • SaveChangesCommand
    Called when the save changes command is executed. You handle this command to save all the pending changes made in the UXGridView.
  • RejectChangesCommand
    Called when the reject changes command is executed. You handle this command to reject all the pending changes made in the UXGridView.

You need to bind these command properties to your ViewModel and handle each of the action. Beside these command, UXGridView also provide HasChanges that you can use to determine whether there are existing changes in the data.

The following code example shows how to define and bind the editing commands from ViewModel to UXGridView.

Code Block
titleView Model
languagec#
using System.Collections;
using Intersoft.Client.Framework;
using Intersoft.Client.Framework.Input;
using Intersoft.Client.UI.Data;
using UXGridView.Samples.ModelServices;

namespace UXGridView.Samples.ViewModels
{
    public class ServerEditingViewModel : ViewModelBase
    {
        public ServerEditingViewModel()
            : base()
        {
            this.Manager = new NorthwindDomainContext();
            this.QueryDescriptor = new QueryDescriptor();
            
            this.ExportCommand = new DelegateCommand(ExecuteExportCommand);
            this.DeleteRowCommand = new DelegateCommand(ExecuteDeleteRow);
            this.InsertRowCommand = new DelegateCommand(ExecuteInsertRow);
            this.PrepareNewRowCommand = new DelegateCommand(ExecutePrepareNewRow);
            this.UpdateCellCommand = new DelegateCommand(ExecuteUpdateCell);
            this.UpdateRowCommand = new DelegateCommand(ExecuteUpdateRow);
            this.RejectRowCommand = new DelegateCommand(ExecuteRejectRow);
            this.RejectChangesCommand = new DelegateCommand(ExecuteRejectChanges);
            this.SaveChangesCommand = new DelegateCommand(ExecuteSaveChanges);
            this.ValidateRowCommand = new DelegateCommand(ExecuteValidateRow);
        }

        #region Fields

        private bool _hasChanges;
        private bool _isBusy;
        private bool _isRefreshed;
        private object _newProduct;
        private IEnumerable _products;
        private QueryDescriptor _queryDescriptor;
        
        #endregion

        #region Properties

        private NorthwindDomainContext Manager { get; set; }

        public IEnumerable Products
        {
            get { return this._products; }
            set
            {
                if (this._products != value)
                {
                    this._products = value;
                    this.OnPropertyChanged("Products");
                }
            }
        }

        public QueryDescriptor QueryDescriptor
        {
            get
            {
                return this._queryDescriptor;
            }
            set
            {
                if (this._queryDescriptor != value)
                {
                    if (this._queryDescriptor != null)
                        this._queryDescriptor.QueryChanged -=
							new System.EventHandler(OnQueryChanged);

                    this._queryDescriptor = value;
                    this._queryDescriptor.QueryChanged +=
						new System.EventHandler(OnQueryChanged);

                    this.OnPropertyChanged("QueryDescriptor");
                }
            }
        }

        #endregion

        #region Selection and Editing Properties

        public object NewProduct
        {
            get { return this._newProduct; }
            set
            {
                if (this._newProduct != value)
                {
                    this._newProduct = value;
                    this.OnPropertyChanged("NewProduct");
                }
            }
        }      

        public bool IsBusy
        {
            get { return this._isBusy; }
            set
            {
                if (this._isBusy != value)
                {
                    this._isBusy = value;
                    this.OnPropertyChanged("IsBusy");
                }
            }
        }

        public bool IsRefreshed
        {
            get { return this._isRefreshed; }
            set
            {
                if (this._isRefreshed != value)
                {
                    this._isRefreshed = value;
                    this.OnPropertyChanged("IsRefreshed");
                }
            }
        }

        public bool HasChanges
        {
            get { return _hasChanges; }
            set
            {
                if (_hasChanges != value)
                {
                    _hasChanges = value;
                    OnPropertyChanged("HasChanges");
                }
            }
        }

        #endregion

        #region Commands

        public DelegateCommand DeleteRowCommand { get; set; }
        public DelegateCommand InsertRowCommand { get; set; }
        public DelegateCommand PrepareNewRowCommand { get; set; }
        public DelegateCommand UpdateCellCommand { get; set; }
        public DelegateCommand UpdateRowCommand { get; set; }
        public DelegateCommand RejectRowCommand { get; set; }
        public DelegateCommand RejectChangesCommand { get; set; }
        public DelegateCommand SaveChangesCommand { get; set; }
        public DelegateCommand ValidateRowCommand { get; set; }

        #endregion

        #region Methods

        public void SaveChanges()
        {

        }

        public void ExecuteDeleteRow(object parameter)
        {

        }

        public void ExecuteInsertRow(object parameter)
        {

        }

        public void ExecutePrepareNewRow(object parameter)
        {
            
        }

        public void ExecuteUpdateCell(object parameter)
        {
            
        }

        public void ExecuteValidateRow(object parameter)
        {
            
        }

        public void ExecuteUpdateRow(object parameter)
        {
            
        }

        public void ExecuteRejectRow(object parameter)
        {
            
        }

        public void ExecuteRejectChanges(object parameter)
        {
            
        }

        public void ExecuteSaveChanges(object parameter)
        {
            
        }

        public virtual void LoadProducts()
        {
            if (Intersoft.Client.Framework.ISControl.IsInDesignModeStatic)
                return;

            var query = this.Manager.GetProductsQuery().
							OrderBy(p => p.ProductID).Parse(this.QueryDescriptor);
            query.IncludeTotalCount = true;

            this.Manager.Load(
               query,
               op =>
               {
                   if (op.IsComplete)
                   {
                       this.Products = new Intersoft.Client.Data.
											ComponentModel.PagedCollectionView(op.Entities);
                       this.QueryDescriptor.PageDescriptor.TotalItemCount = op.TotalEntityCount;
                   }
                   else
                   {
                       MessageBox.Show(op.Error.ToString());
                   }
               },

               true);
        }

        private void OnQueryChanged(object sender, System.EventArgs e)
        {            
            this.LoadProducts();
        }

        #endregion
    }
}
Code Block
titleView
languagexml
<Intersoft:UXGridView
    AutoGenerateColumns="False" QueryOperation="Server"
    CanUserPage="True" PageSize="20"
    RowHeaderVisibility="Visible"
    IsBusy="{Binding IsBusy, Mode=TwoWay}"
    IsRefreshed="{Binding IsRefreshed, Mode=TwoWay}"
    ItemsSource="{Binding Products}"
    SortDescriptors="{Binding QueryDescriptor.SortDescriptors, Mode=TwoWay}"
    PageDescriptor="{Binding QueryDescriptor.PageDescriptor}"
    GroupFootersVisibility="Visible" GroupByBoxVisibility="Visible"
    CanUserAddRows="True"
    CanUserDeleteRows="True"
    CanUserEditRows="True"
    NewItem="{Binding NewProduct, Mode=TwoWay}"
    ValidateRowCommand="{Binding ValidateRowCommand}"
    InsertRowCommand="{Binding InsertRowCommand}"
    DeleteRowCommand="{Binding DeleteRowCommand}"
    PrepareNewRowCommand="{Binding PrepareNewRowCommand}"
    UpdateCellCommand="{Binding UpdateCellCommand}"
    UpdateRowCommand="{Binding UpdateRowCommand}"
    SaveChangesCommand="{Binding SaveChangesCommand}"
    RejectRowCommand="{Binding RejectRowCommand}"
    RejectChangesCommand="{Binding RejectChangesCommand}"
    HasChanges="{Binding HasChanges}">

    <Intersoft:UXGridView.GroupDescriptors>
        <Intersoft:UXGridViewGroupDescriptor PropertyName="CategoryID"/>
    </Intersoft:UXGridView.GroupDescriptors>

    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewTextColumn Header="Category ID" Binding="{Binding CategoryID}"/>
        <Intersoft:UXGridViewTextColumn Header="Product ID" Binding="{Binding ProductID}"
                                        IsReadOnly="True" Aggregate="Count"
										FooterFormatString="Count = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Product Name" Binding="{Binding ProductName}"/>
        <Intersoft:UXGridViewTextColumn Header="Units In Stock" Binding="{Binding UnitsInStock}" 
                                        Aggregate="Max" FooterFormatString="Max = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Unit Price" Binding="{Binding UnitPrice}" 
                                        Aggregate="Avg" FooterFormatString="Avg = {0:n2}"/>
        <Intersoft:UXGridViewTextColumn Header="Units On Order" Binding="{Binding UnitsOnOrder}"
                                        Aggregate="Min" FooterFormatString="Min = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Quantity Per Unit"
										Binding="{Binding QuantityPerUnit}"/>
    </Intersoft:UXGridView.Columns>
</Intersoft:UXGridView>

Working with EditEnterKeyAction Property, EditKeyGesture Property and EnterKeyAction Property

The keyboard gesture is determined by several properties such as EditKeyGesture, EnterKeyAction and EditEnterKeyAction. Each property has specific action that you can customize. The following list details the action of each property.

EditEnterKeyAction:

  • CommitAndMovetoNextRow
    Commit the changes made in the edited row and move to the next row.
  • ExitEdit
    Exit the editing of the selected cell.
  • MoveToNextEditableCell
    Move to next editable cell. (Will move to next row’s cell when it reach the end of the row).

EditKeyGesture:

  • F2
    Directly begin edit on the currently selected cell using F2 key.
  • AnyKeystroke
    Directly begin edit on the currently selected cell from any key stroke.

EnterKeyAction:

  • EnterEdit
    Directly begin edit on the selected cell using Enter key.
  • MoveToNextRow
    Move to next row (does not edit the cell).

Working with EditMouseGesture Property

The mouse gesture is determined by the EditMouseGesture property. The following options are available to customize the edit mouse gesture.

  • SingleClick
    Directly begin edit on the selected cell.
  • SecondClick
    Begin edit on the selected cell after the row is selected.
  • DoubleClick
    Directly begin edit on the selected cell when double click fires.

Working with EmptyRowsVisibility Property and NewRowPosition Property

The rows of UXGridView are determined by the number of items specified in items source. If the number of items in items source is less than the available screen estate it will show blank white space.

Setting the EmptyRowsVisibility to Visible enables UXGridView to show empty rows in this blank white space area, to give a better look and feel.

When CanUserAddRows is enabled and EmptyRowsVisibility is set to Visible, you can change the new row position to bottom through NewRowPosition property.

Modern note

Note that some features are not compatible when CanUserAddRows is enabled and EmptyRowsVisibility is set to Visible such as paging and grouping.

The following are several ways to enter edit mode when the new row position is set to Bottom:

  • Press down key on last row.
  • Press tab key on last column of the last row.
  • Double click on any empty rows when EnterNewRowOnClick is set to False.
  • Click on any on any empty rows when EnterNewRowOnClick is set to True.

Working with ExpandedItem Property

When you expand the row details using any of the methods described above, the ExpandedItem property will be set to the data context of the expanded row. You can use this property for more advanced user interaction, such as displaying a hierarchical grid view.

The following code shows how to create hierarchical grid view using row details.

Code Block
titleXAML
languagexml
<Intersoft:UXGridView AutoGenerateColumns="False"
                      ExpandedItem="{Binding ExpandedItem, Mode=TwoWay}"
                      EnableRowVirtualization="False"
                      ItemsSource="{Binding Employees}">
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewExpanderColumn/>
        <Intersoft:UXGridViewTextColumn Header="Employee ID"
			Binding="{Binding EmployeeID}"/>
        <Intersoft:UXGridViewTextColumn Header="First Name"
			Binding="{Binding FirstName}"/>
        <Intersoft:UXGridViewTextColumn Header="Last Name"
			Binding="{Binding LastName}"/>
        <Intersoft:UXGridViewTextColumn Header="Title"
			Binding="{Binding Title}"/>
    </Intersoft:UXGridView.Columns>
    <Intersoft:UXGridView.RowDetailsTemplate>
        <DataTemplate>
            <Border Margin="0,1,1,1" Background="#FFF7F7F7"
					BorderBrush="#FFAFAFAF" BorderThickness="0,1,0,0">
                <Grid>
                    <Border BorderBrush="#FFAFAFAF" BorderThickness="1,0,0,1"
						HorizontalAlignment="Left" Width="20" VerticalAlignment="Top"
						Height="24" Margin="10,0,0,0"/>
                    <Intersoft:UXGridView ItemsSource="{Binding Orders}"
							Margin="20,10,12,12" CanUserPage="True" PageSize="5"
							AutoGenerateColumns="False">
                        <Intersoft:UXGridView.Columns>
                            <Intersoft:UXGridViewTextColumn Header="Order ID"
								Binding="{Binding OrderID}"/>
                            <Intersoft:UXGridViewTextColumn Header="Order Date"
								Binding="{Binding OrderDate}"/>
                            <Intersoft:UXGridViewTextColumn Header="Required Date"
								Binding="{Binding RequiredDate}"/>
                            <Intersoft:UXGridViewTextColumn Header="Shipped Date"
								Binding="{Binding ShippedDate}"/>
                        </Intersoft:UXGridView.Columns>
                    </Intersoft:UXGridView>
                </Grid>
            </Border>
        </DataTemplate>
    </Intersoft:UXGridView.RowDetailsTemplate>
</Intersoft:UXGridView>

The above code shows how to define the row details to create hierarchical grid view and bind the ExpandedItem property to the ViewModel. In the ViewModel, you write a custom logic to load the child data whenever the ExpandedItem property is set.

Code Block
titleCS
languagec#
public object ExpandedItem
{
    get { return this._expandedItem; }
    set
    {
        if (this._expandedItem != value)
        {
            this._expandedItem = value;
            this.OnPropertyChanged("ExpandedItem");
            // this.LoadOrders(value);
        }
    }
}

Working with ExportCommand Property and ExportItems Property

By default, the exporting processes only the data available in the client. Therefore if you enable server paging, you might not be able to export the complete data correctly. To address this challenge, you can implement the ExportCommand in the ViewModel and provide the desired data to the ExportItems property.

The following code shows you how to bind ExportItems and ExportCommand in the ViewModel and supply the data to export.

Code Block
titleView Model
languagec#
using System.Collections;
using System.ServiceModel.DomainServices.Client;
using System.Windows;
using HowToSamples.Web;
using Intersoft.Client.Data.ComponentModel;
using Intersoft.Client.Data.Provider.Ria;
using Intersoft.Client.Framework.Input;

namespace HowToSamples.ViewModels
{
    public class ExportingViewModel: ViewModelBase
    {
        public ExportingViewModel()
        {
            this.Manager = new NorthwindDomainContext();
            this.CanUserExport = true;
            this.QueryDescriptor = new QueryDescriptor();
            this.ExportCommand = new DelegateCommand(ExecuteExportCommand);
        }

        private bool _canUserExport;
        private IEnumerable _exportItems;
        private IEnumerable _products;
        private QueryDescriptor _queryDescriptor;
       
        private NorthwindDomainContext Manager { get; set; }

        public bool CanUserExport
        {
            get { return this._canUserExport; }
            set
            {
                if (this._canUserExport != value)
                {
                    this._canUserExport = value;
                    this.OnPropertyChanged("CanUserExport");
                }
            }
        }

        public DelegateCommand ExportCommand { get; set; }

        public IEnumerable ExportItems
        {
            get { return this._exportItems; }
            set
            {
                if (this._exportItems != value)
                {
                    this._exportItems = value;
                    this.OnPropertyChanged("ExportItems");
                }
            }
        }

        public IEnumerable Products
        {
            get { return this._products; }
            set
            {
                if (this._products != value)
                {
                    this._products = value;
                    this.OnPropertyChanged("Products");
                }
            }
        }

        public QueryDescriptor QueryDescriptor
        {
            get
            {
                return this._queryDescriptor;
            }
            set
            {
                if (this._queryDescriptor != value)
                {
                    if (this._queryDescriptor != null)
                        this._queryDescriptor.QueryChanged -=
							new System.EventHandler(OnQueryChanged);
                    this._queryDescriptor = value;
                    this._queryDescriptor.QueryChanged += new System.EventHandler(OnQueryChanged);

                    this.OnPropertyChanged("QueryDescriptor");
                }
            }
        }

        public void ExecuteExportCommand(object parameter)
        {
            Intersoft.Client.Data.ComponentModel.QueryDescriptor queryDescriptor =
				this.QueryDescriptor.CreateCopy(true, true, false);
					// copy the query descriptor, but exclude the page descriptor
            var query = this.Manager.GetProductsQuery().
				OrderBy(p => p.ProductID).Parse(queryDescriptor);

            this.Manager.Load(
               query,
               op =>
               {
                   if (op.IsComplete)
                   {
                       Intersoft.Client.Data.ComponentModel.PagedCollectionView current =
							this.Products as Intersoft.Client.Data.ComponentModel.PagedCollectionView;
                       Intersoft.Client.Data.ComponentModel.PagedCollectionView exportedItems =
							new Intersoft.Client.Data.ComponentModel.PagedCollectionView(op.Entities);

                       exportedItems.CopyDefinitionsFrom(current, true, false, false, false);
                       this.ExportItems = exportedItems;
							// supply the export process with correct collection.
                   }
                   else
                   {
                       MessageBox.Show(op.Error.ToString());
                   }
               },

               true);            
        }

        public virtual void LoadProducts()
        {
            if (Intersoft.Client.Framework.ISControl.IsInDesignModeStatic)
                return;

            var query = this.Manager.GetProductsQuery().
							OrderBy(p => p.ProductID).Parse(this.QueryDescriptor);
            query.IncludeTotalCount = true;

            this.Manager.Load(
               query,
               op =>
               {
                   if (op.IsComplete)
                   {
                       this.Products = new Intersoft.Client.Data.
											ComponentModel.PagedCollectionView(op.Entities);
                       this.QueryDescriptor.PageDescriptor.TotalItemCount = op.TotalEntityCount;
                   }
                   else
                   {
                       MessageBox.Show(op.Error.ToString());
                   }
               },

               true);
        }

        private void OnQueryChanged(object sender, System.EventArgs e)
        {            
            this.LoadProducts();
        }
    }
}
Code Block
titleView
languagexml
<UserControl x:Class="HowToSamples.Exporting"
    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"
    xmlns:Intersoft="http://intersoft.clientui.com/schemas"
    xmlns:ViewModels="clr-namespace:HowToSamples.ViewModels"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.DataContext>
            <ViewModels:ExportingViewModel/>
        </Grid.DataContext>
        <Intersoft:UXGridView AutoGenerateColumns="False" QueryOperation="Server"
                              CanUserPage="True" PageSize="20"                              
                              ItemsSource="{Binding Products}" 
                              SortDescriptors="{Binding QueryDescriptor.
													SortDescriptors, Mode=TwoWay}"
                              PageDescriptor="{Binding QueryDescriptor.PageDescriptor}"
                                                            CanUserExport="{Binding CanUserExport}"
                                                            ExportCommand="{Binding ExportCommand}"
                              ExportItems="{Binding ExportItems}">

        <Intersoft:UXGridView.GroupDescriptors>
            <Intersoft:UXGridViewGroupDescriptor PropertyName="CategoryID"/>
        </Intersoft:UXGridView.GroupDescriptors>

        <Intersoft:UXGridView.Columns>
            <Intersoft:UXGridViewTextColumn Header="Category ID"
				Binding="{Binding CategoryID}"/>
            <Intersoft:UXGridViewTextColumn Header="Product ID"
				Binding="{Binding ProductID}" Aggregate="Count"
				FooterFormatString="Count = {0}"/>
            <Intersoft:UXGridViewTextColumn Header="Product Name"
				Binding="{Binding ProductName}"/>
            <Intersoft:UXGridViewTextColumn Header="Units In Stock"
				Binding="{Binding UnitsInStock}" Aggregate="Max"
				FooterFormatString="Max = {0}"/>
            <Intersoft:UXGridViewTextColumn Header="Unit Price"
				Binding="{Binding UnitPrice}" Aggregate="Avg"
				FooterFormatString="Avg = {0:n2}"/>
            <Intersoft:UXGridViewTextColumn Header="Units On Order"
				Binding="{Binding UnitsOnOrder}" Aggregate="Min"
				FooterFormatString="Min = {0}"/>
            <Intersoft:UXGridViewTextColumn Header="Quantity Per Unit"
				Binding="{Binding QuantityPerUnit}"/>
        </Intersoft:UXGridView.Columns>

        </Intersoft:UXGridView>
    </Grid>
</UserControl>

Working with FrozenColumnCount Property

Code Block
titleXAML
languagexml
<Intersoft:UXGridView ItemsSource="{Binding Products}" FrozenColumnCount="2"/>

Working with GroupByBoxVisibility Property

Alternatively, you can also drag the header of a column to the group box. The group box's visibility can also be toggled from the column's context menu. It can be displayed initially by setting the GroupByBoxVisibility to Visible.

Working with GroupDescriptors Property

Code Block
titleXAML
languagexml
<Intersoft:UXGridView AutoGenerateColumns="False" ItemsSource="{Binding Products}">
	<Intersoft:UXGridView.GroupDescriptors>
		<Intersoft:UXGridViewGroupDescriptor PropertyName="CategoryID" SortDirection="Descending"/
	</Intersoft:UXGridView.GroupDescriptors>                           
</Intersoft:UXGridView>

Working with GroupFootersVisibility Property

Code Block
titleXAML
languagexml
<Intersoft:UXGridView GroupFooterVisibility="Visible" GroupByBoxVisibility="Visible"
		CanUserGroupColumns="True" ItemsSource="{Binding Products}" >
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewTextColumn Header="Category ID"
			Binding="{Binding CategoryID}"/>
        <Intersoft:UXGridViewTextColumn Header="Product ID" Binding="{Binding ProductID}"
			Aggregate="Count" FooterFormatString="Count = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Product Name" Binding="{Binding ProductName}"/>
        <Intersoft:UXGridViewTextColumn Header="Units In Stock" Binding="{Binding UnitsInStock}"
			Aggregate="Max" FooterFormatString="Max = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Unit Price" Binding="{Binding UnitPrice}"
			Aggregate="Avg" FooterFormatString="Avg = {0:n2}"/>
        <Intersoft:UXGridViewTextColumn Header="Units On Order" Binding="{Binding UnitsOnOrder}"
			Aggregate="Min" FooterFormatString="Min = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Quantity Per Unit"
			Binding="{Binding QuantityPerUnit}"/>
    </Intersoft:UXGridView.Columns>
</Intersoft:UXGridView>
You can also set multiple values on the Aggregate property such as shown in the following example.
Code Block
titleXAML
languagexml
<Intersoft:UXGridViewTextColumn Header="Unit Price" Binding="{Binding UnitPrice}"
	Aggregate="Avg,Max,Min" FooterFormatString="Avg = {0} | Max = {0} | Min = {0}"/>

Working with IsReadOnlyBinding Property

The following code shows how to implement the IsReadOnlyBinding to achieve the above scenario.

Code Block
titleXAML
languagexml
<Intersoft:UXGridView IsReadOnlyBinding="{Binding Discontinued}">
    <Intersoft:UXGridView.Columns>
        <Intersoft:UXGridViewCheckBoxColumn Header="Discontinued"
			Binding="{Binding Discontinued}"/>
        <Intersoft:UXGridViewTextColumn Header="Category ID"
			Binding="{Binding CategoryID}"
			IsReadOnlyBinding="{Binding Discontinued}"/>
        <Intersoft:UXGridViewTextColumn Header="Product ID"
			Binding="{Binding ProductID}" IsReadOnly="True"
			Aggregate="Count" FooterFormatString="Count = {0}"/>
        <Intersoft:UXGridViewTextColumn Header="Product Name"
			Binding="{Binding ProductName}"/>                    
    </Intersoft:UXGridView.Columns>
</Intersoft:UXGridView>

Working with ScrollIndicatorBinding Property

The following code shows how to use the ScrollIndicatorBinding to customize the data display in the scroll indicator element.

Code Block
titleXAML
languagexml
<Intersoft:UXGridView ItemsSource="{Binding Products}" 
                      HorizontalScrollMode="Deferred"
                      VerticalScrollMode="Deferred"
                      ScrollIndicatorBinding="{Binding ProductName}">
    <Intersoft:UXGridView.Columns>                    
        <Intersoft:UXGridViewTextColumn Header="Category ID"
			Binding="{Binding CategoryID}"/>
        <Intersoft:UXGridViewTextColumn Header="Product ID"
			Binding="{Binding ProductID}"/>
        <Intersoft:UXGridViewTextColumn Header="Product Name"
			Binding="{Binding ProductName}"/>
        <Intersoft:UXGridViewTextColumn Header="Unit Price"
			Binding="{Binding UnitPrice}"/>
        <Intersoft:UXGridViewTextColumn Header="Units In Stock"
			Binding="{Binding UnitsInStock}"/>
        <Intersoft:UXGridViewTextColumn Header="Units On Order"
			Binding="{Binding UnitsOnOrder}"/>
        <Intersoft:UXGridViewTextColumn Header="Quantity Per Unit"
			Binding="{Binding QuantityPerUnit}"/>
    </Intersoft:UXGridView.Columns>
</Intersoft:UXGridView>

Working with SelectedItem Property, SelectedItems Property, SelectionMode Property and SelectionUnit Property

UXGridView has three type of SelectionMode that you can choose from.

  • Single
    Only one item can be selected.
  • Multiple
    Allow multiple item to be selected.
  • Extended
    Allow multiple item to be selected. You need to hold Shift and / or Ctrl modifier to perform the multiple selection.

When a row is selected, the SelectedItem and SelectedItems property will be automatically synchronized. You can bind these properties to your ViewModel to capture the currently selected items.

Furthermore, you can also customize the SelectionUnit to one of the possible three values: Row, Cell or RowAndCell.

Working with SortDescriptions Property

The following example shows how to implement predefined sorting with client data operation.

Code Block
titleXAML
languagexml
xmlns:Intersoft="http://intersoft.clientui.com/schemas"
xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=System.Windows"

<Intersoft:UXGridView AutoGenerateColumns="False" ItemsSource="{Binding Products}">
    <Intersoft:UXGridView.SortDescriptions>
        <ComponentModel:SortDescription PropertyName="ProductName" Direction="Ascending"/>
    </Intersoft:UXGridView.SortDescriptions>                               
</Intersoft:UXGridView>

...