In our project we want to load settings. Because of the origin of this settings structure these are very generic, exposed via wcf etc. So when we load them in our viewmodel they have the type Object. Also they consist of the real type information so we can convert them to the corresponding type. So far so good.
When we load them in a gridview we would like to have different controls, for the different types. A Boolean should be a togglebutton, a int a numeric updown control and a string a regular textbox. For this approach we use Template selectors, but we also need to convert the types of the objects as described above. Therefore we use converters so the controls accepting the correct values and types. Until this point everything works great. We the problem arises when you scroll down in the grid. I guess you did some optimization. Therefore the templates and converters are evaluated when scrolling down. But in a different order then on initial loading. When the grid load for the first time, first the template is selected and then the converter. But when scrolling down, this order changes. To me that's a bit strange, because how can the converter be determined is there is no template. You will find sample code below. Only in our application there are binding errors showing up in the output window, in this example not. But the problem is still the same. Can we work around this issue, or need you guys to update this?
MainWindow:
When we load them in a gridview we would like to have different controls, for the different types. A Boolean should be a togglebutton, a int a numeric updown control and a string a regular textbox. For this approach we use Template selectors, but we also need to convert the types of the objects as described above. Therefore we use converters so the controls accepting the correct values and types. Until this point everything works great. We the problem arises when you scroll down in the grid. I guess you did some optimization. Therefore the templates and converters are evaluated when scrolling down. But in a different order then on initial loading. When the grid load for the first time, first the template is selected and then the converter. But when scrolling down, this order changes. To me that's a bit strange, because how can the converter be determined is there is no template. You will find sample code below. Only in our application there are binding errors showing up in the output window, in this example not. But the problem is still the same. Can we work around this issue, or need you guys to update this?
MainWindow:
<
Grid
>
<
Grid.Resources
>
<
local:BooleanConverter
x:Key
=
"BooleanConverter"
/>
<
local:InvBooleanConverter
x:Key
=
"InvBooleanConverter"
/>
<
local:StringToIntConverter
x:Key
=
"StringToIntConverter"
/>
<
local:StringToDblConverter
x:Key
=
"StringToDblConverter"
/>
<
local:SettingValueTemplateSelector
x:Key
=
"SettingValueTemplateSelector"
>
<
local:SettingValueTemplateSelector.BooleanTemplate
>
<
DataTemplate
>
<
StackPanel
Orientation
=
"Horizontal"
>
<
telerik:RadRadioButton
IsChecked
=
"{Binding Path=Value}"
>
<
TextBlock
Text
=
"Enabled"
/>
</
telerik:RadRadioButton
>
<
telerik:RadRadioButton
IsChecked
=
"{Binding Path=Value}"
>
<
TextBlock
Text
=
"Disabled"
/>
</
telerik:RadRadioButton
>
</
StackPanel
>
</
DataTemplate
>
</
local:SettingValueTemplateSelector.BooleanTemplate
>
<
local:SettingValueTemplateSelector.IntTemplate
>
<
DataTemplate
>
<
telerik:RadNumericUpDown
Value
=
"{Binding Path=Value, Converter={StaticResource StringToIntConverter}}"
NumberDecimalDigits
=
"0"
/>
</
DataTemplate
>
</
local:SettingValueTemplateSelector.IntTemplate
>
<
local:SettingValueTemplateSelector.DoubleTemplate
>
<
DataTemplate
>
<
telerik:RadNumericUpDown
Value
=
"{Binding Path=Value,Converter={StaticResource StringToDblConverter}}"
/>
</
DataTemplate
>
</
local:SettingValueTemplateSelector.DoubleTemplate
>
<
local:SettingValueTemplateSelector.StringTemplate
>
<
DataTemplate
>
<
TextBlock
Text
=
"{Binding Path=Value, Mode=TwoWay}"
/>
</
DataTemplate
>
</
local:SettingValueTemplateSelector.StringTemplate
>
</
local:SettingValueTemplateSelector
>
</
Grid.Resources
>
<
telerik:RadGridView
x:Name
=
"RadGridView"
GroupRenderMode
=
"Flat"
RowIndicatorVisibility
=
"Collapsed"
CanUserFreezeColumns
=
"False"
ItemsSource
=
"{Binding ElementName=Window1, Path=List}"
IsReadOnly
=
"false"
ScrollMode
=
"Deferred"
AutoExpandGroups
=
"True"
AutoGenerateColumns
=
"false"
Margin
=
"0,2,0,-2"
>
<
telerik:RadGridView.Columns
>
<
telerik:GridViewDataColumn
Header
=
"Value"
IsGroupable
=
"True"
DataMemberBinding
=
"{Binding Value}"
CellTemplateSelector
=
"{StaticResource SettingValueTemplateSelector}"
Background
=
"LightGray"
>
</
telerik:GridViewDataColumn
>
<
telerik:GridViewDataColumn
Header
=
"ValueType"
IsGroupable
=
"True"
DataMemberBinding
=
"{Binding ValueType}"
Background
=
"LightGray"
>
</
telerik:GridViewDataColumn
>
</
telerik:RadGridView.Columns
>
</
telerik:RadGridView
>
</
Grid
>
Template selector:public
class
SettingValueTemplateSelector : DataTemplateSelector
{
public
override
DataTemplate SelectTemplate(
object
item, DependencyObject container)
{
if
(item
is
DataObjecten)
{
DataObjecten model = item
as
DataObjecten;
if
(model.ValueType ==
typeof
(
int
))
return
this
.IntTemplate;
else
if
(model.ValueType ==
typeof
(String))
return
this
.StringTemplate;
else
if
(model.ValueType ==
typeof
(
double
))
return
this
.DoubleTemplate;
else
if
(model.ValueType ==
typeof
(
bool
))
return
this
.BooleanTemplate;
else
return
null
;
}
return
null
;
}
}
One of the converters (basic):public
class
StringToIntConverter : IValueConverter
{
public
object
Convert(
object
value, Type targetType,
object
parameter, System.Globalization.CultureInfo culture)
{
int
retValue=0;
if
(
int
.TryParse(value.ToString(),
out
retValue))
{
return
retValue;
}
else
return
0;
}
public
object
ConvertBack(
object
value, Type targetType,
object
parameter, System.Globalization.CultureInfo culture)
{
throw
new
NotSupportedException(
"Do not use this converter for objects other than boolean"
);
}
}
Model:public
class
DataObject
{
public
object
Value {
get
;
set
; }
public
Type ValueType {
get
;
set
; }
}
List.Add(
new
DataObject() { Value =
"8"
, ValueType =
typeof
(
int
) });
List.Add(
new
DataObject() { Value =
"8"
, ValueType =
typeof
(
double
) });
List.Add(
new
DataObject() { Value =
"8gf"
, ValueType =
typeof
(
string
) });
List.Add(
new
DataObject() { Value = 454365, ValueType =
typeof
(
int
) });
List.Add(
new
DataObject() { Value =
false
, ValueType =
typeof
(
bool
) });