This is a migrated thread and some comments may be shown as answers.

Gridview, TemplateSelectors and Converters

3 Answers 183 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Theo
Top achievements
Rank 1
Theo asked on 22 Aug 2013, 11:26 AM
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:
<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) });

3 Answers, 1 is accepted

Sort by
0
Nedyalko Nikolov
Telerik team
answered on 27 Aug 2013, 07:54 AM
Hello,

I've made a project based on your code snippets and according to me everything works fine on my end.
Could you please use the attached project as a reference and provide me with more info how to simulate the problem?
Thank you in advance.

Regards,
Nedyalko Nikolov
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Theo
Top achievements
Rank 1
answered on 28 Aug 2013, 11:37 AM
Thanks for your support. Unfortunately your answer is exactly my problem I am facing at this moment. First of all I changed the data in your project, so debugging would be easier, like so:
this.DataSource.Add(new DataObject() { Value = 8, ValueType = typeof(int) });
this.DataSource.Add(new DataObject() { Value = 3d, ValueType = typeof(double) });
this.DataSource.Add(new DataObject() { Value = "454365j", ValueType = typeof(string) });
And I copied this several times so the grid has some more data. Start the application and wait until it is loaded. Place breakpoints in the Convert methods of the converters. Now scroll down in the application so data which was not visible now will be. You will notice for example that "454365j" item will be converted to an int. This is because the template selector will hit later. And in this example there is no need for a converter since this is an int. There is were our application also has troubles. The order of execution is not correct in my opinion. 

btw, should I enter a support ticket for this in the next case?
0
Nedyalko Nikolov
Telerik team
answered on 02 Sep 2013, 01:36 PM
Hello,

You could place different controls in each Data template and you will see that there is no problem with bindings. For example I've changed telerik:RadNumericUpDown for doubles with a ordinary TextBlock and TextBlock for string values with TextBox and scrolling work as expected too.
Could you please send me (in a separate support ticket, because you cannot attach files in a forum post) a repro project which I can debug on my side in order to see what is going on?

Regards,
Nedyalko Nikolov
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
Tags
GridView
Asked by
Theo
Top achievements
Rank 1
Answers by
Nedyalko Nikolov
Telerik team
Theo
Top achievements
Rank 1
Share this question
or