Intersoft ClientUI Documentation
UXQueryBuilder

UXQueryBuilder is an advanced data filtering control for Silverlight and WPF that allows user to visually build complex filter definitions. Designed with a sleek user interface, UXQueryBuilder lets users easily understand complex condition hierarchy and allow users to intuitively interact with each condition. Comes with full MVVM support and integration with all ClientUI data controls, adding the query builder functionality to your business applications is truly a breeze.

Understanding UXQueryBuilder

The QueryDescriptor class provides powerful and flexible creation of data filters through the use of CompositeFilterDescriptor or CompositeFilterDescription. Consider the following code that represents a composite nested filters:

C#
Copy Code
CompositeFilterDescriptor composite = new CompositeFilterDescriptor();
composite.FilterDescriptors.Add(new FilterDescriptor { PropertyName = "Garage", Value = true, Operator = FilterOperator.IsEqualTo });
composite.FilterDescriptors.Add(new FilterDescriptor { PropertyName = "Baths", Value = 2, Operator = FilterOperator.IsGreaterThan });
composite.LogicalOperator = FilterCompositionLogicalOperator.And;

CompositeFilterDescriptor outerComposite = new CompositeFilterDescriptor();
outerComposite.FilterDescriptors.Add(new FilterDescriptor { PropertyName = "Price", Value=35000, Operator = FilterOperator.IsLessThan});
outerComposite.FilterDescriptors.Add(new FilterDescriptor { PropertyName="YearBuilt", Value = new DateTime(1988,12,13), Operator = FilterOperator.IsGreaterThan});
outerComposite.FilterDescriptors.Add(composite);
outerComposite.LogicalOperator = FilterCompositionLogicalOperator.And;

As the hierarchy of composite filters gets more complex, it will be significantly more difficult to maintain the codes or manipulate the composite filters in an intuitive manner during runtime. Compare the same code used to produce the visual representation of the filters using UXQueryBuilder:

UXQueryBuilder provides graphical representation and ultimate ease-of-use to interact with complex filters through a sleek and intuitive user interface. UXQueryBuilder serves as a client-side control that translates complex queries in the form of a visual representation and sends the designated filters to QueryDescriptor without writing any code. UXQueryBuilder is a fully customizable query editor which supports industry-standard WCF RIA and DevForce data sources.

Using UXQueryBuilder

This section provides a quick start on how to use UXQueryBulider in the simplest scenario. To learn more about the user interface of UXQueryBuilder, see UI Highlights section below.

Server and Client Side Operation

UXQueryBuilder is designed to be able to handle both server and client side operations. The server side operation takes advantage of QueryDescriptor class while the client side operation takes advantage of the PagedCollectionView.

For more information on how to configure UXQueryBuilder to handle server-side operation, see How-to: Use UXQueryBuilder for server side operation. Also, to configure UXQueryBuilder to handle client-side operation, see How-to: Use UXQueryBuilder for client side operation.

Customizing UXQueryBuilder

There are three main parts in UXQueryBuilder: PropertyName, FilterOperator, and Value. The following section explains in details about the approaches used to customize each of these parts and suit UXQueryBuilder to your business model.

Listing Properties

Listing properties in property name in UXQueryBuilder can be done in two ways: using ObjectType or FilterPropertiesSource.

Using ObjectType

ObjectType provides a way to list properties by specifying the type of the model directly into UXQueryBuilder .

Take the following object model as an example.

Order_Detail.cs
Copy Code
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Intersoft.Client.Data.ComponentModel;

namespace ClientUI._2012R2.Preview.DomainModel
{
    public partial class Order_Detail
    {
        public class Order_DetailFilterMetadata
        {
            [Display(Name = "Order ID")]
            public int OrderID { get; set; }

            [Display(Name = "Product ID")]
            public int ProductID { get; set; }

            [Display(Name = "UnitPrice")]
            public decimal UnitPrice { get; set; }

            [Display(Name = "Quantity")]
            public short Quantity { get; set; }

            [Display(Name = "Discount")]
            public float Discount { get; set; }
        }
    }
}       

The DisplayAttribute determines the display name of the property. If DisplayAttribute does not exist, then the property name will be listed as display name. Bind the object model to the ObjectType property of UXQueryBuilder. The ObjectType takes the Type property of the object model.

XAML
Copy Code
<Intersoft:UXQueryBuilder ObjectType="{Binding ObjectType}" FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server" />

Using FilterPropertiesSource

You can also achieve the same result by binding an IEnumerable<CustomClass> to FilterPropertiesSource property of UXQueryBuilder in the view model and providing the respective member path in the view.

C#
Copy Code
this._orderDetailsFilterMemberData = new ObservableCollection<FilterMemberData>
{ 
    new FilterMemberData { PropertyDisplay = "Order ID", PropertyType = typeof(int), PropertyName = "OrderID" }, 
    new FilterMemberData { PropertyDisplay = "Product ID", PropertyType = typeof(int), PropertyName = "ProductID" }, 
    new FilterMemberData { PropertyDisplay = "Unit Price", PropertyType = typeof(decimal), PropertyName = "UnitPrice" }, 
    new FilterMemberData { PropertyDisplay = "Quantity", PropertyType = typeof(short), PropertyName = "Quantity" }, 
    new FilterMemberData { PropertyDisplay = "Discount", PropertyType = typeof(float), PropertyName = "Discount" }, 
};              
XAML
Copy Code
<Intersoft:UXQueryBuilder FilterPropertiesSource="{Binding OrderDetailsFilterMemberData}"
            QueryOperation="Server" EnableNestedFilter="{Binding EnabledNestedFilter}" 
            PropertyDisplayMemberPath="PropertyDisplay" PropertyNameMemberPath="PropertyName" 
            PropertyTypeMemberPath="PropertyType" />

Customizing Property Generation and Editors

UXQueryBuilder allows room for further customization for generation of property names through the use of IncludeNavigationProperties and PropertyListMode properties. These properties give developers refined control over UXQueryBuilder property generation.

Include Navigation Properties

The IncludeNavigationProperties property enables UXQueryBuilder to list nested navigation properties in the object model. You can enable it by setting IncludeNavigationProperties to true.

Using ObjectType

Using the previous object model:

Order_Detail.cs
Copy Code
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Intersoft.Client.Data.ComponentModel;

namespace ClientUI._2012R2.Preview.DomainModel
{
    public partial class Order_Detail
    {
        public class Order_DetailFilterMetadata
        {
            public int OrderID { get; set; }

            public int ProductID { get; set; }

            public decimal UnitPrice { get; set; }

            public short Quantity { get; set; }

            public float Discount { get; set; }
                        
                        public Product Product { get; set; }
        }
    }
}               
XAML
Copy Code
<Intersoft:UXQueryBuilder ObjectType="{Binding ObjectType}"
        FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server"
        IncludeNavigationProperties="True"/>
                

Using FilterPropertiesSource

XAML
Copy Code
<Intersoft:UXQueryBuilder FilterPropertiesSource="{Binding ProductsFilterMemberData}"
        ParentNameMemberPath="ParentName" PropertyDisplayMemberPath="PropertyDisplay"
        PropertyNameMemberPath="PropertyName" PropertyTypeMemberPath="PropertyType"
        PropertyPreferredFilterOperatorMemberPath="PreferredFilterOperator"
        FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server"
                IncludeNavigationProperties="True"/>

To use navigation properties in conjunction with FilterPropertiesSource, you need to specify the ParentNameMemberPath.

C#
Copy Code
this._orderDetailsFilterMemberData = new ObservableCollection<FilterMemberData> 
{ 
    new FilterMemberData { PropertyDisplay = "Order ID", PropertyType = typeof(int), PropertyName = "OrderID" }, 
    new FilterMemberData { PropertyDisplay = "Product ID", PropertyType = typeof(int), PropertyName = "ProductID" }, 
    new FilterMemberData { PropertyDisplay = "Unit Price", PropertyType = typeof(decimal), PropertyName = "UnitPrice" }, 
    new FilterMemberData { PropertyDisplay = "Quantity", PropertyType = typeof(short), PropertyName = "Quantity" }, 
    new FilterMemberData { PropertyDisplay = "Discount", PropertyType = typeof(float), PropertyName = "Discount" }, 
    new FilterMemberData { PropertyDisplay = "ProductID", PropertyType = typeof(int), PropertyName = "Product.Product", ParentName = "Product"}, 
    new FilterMemberData { PropertyDisplay = "ProductName", PropertyType = typeof(string), PropertyName = "Product.ProductName", ParentName = "Product"}, 
};

Property List Mode

PropertyListMode allows UXQueryBuilder to generate properties based on the FilterMemberAttributeIgnoreFilterMemberAttribute, DataMemberAttribute and IgnoreDataMemberAtrtibutePropertyListMode consists of three modes: AllFilterMemberOnly, and FilterMemberAndDataMember. You can specify which properties not to be included during property generation by utilizing the IgnoreFilterMemberAttribute or IgnoreDataMemberAttribute and set the PropertyListMode accordingly.

PropertyListMode.All

By setting PropertyListMode to PropertyListMode.AllUXQueryBuilder will list all properties related to the object model. However, this may cause UXQueryBuilder to list unwanted properties.

PropertyListMode.FilterMemberOnly

Setting PropertyListMode to PropertyListMode.FilterMemberOnly will cause UXQueryBuilder to list all properties with the FilterMemberAttribute.

PropertyListMode.FilterMemberAndDataMember

UXQueryBuilder will list all properties with either FilterMemberAttribute or DataMemberAttribute when PropertyListMode is set to PropertyListMode.FilterMemberAndDataMember.

Using ObjectType

You can customize which properties will be listed by specifying FilterMemberAttribute as follows:

Order_Detail.cs
Copy Code
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Intersoft.Client.Data.ComponentModel;

namespace ClientUI._2012R2.Preview.DomainModel
{
    [FilterMetadata(typeof(Order_DetailFilterMetadata))]
    public partial class Order_Detail
    {
        public class Order_DetailFilterMetadata
        {
            [FilterMember]
            public int OrderID { get; set; }

            [IgnoreFilterMember]
            public int ProductID { get; set; }

            [IgnoreFilterMember]
            public decimal UnitPrice { get; set; }

            [IgnoreFilterMember]
            public short Quantity { get; set; }

            [FilterMember]
            public float Discount { get; set; }

            [FilterMember]
            public Product Product { get; set; }
        }
    }
}

Using FilterPropertiesSource

FilterPropertiesSource is not affected by PropertyListMode. Simply do not include unwanted properties in the view model.

Filter Operator Customization

This section elaborates how developers can customize the filter operator generated by the selected property.

Default Operators

By default, UXQueryBuilder provides predefined operators for common property types.

Numeric types and DateTimeIsEqualToIsGreaterThanIsGreaterThanOrEqualToIsLessThanIsLessThanOrEqualToIsNotEqualTo.

String type: ContainsDoesNotContainEndsWithIsContainedInIsEqualToStartsWithIsNullOrEmpty.

Other types: IsEqualToIsNotEqualTo.

Exclude Operator

UXQueryBuilder provides the option for developers to include a specific set of filter operators by excluding undesired filter operators. The following example will demonstrate how to exclude specific set of operators in both ObjectType and FilterPropertiesSource scenario.

Using ObjectType

Order_Detail.cs
Copy Code
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Intersoft.Client.Data.ComponentModel;

namespace ClientUI._2012R2.Preview.DomainModel
{
    [FilterMetadata(typeof(Order_DetailFilterMetadata))]
    public partial class Order_Detail
    {
        public class Order_DetailFilterMetadata
        {
            [FilterMember(ExcludeFilterOperator = ExcludeFilterOperator.IsEqualTo ^ ExcludeFilterOperator.IsGreaterThan ^ ExcludeFilterOperator.IsGreaterThanOrEqualTo)]
            public int OrderID { get; set; }

            [IgnoreFilterMember]
            public int ProductID { get; set; }

            [IgnoreFilterMember]
            public decimal UnitPrice { get; set; }

            [IgnoreFilterMember]
            public short Quantity { get; set; }

            [FilterMember]
            public float Discount { get; set; }

            [FilterMember]
            public Product Product { get; set; }
        }
    }
}

You can specify multiple ExcludeFilterOperator by using the ^ (caret) sign.

Using FilterPropertiesSource

Currently, ExcludeFilterOperator is not available in FilterPropertiesSource.

Preferred Filter Operator

PreferredFilterOperator is used to auto-select a filter operator when a property is selected, giving a more intuitive experience in using the UXQueryBuilder.

Using ObjectType

Order_Detail.cs
Copy Code
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Intersoft.Client.Data.ComponentModel;

namespace ClientUI._2012R2.Preview.DomainModel
{
    [FilterMetadata(typeof(Order_DetailFilterMetadata))]
    public partial class Order_Detail
    {
        public class Order_DetailFilterMetadata
        {
            [FilterMember(PreferredFilterOperator = FilterOperator.IsGreaterThanOrEqualTo)]
            public int OrderID { get; set; }

            [IgnoreFilterMember]
            public int ProductID { get; set; }

            [IgnoreFilterMember]
            public decimal UnitPrice { get; set; }

            [IgnoreFilterMember]
            public short Quantity { get; set; }

            [FilterMember]
            public float Discount { get; set; }

            [FilterMember]
            public Product Product { get; set; }
        }
    }
}

Using FilterPropertiesSource

Simply add ExcludeFilterOperator property in the your custom class and specify the PropertyPreferredFilterOperatorMemberPath in the view.

C#
Copy Code
this._orderDetailsFilterMemberData = new ObservableCollection<FilterMemberData>
{ 
    new FilterMemberData { PropertyDisplay = "Order ID", PropertyType = typeof(int), PropertyName = "OrderID", PreferredFilterOperator = FilterOperator.IsGreaterThanOrEqualTo}, 
    new FilterMemberData { PropertyDisplay = "Product ID", PropertyType = typeof(int), PropertyName = "ProductID" }, 
    new FilterMemberData { PropertyDisplay = "Unit Price", PropertyType = typeof(decimal), PropertyName = "UnitPrice" }, 
    new FilterMemberData { PropertyDisplay = "Quantity", PropertyType = typeof(short), PropertyName = "Quantity" }, 
    new FilterMemberData { PropertyDisplay = "Discount", PropertyType = typeof(float), PropertyName = "Discount" }, 
    new FilterMemberData { PropertyDisplay = "ProductID", PropertyType = typeof(int), PropertyName = "Product.Product", ParentName = "Product"}, 
    new FilterMemberData { PropertyDisplay = "ProductName", PropertyType = typeof(string), PropertyName = "Product.ProductName", ParentName = "Product"}, 
};
XAML
Copy Code
<Intersoft:UXQueryBuilder FilterPropertiesSource="{Binding OrderDetailsFilterMemberData}"
        QueryOperation="Server" PropertyDisplayMemberPath="PropertyDisplay"
        ParentNameMemberPath="ParentName" PropertyNameMemberPath="PropertyName"
        PropertyTypeMemberPath="PropertyType"
        PropertyPreferredFilterOperatorMemberPath="PreferredFilterOperator" />
                

 

Value Customization

Default Editors

By default, UXQueryBuilder provides four value editors for common data types as follows:

String/Other : UXTextBox

DateTime : UXDateTimePicker

Boolean/Enum : UXComboBox

Numeric : UXCurrencyEditor

Data List Provider

DataListProvider provides a convenient way to enhance the filter experience by providing a predefined set of values to the value editor in the object model. Suppose the user would like to search for SupplierID. It will be quite an unpleasant experience if the user would have to type the ID of the Supplier to execute the filter process. In this scenario, DataListProvider can be used to enhance the filter experience.

ModelSnippet
Copy Code
namespace ClientUI._2012R2.Preview.DomainModel
{
    [FilterMetadata(typeof(ProductFilterMetadata))]
    [DisplayMember("ProductName")]
    public partial class Product
    {
        public class ProductFilterMetadata
        {
            [FilterMember]
            [DataListProvider("ClientUI._2012R2.Preview.DataListProvider.SupplierDataListProvider")]
            [Display(Name = "Supplier ID")]
            public System.Nullable<int> SupplierID { get; set; }
        }
    }
}         
SupplierDataListProvider.cs
Copy Code
using System;
using System.Collections;
using System.Linq;
using ClientUI._2012R2.Preview.DomainModel;
using IdeaBlade.EntityModel;
using Intersoft.Client.Data.ComponentModel;
using Intersoft.Client.Data.ComponentModel.CollectionViews;
using Intersoft.Client.UI.Editors;

namespace ClientUI._2012R2.Preview.DataListProvider
{
    public class SupplierDataListProvider : EditorDataProvider
    {
        public SupplierDataListProvider()
        {
            this._manager = new NorthwindEntities();
            this.IsAsync = true;
            this.DisplayMemberPath = "CompanyName";
            this.SelectedValuePath = "SupplierID";
        }

        private NorthwindEntities Manager
        {
            get { return this._manager ?? (this._manager = new NorthwindEntities()); }
        }

        private NorthwindEntities _manager;

        public override bool IsAsync { get; set; }

        public override IEnumerable GetData()
        {
            throw new NotImplementedException();
        }

        public override object GetSingle(object item)
        {
            throw new NotImplementedException();
        }

        public override void BeginGetDataAsync(Guid token)
        {
            if (this.Manager != null)
            {
                var supplierQuery = this.Manager.Suppliers;
                this.Manager.ExecuteQueryAsync(supplierQuery, op =>
                {
                    if (op.CompletedSuccessfully)
                    {
                        this.EndGetDataAsync(token, op.Results);
                    }
                });
            }
        }

        public override void BeginSingleAsync(Guid token, object item)
        {
            if (this.Manager != null)
            {
                FilterDescriptor filterDescriptor = item as FilterDescriptor;
                FilterDescription filterDescription = item as FilterDescription;
                PropertyGridDefinition property = item as PropertyGridDefinition;
                int supplierID = 0;

                if (filterDescriptor != null && filterDescriptor.Value != null)
                    supplierID = (int)filterDescriptor.Value;
                else if (filterDescription != null && filterDescriptor.Value != null)
                    supplierID = (int)filterDescription.Value;
                else if (property != null && property.Value != null)
                    supplierID = (int)property.Value;

                var supplierQuery = this.Manager.Suppliers.Where(o => o.SupplierID == supplierID);
                this.Manager.ExecuteQueryAsync(supplierQuery, op =>
                {
                    if (op.CompletedSuccessfully)
                    {
                        this.EndGetSingleAsync(token, op.Results.FirstOrDefault());
                    }
                });
            }
        }

        public override string DisplayMemberPath { get; set; }

        public override string SelectedValuePath { get; set; }

    }
}
                

The following illustration shows the value editor automatically changed to UXComboBox when DataListProvider is used. When users select a value from the combobox control, the actual value (usually the unique ID) of the selection will be set to the filter descriptor behind the scene. This powerful feature is particularly useful to address common business applications such as in master-detail scenarios.

Customizing Default Editors

Using Explicit Styles

You can customize the default editors provided by UXQueryBuilder by specifying explicit styles and target the appropriate value editor.

XAML
Copy Code
<Intersoft:UXQueryBuilder Intersoft:DockPanel.Dock="Top" ObjectType="{Binding ObjectType}"
                          FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server" 
                           >
        <Intersoft:UXQueryBuilder.DateTimeEditorStyle>
            <Style TargetType="Intersoft:UXDateTimePicker">
                <Setter Property="MinHeight" Value="24" />
                <Setter Property="CornerRadius" Value="0,4,4,0" />
                <Setter Property="IsAdvancingCaret" Value="True"/>
                <Setter Property="FirstDayOfWeek" Value="Monday"/>
            </Style>
        </Intersoft:UXQueryBuilder.DateTimeEditorStyle>
        <Intersoft:UXQueryBuilder.DefaultEditorStyle>
            <Style TargetType="Intersoft:UXTextBox">
                <Setter Property="MinHeight" Value="24" />
                <Setter Property="CornerRadius" Value="0,4,4,0" />
                <Setter Property="WatermarkText" Value="Specify Value"/>
                <Setter Property="WatermarkTextVisibility" Value="Visible"/>
                <Setter Property="MaxLength" Value="250"/>
            </Style>
        </Intersoft:UXQueryBuilder.DefaultEditorStyle>
</Intersoft:UXQueryBuilder>

Using Editor Definitions

The following snippet code shows how to customize the default editor using EditorDefinition.

XAML
Copy Code
<Intersoft:UXQueryBuilder Intersoft:DockPanel.Dock="Top" ObjectType="{Binding ObjectType}"
        FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server">
    <Intersoft:UXQueryBuilder.EditorDefinitions>
        <Intersoft:EditorDefinition TargetType="System.Nullable'1[System.DateTime]">
            <Intersoft:EditorDefinition.EditorStyle>
                <Style TargetType="Intersoft:UXDateTimePicker">
                    <Setter Property="MinHeight" Value="24" />
                    <Setter Property="CornerRadius" Value="0,4,4,0" />
                    <Setter Property="IsAdvancingCaret" Value="True" />
                    <Setter Property="FirstDayOfWeek" Value="Monday" />
                </Style>
            </Intersoft:EditorDefinition.EditorStyle>
        </Intersoft:EditorDefinition>

        <Intersoft:EditorDefinition>
            <Intersoft:EditorDefinition.EditorStyle>
                <Style TargetType="Intersoft:UXCurrencyEditor">
                    <Setter Property="MaxLength" Value="5" />
                    <Setter Property="MinHeight" Value="24" />
                    <Setter Property="CornerRadius" Value="0,4,4,0" />
                    <Setter Property="WatermarkText" Value="Specify Value" />
                    <Setter Property="WatermarkTextVisibility" Value="Visible" />
                </Style>
            </Intersoft:EditorDefinition.EditorStyle>
            <Intersoft:EditorDefinition.PropertyDefinitions>
                <Intersoft:PropertyDefinition Name="OrderID" Type="System.Int32"></Intersoft:PropertyDefinition>
            </Intersoft:EditorDefinition.PropertyDefinitions>
        </Intersoft:EditorDefinition>
    </Intersoft:UXQueryBuilder.EditorDefinitions>
</Intersoft:UXQueryBuilder>    

Using Editor Selector

IEditorSelector provides a way to customize the default editor programmatically.

EditorSelector.cs
Copy Code
using Intersoft.Client.UI.Editors;
using Intersoft.Client.UI.Aqua.UXInput;

namespace ClientUI._2012R2.Preview.Selectors
{
    public class EditorSelector : IEditorSelector
    {
        public void ResolveSelector(EditorSelectorArgs args)
        {
            switch (args.PropertyName)
            {
                case "UnitPrice":
                    UXCurrencyEditor unitPriceEditor = args.EditorObject as UXCurrencyEditor;
                    unitPriceEditor.EditMask = "C2";
                    break;

                case "UnitsInStock":
                    UXCurrencyEditor unitsInStockEditor = args.EditorObject as UXCurrencyEditor;
                    unitsInStockEditor.EditMask = "N0";
                    break;

                case "UnitsOnOrder":
                    UXCurrencyEditor unitsOnOrderEditor = args.EditorObject as UXCurrencyEditor;
                    unitsOnOrderEditor.EditMask = "N0";
                    break;
            }
        }
    }
}
XAML
Copy Code
<Intersoft:UXPage.Resources>
    <Selector:EditorSelector x:Key="EditorSelector" />
</Intersoft:UXPage.Resources>
                        
<Intersoft:UXQueryBuilder ObjectType="{Binding ObjectType}" EditorSelector="{StaticResource EditorSelector}"
    FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server" />

Overriding Default Editors

Using Editor Template

You can use DataTemplate to override the default value editor.

XAML
Copy Code
<Intersoft:UXPage.Resources>
    <DataTemplate x:Key="NumericEditorTemplate">
        <Intersoft:UXNumericUpDown Value="{Binding Value, Mode=TwoWay}" />
    </DataTemplate>
</Intersoft:UXPage.Resources>
                
<Intersoft:UXQueryBuilder ObjectType="{Binding ObjectType}"
                    FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server"
                    NumericEditorTemplate="{StaticResource NumericEditorTemplate}" />

Using Editor Definitions

You can use EditorDefinition to override the default editor.

Example Title
Copy Code
<Intersoft:UXQueryBuilder ObjectType="{Binding ObjectType}"
        FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server">
    <Intersoft:UXQueryBuilder.EditorDefinitions>
        <Intersoft:EditorDefinition TargetType="System.Nullable'1[System.DateTime]">
            <Intersoft:EditorDefinition.EditorTemplate>
                <DataTemplate>
                    <Intersoft:UXDateTimeUpDown Value="{Binding Value, Mode=TwoWay}" CornerRadius="0,4,4,0"
                            MinHeight="24" MinWidth="100" />
                </DataTemplate>
            </Intersoft:EditorDefinition.EditorTemplate>
        </Intersoft:EditorDefinition>

        <Intersoft:EditorDefinition>
            <Intersoft:EditorDefinition.EditorTemplate>
                <DataTemplate>
                    <Intersoft:UXNumericUpDown Value="{Binding Value, Mode=TwoWay}" CornerRadius="0,4,4,0"
                            MinHeight="24" MinWidth="100" />
                </DataTemplate>
            </Intersoft:EditorDefinition.EditorTemplate>
            <Intersoft:EditorDefinition.PropertyDefinitions>
                <Intersoft:PropertyDefinition Name="Freight" Type="System.Nullable'1[System.Decimal]" />
            </Intersoft:EditorDefinition.PropertyDefinitions>
        </Intersoft:EditorDefinition>
    </Intersoft:UXQueryBuilder.EditorDefinitions>
</Intersoft:UXQueryBuilder>
                

Using Editor Selector

You can also override the default value editors programmatically using IEditorSelector.

EditorSelector.cs
Copy Code
using System.Windows;
using Intersoft.Client.UI.Controls;
using Intersoft.Client.UI.Editors;
using Intersoft.Client.UI.Aqua.UXInput;

namespace ClientUI._2012R2.Preview.Selectors
{
    public class EditorSelectorTemplate : IEditorSelector
    {
        public DataTemplate UnitsInStockEditor { get; set; }

        public DataTemplate UnitsOnOrderEditor { get; set; }

        public DataTemplate UnitPriceEditor { get; set; }

        public void ResolveSelector(EditorSelectorArgs args)
        {
            if (args.PropertyName == "UnitPrice")
            {
                if (!(args.EditorObject is UXNumericUpDown))
                    args.EditorTemplate = this.UnitPriceEditor;
            }

            if (args.PropertyName == "UnitsInStock")
            {
                if (!(args.EditorObject is UXSliderBar))
                    args.EditorTemplate = this.UnitsInStockEditor;
            }

            if (args.PropertyName == "UnitsOnOrder")
            {
                if (!(args.EditorObject is UXSliderBar))
                    args.EditorTemplate = this.UnitsOnOrderEditor;
            }
        }
    }
}   
XAML
Copy Code
<Intersoft:UXPage.Resources>
        <DataTemplate x:Key="UnitPriceEditor">
            <Intersoft:UXNumericUpDown MinWidth="100" MinHeight="24" CornerRadius="0,4,4,0" Value="{Binding Value, Mode=TwoWay}" />
        </DataTemplate>
        <DataTemplate x:Key="UnitsOnOrderEditor">
            <Intersoft:UXSliderBar Value="{Binding Value, Mode=TwoWay}" Maximum="100" Minimum="0" LargeChange="10" SmallChange="1"/>
        </DataTemplate>
        <DataTemplate x:Key="UnitsInStockEditor">
            <Intersoft:UXSliderBar Value="{Binding Value, Mode=TwoWay}" Maximum="100" Minimum="0" LargeChange="10" SmallChange="1"/>
        </DataTemplate>
        <Selector:EditorSelectorTemplate x:Key="EditorSelector" UnitPriceEditor="{StaticResource UnitPriceEditor}" UnitsOnOrderEditor="{StaticResource UnitsOnOrderEditor}" UnitsInStockEditor="{StaticResource UnitsInStockEditor}" />
</Intersoft:UXPage.Resources>
                        
<Intersoft:UXQueryBuilder ObjectType="{Binding ObjectType}" EditorSelector="{StaticResource EditorSelector}"
    FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server" />
                

Using Editor Type

You can also specify EditorType in the model to override the default editor.

Order_Detail.cs
Copy Code
[FilterMetadata(typeof(ProductFilterMetadata))]
[DisplayMember("ProductName")]
public partial class Product
{
    public class ProductFilterMetadata
    {
        [FilterMember(EditorTypeName = "ClientUI._2012R2.Preview.Views.UXQueryBuilder.QueryBuilderProductNameSelector")]
        [Display(Name = "Product Name")]
        public string ProductName { get; set; }
    }
}            

UX Features

Enable Nested Filter

When EnableNestedFilter property is set to true, UXQueryBuilder enables the creation of nested filters. You can set EnableNestedFilter to false if you do not need the user to create complex nested filters. EnableNestedFilter will not have any effect if there is only one filter item in the filter collection.

Predefined Composite Filter

UXQueryBuilder enables predefined composite filter to take effect upon first load by simply creating a composite filter and bind the composite filter to the CompositeFilter property.

C#
Copy Code
CompositeFilterDescriptor composite = new CompositeFilterDescriptor();
composite.FilterDescriptors.Add(new FilterDescriptor() { PropertyName = "OrderDate", Value = new DateTime(1996, 1, 1), Operator = FilterOperator.IsGreaterThanOrEqualTo });
composite.FilterDescriptors.Add(new FilterDescriptor() { PropertyName = "OrderDate", Value = new DateTime(1997, 1, 1), Operator = FilterOperator.IsLessThanOrEqualTo });

this.PredefinedCompositeFilterDescriptor = composite;

this.QueryDescriptor.FilterDescriptors.Add(composite);
                
XAML
Copy Code
<Intersoft:UXQueryBuilder ObjectType="{Binding ObjectType}"
        CompositeFilter="{Binding PredefinedCompositeFilterDescriptor}"
        FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server" />

Save / Load Filters

UXQueryBuilder features save and loading of filters for future reusability. After creating a complex set of filters, users are able to save the filter into industry-standard JSON (JavaScript Object Notation) format and load them. This feature is not enabled by default. For example, you can create a UXButton with command that calls UXQueryBuilderCommands.Save or UXQueryBuilderCommands.Load accordingly.

XAML
Copy Code
<StackPanel>
    <Intersoft:UXButton Command="Intersoft:UXQueryBuilderCommands.Save" Content="Save Filters" CommandTarget="{Binding ElementName=UXQueryBuilder}"/>
    <Intersoft:UXButton Command="Intersoft:UXQueryBuilderCommands.Load" Content="Load Filters" CommandTarget="{Binding ElementName=UXQueryBuilder}"/>
</StackPanel>

Edit Mouse Gestures

EditMouseGesture property defines the mouse gesture needed for UXQueryBuilder to enter editing mode, consisting of SingleClickDoubleClick and SecondClick.

Localization

Localization is available to UXQueryBuilder by utilizing the ResourceOverride and overriding each string, shown as follows:

C#
Copy Code
<Intersoft:UXQueryBuilder Intersoft:DockPanel.Dock="Top" ObjectType="{Binding ObjectType}"
                          FilterDescriptors="{Binding QueryDescriptor.FilterDescriptors, Mode=TwoWay}" QueryOperation="Server"
                          EnableNestedFilter="{Binding EnabledNestedFilter}" 
                          IncludeNavigationProperties="{Binding IncludeNavigationProperties}"
                          PropertyListMode="{Binding SelectedPropertyListMode}" 
                           >
    <Intersoft:UXQueryBuilder.ResourceOverride>
        <Intersoft:UXQueryBuilderResource 
            BooleanValueFalse="Falsch"
            BooleanValueTrue="Wahr" 
            />
    </Intersoft:UXQueryBuilder.ResourceOverride>
</Intersoft:UXQueryBuilder>
                

UI Highlights

The following section highlights the UI elements in UXQueryBuilder.

If there is only one item, UXQueryBuilder will hide the composite logical operator button, as this element is considered to have no use when there is not at least two filter items.

Add Condition

When the Add Condition button is clicked, UXQueryBuilder will smooth animate to show the composite logical operator button, as well as adding one more item to the filter items collection. You can also use Ctrl+Shift+A to add condition.

Enable Nested Filter

If EnableNestedFilter is set to true and there is more than one filter item, then Add Nested Condition button will appear. You cannot add a nested filter when there is only one item in the collection.

Add Nested Condition

If the Add Group button is pressed, UXQueryBuilder will convert the current filter item to a composite filter, retaining the previous filter.

The nested condition will also be added with a smooth animation.

Composite Logical Operator

The composite logical operator is used to change the logical operator for the currently selected composite filter. You can also Add Condition, Add Group and Delete inside the dropdown.

Delete

When Delete button is pressed, UXQueryBuilder will delete the current filter item. You can also press Delete on the keyboard to delete the filter item.

If there is only one filter item, UXQueryBuilder will revert to its original state, with composite logical operator button hidden.

Clear

When Clear button is pressed, UXQueryBuilder will automatically clear all filter items and restore UXQueryBuilder to initial state.

Filter

When Filter button is pressed, the filter process takes place. UXQueryBuilder automatically validates when either PropertyName or Value is not specified. You can also use Shift+Enter to execute the filter process anytime.

If all filters are considered valid, then the filter process will continue.

Keyboard Navigation

Despite its nature to handle complex queries, UXQueryBuilder is designed to give an intuitive keyboard navigation experience.

Tab Cycles

The following figure will illustrate how Tab cycles is handle in UXQueryBuilder.

Filter Items Cycles

Pressing Up and Down key when focused on a filter item will intuitively cycle between filter items.

Shortcut Keys

Pressing Delete will delete the current filter item. Pressing Ctrl+Shift+A will either Add Condition (when focused to an item) or Add Nested Condition (when focused to composite logical operator button or add condition button).

See Also

Tasks