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:BooleanConverterx:Key="BooleanConverter"/><local:InvBooleanConverterx:Key="InvBooleanConverter"/><local:StringToIntConverterx:Key="StringToIntConverter"/><local:StringToDblConverterx:Key="StringToDblConverter"/><local:SettingValueTemplateSelectorx:Key="SettingValueTemplateSelector"><local:SettingValueTemplateSelector.BooleanTemplate><DataTemplate><StackPanelOrientation="Horizontal"><telerik:RadRadioButtonIsChecked="{Binding Path=Value}"><TextBlockText="Enabled"/></telerik:RadRadioButton><telerik:RadRadioButtonIsChecked="{Binding Path=Value}"><TextBlockText="Disabled"/></telerik:RadRadioButton></StackPanel></DataTemplate></local:SettingValueTemplateSelector.BooleanTemplate><local:SettingValueTemplateSelector.IntTemplate><DataTemplate><telerik:RadNumericUpDownValue="{Binding Path=Value, Converter={StaticResource StringToIntConverter}}"NumberDecimalDigits="0"/></DataTemplate></local:SettingValueTemplateSelector.IntTemplate><local:SettingValueTemplateSelector.DoubleTemplate><DataTemplate><telerik:RadNumericUpDownValue="{Binding Path=Value,Converter={StaticResource StringToDblConverter}}"/></DataTemplate></local:SettingValueTemplateSelector.DoubleTemplate><local:SettingValueTemplateSelector.StringTemplate><DataTemplate><TextBlockText="{Binding Path=Value, Mode=TwoWay}"/></DataTemplate></local:SettingValueTemplateSelector.StringTemplate></local:SettingValueTemplateSelector></Grid.Resources><telerik:RadGridViewx: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:GridViewDataColumnHeader="Value"IsGroupable="True"DataMemberBinding="{Binding Value}"CellTemplateSelector="{StaticResource SettingValueTemplateSelector}"Background="LightGray"></telerik:GridViewDataColumn><telerik:GridViewDataColumnHeader="ValueType"IsGroupable="True"DataMemberBinding="{Binding ValueType}"Background="LightGray"></telerik:GridViewDataColumn></telerik:RadGridView.Columns></telerik:RadGridView></Grid>
Template selector:publicclassSettingValueTemplateSelector : DataTemplateSelector{publicoverrideDataTemplate SelectTemplate(objectitem, DependencyObject container){if(itemisDataObjecten){DataObjecten model = itemasDataObjecten;if(model.ValueType ==typeof(int))returnthis.IntTemplate;elseif(model.ValueType ==typeof(String))returnthis.StringTemplate;elseif(model.ValueType ==typeof(double))returnthis.DoubleTemplate;elseif(model.ValueType ==typeof(bool))returnthis.BooleanTemplate;elsereturnnull;}returnnull;}}
One of the converters (basic):publicclassStringToIntConverter : IValueConverter{publicobjectConvert(objectvalue, Type targetType,objectparameter, System.Globalization.CultureInfo culture){intretValue=0;if(int.TryParse(value.ToString(),outretValue)){returnretValue;}elsereturn0;}publicobjectConvertBack(objectvalue, Type targetType,objectparameter, System.Globalization.CultureInfo culture){thrownewNotSupportedException("Do not use this converter for objects other than boolean");}}
Model:publicclassDataObject{publicobjectValue {get;set; }publicType ValueType {get;set; }}List.Add(newDataObject() { Value ="8", ValueType =typeof(int) });List.Add(newDataObject() { Value ="8", ValueType =typeof(double) });List.Add(newDataObject() { Value ="8gf", ValueType =typeof(string) });List.Add(newDataObject() { Value = 454365, ValueType =typeof(int) });List.Add(newDataObject() { Value =false, ValueType =typeof(bool) });