Welcome to the Xceed Community | Help
Community Search  
More Search Options

DON'T PANIC!

Sneak Peek at Version 3.2!

So version 3.2 is compiled and ready to be released in mid-June! It has been a hectic past couple of weeks trying to get everything done and we are all very happy with the end result. I know that many of you have been anxiously waiting for the 3.2 release so I though I would give you a little preview to whet your appetite. So what exactly is included in version 3.2? Good question! It looks something like this:

  • Custom distinct values (e.g., "less than 10") in the auto-filter control
  • Filter row that allows end users to provide filter criteria at run time.
  • Built-in support for Entity Framework
  • Improvements to the datagrid's data virtualization capabilities including grouping and support for data sources implementing IQueryable (LINQ)
  • Automatic detection of foreign key constraints and enumerations
  • Support for unbound columns and data
  • Enable and disable grouping and sorting on a per-column basis
  • and a couple little extras that you will discover!

One feature that clients have often inquired about is custom distinct values. Or, in other words, being able to provide "Excel-like" filter criteria such as "less than x" and "greater than x" in the auto-filter drop down. With version 3.2, it is possible to do so and even more. How? Easy! Just use the QueryDistinctValue event exposed by each DataGridItemProperty and return the desired distinct value. For example, in the code below, I provide distinct values that will filter date/time values according to the year (by default, all dates would have been displayed in the auto-filter control) and I also provide value ranges where, by default, all values would have been displayed in the drop down.

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
  <Grid.Resources>
     <xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
                          Source="{Binding Source={x:Static Application.Current}, Path=Orders}"
                          AutoFilterMode="And"
                          DefaultCalculateDistinctValues="False">
        <xcdg:DataGridCollectionViewSource.ItemProperties>
          <xcdg:DataGridItemProperty Name="OrderDate"
                          QueryDistinctValue="DataGridItemProperty_QueryDistinctValue_Date"
                          CalculateDistinctValues="True"/>
          <xcdg:DataGridItemProperty Name="RequiredDate"
                          QueryDistinctValue="DataGridItemProperty_QueryDistinctValue_Date"
                          CalculateDistinctValues="True" />
          <xcdg:DataGridItemProperty Name="ShippedDate"
                          QueryDistinctValue="DataGridItemProperty_QueryDistinctValue_Date"
                          CalculateDistinctValues="True" />
          <xcdg:DataGridItemProperty Name="Freight"
                          QueryDistinctValue="DataGridItemProperty_QueryDistinctValue_Range"
                          CalculateDistinctValues="True" />
        </xcdg:DataGridCollectionViewSource.ItemProperties>
     </xcdg:DataGridCollectionViewSource>
  
  </Grid.Resources>
  <xcdg:DataGridControl x:Name="OrdersGrid"
                        ItemsSource="{Binding Source={StaticResource cvs_orders}}"/>
</Grid>

private void DataGridItemProperty_QueryDistinctValue_Date( object sender, QueryDistinctValueEventArgs e)
{
 if( e.DataSourceValue is DateTime )
 {
   e.DistinctValue = ( ( DateTime )e.DataSourceValue ).ToString( "MMMM" );
 }
}

private void DataGridItemProperty_QueryDistinctValue_Range(object sender,QueryDistinctValueEventArgs e)
{
 if( e.DataSourceValue is decimal )
 {
   decimal value = ( decimal )e.DataSourceValue;
   if( value <= 100 )
   {
     e.DistinctValue = "0 - 100";
   }
   else if( value > 100 && value <= 500 )
   {
     e.DistinctValue = "101 - 500";
   }
   else
   {
     e.DistinctValue = "500+";
   }
 }
}

Beautifully simple Smile

Version 3.2 also adds the ability for end users to provide filtering criteria at run time through the use of a "filter row", which can be added to the fixed or scrolling header and footer sections of a grid, group, or detail. In addition to supporting relation filters such as "contains", "equal to", and "greater than", among others, the filter row also supports conditional filters such as "AND" and "NOT", which allow a column to be filtered by more than one filter criterion.

 

 

 

 

 

 

Another sought-after feature is built-in support for Entity Framework. Although it was possible to use Entity Framework with the previous version of the grid, version 3.2 makes this a whole lot simpler by automatically detecting Entity collections (EntityCollection<TEntity>) and displaying their content as details. In the case where the reference to related Entity objects are not loaded, the QueryDetails event, exposed by the EntityDetailDescription class, can be handled to provide details for a data item.  For example, in the code snippet below, a query that will return the appropriate details for a parent item is executed and the Handled property set to true to indicate that the event was handled.

private void EntityDetailDescription_QueryDetails( object sender, QueryEntityDetailsEventArgs e )
{
    Customer customer = ( Customer )e.ParentItem;

    // Since EntityFramework doesn't load automatically references to
    // other objects, we build a query that will include those objects.
    // We start from the base query but we could have added restrictions
    // to the query.
    ObjectQuery<Order> query = customer.Orders.CreateSourceQuery();
    customer.Orders.Attach( query.Include( "Employee" ).Include( "Shipper" ) );
    e.Handled = true;
}

A feature that was lacking in the 3.1 implementation of data virtualization was grouping support. With version 3.2, this limitation is a thing of the past :) Now, unlike the other features I just mentioned, grouping in a virtualized collection view is not something for the feint of heart! But, if you know what data you are dealing with and with the help of the Data Virtualization sample, which provides a detailed example of how to implement grouping support, you should be up and grouping in no time. If not, contact our support department, that's what they are there for Wink

For those of you who are already using the virtualized collection view provided with Xceed DataGrid for WPF, you may be happy to learn that version 3.2 also provides built-in support for IQueryable data sources through the DataGridVirtualizingQueryableCollectionView and its XAML-proxy the DataGridVirtualizingQueryableCollectionViewSource, which, by the way, earned its developer the "longest class name" award!

A feature that has been implemented in version 3.2 whose lack caused a lot of frustration in previous versions, is automatic detection and support for foreign keys and enumerations. In previous versions, in order to display foreign key constraints, you had to write a lot of code, which, quite honestly, was time consuming and annoying to implement. In version 3.2, all that is a thing of the past (although you can still use your code if you want!). By default, foreign key constraints defined by a DataTable or DataView used as a data source, as well as enums, can be automatically detected and displayed and edited, through a ComboBox, as the corresponding value rather than its key. If you are dealing with a different type of source or would like to provide custom key/value mappings, you can do that too. Although it is recommended to always bind the grid to its data by-proxy of a DataGridCollectionView[Source] or any other data-grid collection view, it is not obligatory. When binding a grid directly to a source that contains foreign key constraints or enums and data-grid collection view is not used, it is still possible to display the value rather than the key of the constraints and enums; however, they must be defined manually by providing the appropriate foreign key configurations, and a ForeignKeyConverter must be used in order to convert keys to values and back (see ReportsTo column in Example ).

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
  <Grid.Resources>
     <local:OccupationToStringConverter x:Key="occupationToStringConverter" />
     <local:PersonForeignKeyConverter x:Key="personForeignKeyConverter" />

     <ObjectDataProvider x:Key="occupationValues"
                         MethodName="GetValues"
                         ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
           <x:Type TypeName="local:Occupation" />
        </ObjectDataProvider.MethodParameters>
     </ObjectDataProvider>

  </Grid.Resources>    
 
  <xcdg:DataGridControl x:Name="PersonsGrid"
                        ItemsSource="{Binding Source={x:Static Application.Current}, Path=Persons}">

    <xcdg:DataGridControl.Columns>
       <xcdg:Column FieldName="Occupation">
          <xcdg:Column.CellContentTemplate>
             <DataTemplate>
                <TextBlock Text="{Binding Converter={StaticResource occupationToStringConverter}}" />
             </DataTemplate>
          </xcdg:Column.CellContentTemplate>
          <xcdg:Column.ForeignKeyConfiguration>
            <xcdg:ForeignKeyConfiguration ItemsSource="{Binding Source={StaticResource occupationValues}}"/>
          </xcdg:Column.ForeignKeyConfiguration>
       </xcdg:Column>
       <xcdg:Column FieldName="ReportsTo">
          <xcdg:Column.CellContentTemplate>
             <DataTemplate>
                <StackPanel Orientation="Horizontal">
                   <TextBlock Text="{Binding FirstName}" />
                   <TextBlock Text=" " />
                   <TextBlock Text="{Binding LastName}" />
                </StackPanel>
             </DataTemplate>
          </xcdg:Column.CellContentTemplate>
          <xcdg:Column.ForeignKeyConfiguration>
            <xcdg:ForeignKeyConfiguration ItemsSource="{Binding Source={x:Static Application.Current}, Path=Persons}"
                                           ForeignKeyConverter="{StaticResource personForeignKeyConverter}"
                                           ValuePath="PersonID"/>
          </xcdg:Column.ForeignKeyConfiguration>
       </xcdg:Column>
    </xcdg:DataGridControl.Columns>
  </xcdg:DataGridControl>
</Grid>

Another feature that was often requested is support for unbound columns and data. Now, you may be wondering why I am referring to unbound columns AND unbound data. Good question. Initially, this feature was known as unbound columns; however, after it was implemented, we realized that  unbound columns and unbound data were two different things. Let me try to explain... "Unbound data" is data that can be "appended" to a data item through the use of unbound item properties, which are represented by the DataGridUnboundItemProperty class. Unlike "unbound columns", which can be used to display non-data related information such as a label or controls that allow some sort of action to be carried out, unbound item properties can be used to provide additional data, such as calculated columns. If you are scratching your head at this point, don't worry, it is a lot simpler than it seems! Let me demonstrate:

Unbound Data

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
  <Grid.Resources>
     <xcdg:DataGridCollectionViewSource x:Key="cvs_products"
                                        Source="{Binding Source={x:Static Application.Current}, Path=Products}">

        <xcdg:DataGridCollectionViewSource.ItemProperties>

          <xcdg:DataGridUnboundItemProperty Name="TotalUnitsValue"
                                            DataType="{x:Type sys:Double}"
                                            QueryValue="DataGridUnboundItemProperty_QueryValue" />
        </xcdg:DataGridCollectionViewSource.ItemProperties>
     </xcdg:DataGridCollectionViewSource>

     <local:CurrencyConverter x:Key="currencyConverter" />

  </Grid.Resources>
  <xcdg:DataGridControl x:Name="OrdersGrid"
                        ItemsSource="{Binding Source={StaticResource cvs_products}}">
     <xcdg:DataGridControl.Columns>
        <xcdg:Column FieldName="TotalUnitsValue"
                     Title="Total Inventory">
           <xcdg:Column.CellContentTemplate>
              <DataTemplate>
                 <TextBlock Text="{Binding Converter={StaticResource currencyConverter}}" />
              </DataTemplate>
           </xcdg:Column.CellContentTemplate>
        </xcdg:Column>

        <xcdg:Column FieldName="Photo"
                     Visible="False" />           
     </xcdg:DataGridControl.Columns>
  </xcdg:DataGridControl>
</Grid>

private void DataGridUnboundItemProperty_QueryValue( object sender, DataGridItemPropertyQueryValueEventArgs e )
{
 System.Data.DataRowView row = e.Item as System.Data.DataRowView;
 if( row != null )
 {
   if( row[ "UnitsInStock" ] != DBNull.Value )
   {
     e.Value = ( double )( ( short )row[ "UnitsInStock" ] * ( decimal )row[ "UnitPrice" ] );
   }
 }
}

Unbound Columns

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
  <Grid.Resources>
     <xcdg:DataGridCollectionViewSource x:Key="cvs_products"
                                        Source="{Binding Source={x:Static Application.Current}, Path=Products}" />

  </Grid.Resources>
  <xcdg:DataGridControl x:Name="OrdersGrid"
                        ItemsSource="{Binding Source={StaticResource cvs_products}}">
     <xcdg:DataGridControl.Columns>

       <xcdg:UnboundColumn FieldName="EditRowColumn"
                           Width="30"
                           MinWidth="30"
                           MaxWidth="30">
          <xcdg:UnboundColumn.CellContentTemplate>
             <DataTemplate>
                <Button Click="Button_Click"
                        Content="..." />
             </DataTemplate>
          </xcdg:UnboundColumn.CellContentTemplate>
       </xcdg:UnboundColumn>
        <xcdg:Column FieldName="Photo"
                     Visible="False" />
     </xcdg:DataGridControl.Columns>
  </xcdg:DataGridControl>
</Grid>

private void Button_Click( object sender, RoutedEventArgs e )
{
  Cell cell = Cell.FindFromChild( sender as DependencyObject );

  ProductsEditorWindow editor = new ProductsEditorWindow( DataGridControl.GetParentDataGridControl( cell ).GetItemFromContainer( cell.ParentRow ) as DataRowView );

  editor.ShowDialog();
}

Notice that although both the UnboundColumn and DataGridUnboundItemProperty classes both use the term "unbound" they are not meant to be used together. Meaning that an unbound item property's corresponding column is a Column and not an Unbound column.

A little feature, but one that has been often requested, is to enable and disable grouping and sorting on a per-column basis. If you are one of those who requested this feature, version 3.2 is what you need!

So there you go! Version 3.2 is scheduled to be released on June 15th. So mark the date on your calendar!

Any questions or comments? Feel free to post them in the comments section below.

Published June 1, 2009 10:38 AM by Jenny

Comments

 

Technocars said:

hi,

what about disable enable filtering and moving for specific columns?

June 2, 2009 6:28 AM
 

Jenny said:

You can also display the auto-filter drop down per column (although that was possible in previous version as well).  If you don't want a column to be moved, you can fix it using a combination of its VisiblePosition property and the FixedColumnCount property.

June 2, 2009 7:59 AM
 

Jenny said:

"You can also display the auto-filter drop down per column"

I meant enable/disable!

June 2, 2009 8:03 AM
 

David said:

What happened to the "Built-in search with end-user UI"  that was supposed to be in version 3.2?

June 2, 2009 1:16 PM
 

Odi [Xceed] said:

It's been moved for development during Q4 2009, best I can say at this point is end-of-the year or January 2010... The roadmap post in the forums has the latest news.

Sorry that we had to postpone that feature, I really liked it and wanted it too, but there was more demand for other features first.

June 2, 2009 1:39 PM
 

Technocars said:

ok thx Jenny,

what about the column resizing (enable/disable column resizing), and column grouping (column can be dragged into the group by area) i'm mean enable disable it for a specific column

June 3, 2009 8:25 AM
 

Technocars said:

sorry i mentioned groupping by mistake. i know it is covered in the new release

June 3, 2009 8:31 AM
 

Jenny said:

To prevent a column from being resized, you can set its MinWidth and MaxWidth properties to the same value.

June 3, 2009 10:19 AM
 

Luca said:

what about an out of the box implementation of the event SelectedIndexChanged?

June 6, 2009 12:54 PM
 

Jenny said:

Yes. Version 3.2 exposes a SelectionChanged event on the DataGridControl class.

June 8, 2009 9:20 AM
 

Flor said:

Are UnboundColumn and DataGridUnboundItemProperty not allowed to be used together? What if I want a certain data that can be "appended" to a data item be displayed through or even just related to an UnboundColumn?

June 18, 2009 2:03 PM
 

Jenny said:

It's not a question that they can't be used together, it's more of a question that they do not have the same role. A DataGridUnboundItemProperty represents data that is "appended" to the original data item and will have its corresponding column in the Columns collection; however, it will be a Column instance rather than an UnboundColumn instance. An UnboundColumn represents and should be used to represent "static" data or controls such as a label or a button.

Is there a reason why you want to use an UnboundColumn with a DataGridUnboundItemProperty?

June 18, 2009 4:04 PM
 

Flor said:

Thanks Jenny

Basically, I wanted to have a column with buttons but when a button is selected, I wanted to have access to the data item that was bound to that row. Not sure if that is what the given example is demonstrating. Not sure what a ProductsEditorWindow is.

June 22, 2009 10:21 AM
 

Jenny said:

The ProductsEditorWindow is a simple window that allows a DataRowView to be edited when one of the buttons, which are defined by the UnboundColumn, is clicked.

In the Click event, I retrieve the appropriate DataRowView and pass it to the ProductsEditorWindow:

private void Button_Click( object sender, RoutedEventArgs e )

{

 Cell cell = Cell.FindFromChild( sender as DependencyObject );

 ProductsEditorWindow editor = new ProductsEditorWindow( DataGridControl.GetParentDataGridControl( cell ).GetItemFromContainer( cell.ParentRow ) as DataRowView );

 editor.ShowDialog();

}  

Here is the code-behind for the ProductsEditorWindow that simply sets the DataRowView as the DataContext in the ctor (the elements in XAML are bound to the DataContext AKA DataRowView and its properties) and calls its EndEdit/CancelEdit methods to commit or reject modifications when the save or cancel buttons are clicked, respectively:

public partial class ProductsEditorWindow: Window

{

 public ProductsEditorWindow( DataRowView row )

 {

   InitializeComponent();

   this.DataContext = row;      

 }

 private void SaveButton_Click( object sender, RoutedEventArgs e )

 {

   ( ( DataRowView )this.DataContext ).EndEdit();

   this.Close();

 }

 private void CancelButton_Click( object sender, RoutedEventArgs e )

 {

   ( ( DataRowView )this.DataContext ).CancelEdit();

   this.Close();

 }

}

Hope this helps clear things up!

June 22, 2009 10:32 AM
 

Flor said:

Thanks for the explanation

Two questions:

-What do I need for the ProductsEditorWindow. I am using 3.2 but I couldn't access it, not sure if I need some type of using statement?

-Since an Unbound Column has static data, would I be able to access this static data in the code behind? For example, if I have an Unbound Column with buttons, I would like to be able to do something to the button such as enable/disable or change its color etc whenever my code signals. For example, my buttons in the Unbound Column are disabled, I have received some data so now it is okay to enable a button(just one button not all buttons in the column because the data received pertains to the info in one row). I was able to do this on the cell itself but not on the button which sits on the cell.

June 25, 2009 3:53 PM
 

Jenny said:

The ProductsEditorWindow is a Window that I created for example purposes only. It is not part of Xceed DataGrid for WPF. That said, in my previous reply you have the code-behind of the ProductsEditorWindow and here is the XAML portion of it:

<Window x:Class="Xceed.Wpf.Documentation.ProductsEditorWindow"

       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

       Title="ProductsEditorWindow"

       Height="300"

       Width="300">

  <Grid>

     <Grid.RowDefinitions>

        <RowDefinition />

        <RowDefinition />

        <RowDefinition />

        <RowDefinition />

        <RowDefinition />

        <RowDefinition />

        <RowDefinition />

        <RowDefinition />

     </Grid.RowDefinitions>

     <Grid.ColumnDefinitions>

        <ColumnDefinition Width="*" />

        <ColumnDefinition Width="*" />

     </Grid.ColumnDefinitions>

     <Label Content="Product Name: "

            Grid.Row="0"

            Grid.Column="0" />

     <TextBox Text="{Binding Path=ProductName}"

              Grid.Row="0"

              Grid.Column="1" />

     <Label Content="Quantity Per Unit: "

            Grid.Row="1"

            Grid.Column="0" />

     <TextBox Text="{Binding Path=QuantityPerUnit}"

              Grid.Row="1"

              Grid.Column="1" />

     <Label Content="Unit Price: "

            Grid.Row="2"

            Grid.Column="0" />

     <TextBox Text="{Binding Path=UnitPrice}"

              Grid.Row="2"

              Grid.Column="1" />

     <Label Content="Units In Stock: "

            Grid.Row="3"

            Grid.Column="0" />

     <TextBox Text="{Binding Path=UnitsInStock}"

              Grid.Row="3"

              Grid.Column="1" />

     <Label Content="UnitsOnOrder: "

            Grid.Row="4"

            Grid.Column="0" />

     <TextBox Text="{Binding Path=UnitsOnOrder}"

              Grid.Row="4"

              Grid.Column="1" />

     <Label Content="Reorder Level: "

            Grid.Row="5"

            Grid.Column="0" />

     <TextBox Text="{Binding Path=ReorderLevel}"

              Grid.Row="5"

              Grid.Column="1" />

     <Label Content="Discontinued: "

            Grid.Row="6"

            Grid.Column="0" />

     <CheckBox IsChecked="{Binding Path=Discontinued}"

               Grid.Row="6"

               Grid.Column="1" />

     <Button Content="Save"

             Click="SaveButton_Click"

             Grid.Row="7"

             Grid.Column="0" />

     <Button Content="Cancel"

             Click="CancelButton_Click"

             Grid.Row="7"

             Grid.Column="1"/>

  </Grid>

</Window>

As for your second question, you can access the parent cell of the control or data displayed in the cell through the Cell.FindFromChild method, which is demonstrated in my previous reply (Button_Click event).

June 26, 2009 11:17 AM
Anonymous comments are disabled
Contact | Site Map | Reviews | Legal Terms of Use | Trademarks | Privacy Statement Copyright 2008 Xceed Software Inc.