I'm looking to add a custom control to each FilterCriteria in our RadDataFilter. Ideally, this would be a button to the right of the UserInput control. When pressed, it'll fetch unique values from the database and present them in a list of some sort. The user can then select a unique value and insert it into the UserInput control instead of having to type the value themselves.
I've looked at the documentation regarding custom FilterEditors. It looks like I could create the mapping from EditorTemplateRule to DataTemplate based on the PropertyInfo type instead of the PropertyInfo name. I would then need only a handful of DataTemplates (one per type) instead of hundreds of DataTemplates (we have hundreds of columns to search across).
However, it also seems I'd have to re-implement the stock functionality of the FilterEditors by providing a UserInput control that mimicks the current behavior. For instance, I'd have to handle DateTimes by providing a calendar selector. I'd like to not have to do that. I've been going through the Styles and Templates documentation to see if I can just add a template with a custom control to the right of the FilterEditor, but I'm not having much luck coming up with a solution.
Does anyone have ideas on the best way to approach this sort of customization?
Thanks.
I've looked at the documentation regarding custom FilterEditors. It looks like I could create the mapping from EditorTemplateRule to DataTemplate based on the PropertyInfo type instead of the PropertyInfo name. I would then need only a handful of DataTemplates (one per type) instead of hundreds of DataTemplates (we have hundreds of columns to search across).
However, it also seems I'd have to re-implement the stock functionality of the FilterEditors by providing a UserInput control that mimicks the current behavior. For instance, I'd have to handle DateTimes by providing a calendar selector. I'd like to not have to do that. I've been going through the Styles and Templates documentation to see if I can just add a template with a custom control to the right of the FilterEditor, but I'm not having much luck coming up with a solution.
Does anyone have ideas on the best way to approach this sort of customization?
Thanks.
5 Answers, 1 is accepted
0
Hello Kevin ,
Custom Filter Editors would be the only way to go.
There is almost no "stock" functionality when creating the default editors. Here is how we create the default DateTimeEditor:
So you can create a new control that will host both the editor and your additional UI and return this whole thing as the editor.
For your reference I am pasting the entire source code of our FilterEditorFactory:
I hope this helps. Let me know if you have any questions.
Greetings,
Ross
the Telerik team
Custom Filter Editors would be the only way to go.
There is almost no "stock" functionality when creating the default editors. Here is how we create the default DateTimeEditor:
private
static
FrameworkElement CreateDateTimeEditor()
{
var dateTimePicker =
new
RadDateTimePicker();
dateTimePicker.InputMode = InputMode.DatePicker;
dateTimePicker.IsTooltipEnabled =
false
;
var selectedValueBinding =
new
Binding(
"Value"
)
{
Mode = BindingMode.TwoWay,
FallbackValue =
null
,
Converter =
new
DateTimeFilterEditorConverter()
};
dateTimePicker.SetBinding(RadDateTimePicker.SelectedValueProperty, selectedValueBinding);
return
dateTimePicker;
}
So you can create a new control that will host both the editor and your additional UI and return this whole thing as the editor.
For your reference I am pasting the entire source code of our FilterEditorFactory:
using
System;
using
System.Windows;
using
Telerik.Windows.Controls.Filtering.Editors;
using
Telerik.Windows.Data;
using
System.Windows.Data;
using
System.Windows.Controls;
using
System.Collections;
using
System.Collections.Generic;
namespace
Telerik.Windows.Controls.GridView
{
internal
static
class
FilterEditorFactory
{
public
static
bool
IsCoreFrameworkElement(
object
element)
{
var fe = element
as
FrameworkElement;
if
(fe !=
null
)
{
var assName = fe.GetType().Assembly.FullName.Split(
','
)[0];
#if SILVERLIGHT
return
assName ==
"System.Windows"
;
#endif
#if WPF
return
assName ==
"PresentationFramework"
;
#endif
}
return
false
;
}
public
static
FrameworkElement CreateEditor(Type type)
{
FrameworkElement editor;
if
(type ==
typeof
(
string
))
{
editor = FilterEditorFactory.CreateStringEditor();
}
else
if
(type ==
typeof
(DateTime) || type ==
typeof
(DateTime?))
{
editor = FilterEditorFactory.CreateDateTimeEditor();
}
else
if
(type ==
typeof
(
bool
) || type ==
typeof
(
bool
?))
{
editor = FilterEditorFactory.CreateBooleanEditor(type);
}
else
if
(type.IsNumericType())
{
editor = FilterEditorFactory.CreateNumericEditor(type);
}
else
if
(type.IsEnum)
{
editor = FilterEditorFactory.CreateEnumEditor(type);
}
else
{
editor = FilterEditorFactory.CreateDefaultEditor();
}
return
editor;
}
/// <summary>
/// Creates the string editor.
/// </summary>
/// <returns></returns>
private
static
FrameworkElement CreateStringEditor()
{
return
new
StringFilterEditor();
}
private
static
FrameworkElement CreateDateTimeEditor()
{
var dateTimePicker =
new
RadDateTimePicker();
dateTimePicker.InputMode = InputMode.DatePicker;
dateTimePicker.IsTooltipEnabled =
false
;
var selectedValueBinding =
new
Binding(
"Value"
)
{
Mode = BindingMode.TwoWay,
FallbackValue =
null
,
Converter =
new
DateTimeFilterEditorConverter()
};
dateTimePicker.SetBinding(RadDateTimePicker.SelectedValueProperty, selectedValueBinding);
return
dateTimePicker;
}
private
static
FrameworkElement CreateBooleanEditor(Type type)
{
var checkBox =
new
CheckBox();
checkBox.IsThreeState = type ==
typeof
(
bool
?);
var isCheckedBinding =
new
Binding(
"Value"
)
{
Mode = BindingMode.TwoWay,
FallbackValue =
false
};
checkBox.SetBinding(CheckBox.IsCheckedProperty, isCheckedBinding);
return
checkBox;
}
private
static
FrameworkElement CreateNumericEditor(Type type)
{
var maskedTextBox =
new
RadMaskedTextBox();
maskedTextBox.MaskType = MaskType.Numeric;
maskedTextBox.UpdateValueEvent = UpdateValueEvent.LostFocus;
if
(type ==
typeof
(
double
)
|| type ==
typeof
(
double
?)
|| type ==
typeof
(
float
)
|| type ==
typeof
(
float
?))
{
maskedTextBox.Mask =
"f"
;
}
else
{
maskedTextBox.Mask =
"d"
;
}
var valueBinding =
new
Binding(
"Value"
)
{
Mode = BindingMode.TwoWay,
Converter =
new
FilterDescriptorValueToMaskedTextBoxValueConverter(),
FallbackValue =
null
};
maskedTextBox.SetBinding(RadMaskedTextBox.ValueProperty, valueBinding);
return
maskedTextBox;
}
private
static
FrameworkElement CreateEnumEditor(Type type)
{
var comboBox =
new
RadComboBox();
comboBox.SelectedValuePath =
"Value"
;
comboBox.DisplayMemberPath =
"DisplayName"
;
comboBox.ItemsSource = EnumDataSource.FromType(type);
var selectedItemBinding =
new
Binding(
"Value"
)
{
Mode = BindingMode.TwoWay,
FallbackValue =
null
};
comboBox.SetBinding(RadComboBox.SelectedValueProperty, selectedItemBinding);
return
comboBox;
}
private
static
FrameworkElement CreateDefaultEditor()
{
var textBox =
new
TextBox();
var textBinding =
new
Binding(
"Value"
)
{
Mode = BindingMode.TwoWay,
FallbackValue =
null
};
textBox.SetBinding(TextBox.TextProperty, textBinding);
TextBoxBehavior.SetUpdateTextOnEnter(textBox,
true
);
TextBoxBehavior.SetSelectAllOnGotFocus(textBox,
true
);
return
textBox;
}
private
class
FilterDescriptorValueToMaskedTextBoxValueConverter : IValueConverter
{
public
object
Convert(
object
value, Type targetType,
object
parameter, System.Globalization.CultureInfo culture)
{
if
(value == FilterDescriptor.UnsetValue)
{
return
null
;
}
return
value;
}
public
object
ConvertBack(
object
value, Type targetType,
object
parameter, System.Globalization.CultureInfo culture)
{
return
value;
}
}
private
class
DateTimeFilterEditorConverter : IValueConverter
{
public
object
Convert(
object
value, Type targetType,
object
parameter, System.Globalization.CultureInfo culture)
{
if
(value == FilterDescriptor.UnsetValue)
{
return
null
;
}
return
value;
}
public
object
ConvertBack(
object
value, Type targetType,
object
parameter, System.Globalization.CultureInfo culture)
{
return
value;
}
}
}
}
I hope this helps. Let me know if you have any questions.
Greetings,
Ross
the Telerik team
Browse the videos here>> to help you get started with RadControls for WPF
0
Kevin
Top achievements
Rank 1
answered on 10 Dec 2010, 03:24 PM
Thanks for the information, Ross. It's good to know I have a path I can follow. Unfortunately I'm still at a loss as to how I can make use of the reference code you provided. Are you suggesting that I:
1) Make a custom user control for each Data Type.
2) Have that user control include functionality that you provided in your reference code as well as my custom control.
3) Create a DataTemplate in XAML for each custom control (by data type).
4) Map the DataTemplates to data types using EditorTemplateRules that use PropertyType instead of PropertyName.
I want to make sure I've got the high level steps right before attacking this.
1) Make a custom user control for each Data Type.
2) Have that user control include functionality that you provided in your reference code as well as my custom control.
3) Create a DataTemplate in XAML for each custom control (by data type).
4) Map the DataTemplates to data types using EditorTemplateRules that use PropertyType instead of PropertyName.
I want to make sure I've got the high level steps right before attacking this.
0
Hi Kevin ,
That is exactly my idea.
You can find a similar implementation in our online example called Custom Filter Editors. For example, we have an editor which is RadSlider. Another one is a panel with two buttons. Another one is a RadComboBox. All of them are just controls.
The bottom-line is that the custom editor can be any kind of control -- simple or complex -- as long as you have something inside it that is data-bound to the property called Value. Value is the name of the property on the view model serving as the DataContext for the whole editor control. This is in fact is the Value of the underlying FilterDescriptor object.
Since I have provided all the code needed to initialize our default editors, you can copy them to your more complex control and add your part of the editor.
Let me know if you have any other questions. I will help with anything I can.
Best wishes,
Ross
the Telerik team
That is exactly my idea.
You can find a similar implementation in our online example called Custom Filter Editors. For example, we have an editor which is RadSlider. Another one is a panel with two buttons. Another one is a RadComboBox. All of them are just controls.
The bottom-line is that the custom editor can be any kind of control -- simple or complex -- as long as you have something inside it that is data-bound to the property called Value. Value is the name of the property on the view model serving as the DataContext for the whole editor control. This is in fact is the Value of the underlying FilterDescriptor object.
Since I have provided all the code needed to initialize our default editors, you can copy them to your more complex control and add your part of the editor.
Let me know if you have any other questions. I will help with anything I can.
Best wishes,
Ross
the Telerik team
Browse the videos here>> to help you get started with RadControls for WPF
0
Kevin
Top achievements
Rank 1
answered on 10 Dec 2010, 10:19 PM
Thanks again for the help. I have the code to the point where the RadDataFilter shows my user control which contains the Telerik StringFilterEditor as well as my custom component.It does this based on Type, which is what I need so I think this approach will work out just fine.
There are a couple of issues I'm running into though:
1) Creating the custom user control
Here are the user controls I'm now working with:
SearchView - our user control that contains the RadDataFilter
UniqueStringFilterEditor - our user control that contains the Telerik StringFilterEditor and the UniqueValueSelector
UniqueValueSelector - the user control that contains a button which will display unique values for the current column
I'm currently adding the Telerik StringFilterEditor to the UniqueStringFilterEditor through the code-behind, by inserting it into a stack panel. I'd really like to declare the StringFilterEditor through the XAML instead, but I can't determine whether or not that's possible using the FilterEditorFactory. Do you have any ideas on that?
2) Passing data through the user controls
I'll need to take the selected column name from the RadDataFilter and pass it through to the UniqueValueSelector. It seems like the kind of thing I'd use data binding for, but I can't see how to do it just yet. Any tips there would be greatly appreciated.
0
Hello Kevin ,
"I'd really like to declare the StringFilterEditor through the XAML instead, but I can't determine whether or not that's possible using the FilterEditorFactory."
The Factory is actually internal and is ours. You don't have access to the Factory so just forget that I mentioned it.
The result of the FilterEditorFactory is what RadDataFilter creates by default and provides to the developer (you) in the event handler. Having this default control you can do two things with it:
A. Decide to stick with it and configure it further. For example, change its Background or anything else that comes to mind. This can be done in the EditorCreated event. If this is the case you don't need an EditorTemplateSelector since you are not replacing the default control but simply configuring it.
B. If you have an EditorTemplateSelector the Factory will not even try to produce something because it knows that the editor will be provided by you. In this case you use the EditorTemplateSelector. Since you will replace the default editor with your very own one -- you don't have to care about this Factory at all. What the Factory does (or does not do in this case) is not your concern. I just pasted the code from our Factory so you can create the default editors with the same settings as we do. In other words, now you are the Factory for filter editors, not RadDataFilter.
I'll need to take the selected column name from the RadDataFilter and pass it through to the UniqueValueSelector.
This information is kept in the DataContext that the editor control receives which is of type SimpleFilterViewModel. The most important properties that you care about on this view model are called:
Member -- this is the "name of the column", as you call it.
MemberType
Operator
Value
I have prepared a sample project that demonstrates all of this. I have created some dummy editor control that simply demonstrates the stuff that you can bind to.
I really hope this helps.
Regards,
Ross
the Telerik team
"I'd really like to declare the StringFilterEditor through the XAML instead, but I can't determine whether or not that's possible using the FilterEditorFactory."
The Factory is actually internal and is ours. You don't have access to the Factory so just forget that I mentioned it.
The result of the FilterEditorFactory is what RadDataFilter creates by default and provides to the developer (you) in the event handler. Having this default control you can do two things with it:
A. Decide to stick with it and configure it further. For example, change its Background or anything else that comes to mind. This can be done in the EditorCreated event. If this is the case you don't need an EditorTemplateSelector since you are not replacing the default control but simply configuring it.
B. If you have an EditorTemplateSelector the Factory will not even try to produce something because it knows that the editor will be provided by you. In this case you use the EditorTemplateSelector. Since you will replace the default editor with your very own one -- you don't have to care about this Factory at all. What the Factory does (or does not do in this case) is not your concern. I just pasted the code from our Factory so you can create the default editors with the same settings as we do. In other words, now you are the Factory for filter editors, not RadDataFilter.
I'll need to take the selected column name from the RadDataFilter and pass it through to the UniqueValueSelector.
This information is kept in the DataContext that the editor control receives which is of type SimpleFilterViewModel. The most important properties that you care about on this view model are called:
Member -- this is the "name of the column", as you call it.
MemberType
Operator
Value
I have prepared a sample project that demonstrates all of this. I have created some dummy editor control that simply demonstrates the stuff that you can bind to.
I really hope this helps.
Regards,
Ross
the Telerik team
Browse the videos here>> to help you get started with RadControls for WPF