Force re-fire of CellTemplateSelector

9 posts, 1 answers
  1. Michael Lawrence
    Michael Lawrence avatar
    11 posts
    Member since:
    Jul 2006

    Posted 04 Aug 2010 Link to this post

    Hi People

    I am having an issue with the RadGridView control, specifically around the GridViewColumn.CellTemplateSelector property.  I have a grid with a column which needs to be presented in different ways based on the state of the data.  So, I have defined several DataTemplate items in my XAML, and implemented a DataTemplateSelector to select the appropriate DataTemplate.  When data is initially added to the collection that my grid is bound to, the DataTemplateSelector works as expected.  Very nice.

    However, if the user performs some action which requires the selector to be re-evaluated, I am stuck.  There is no obvious way to trigger this re-evaluation of the selector for existing rows.  I have tried triggering collection changed events off the underlying ObservableCollection I am binding to, and while this ensures that new items added to the grid are rendered correctly via the selector, I can't get the old ones to be re-evaluated.  I need to invalidate them some how.

    I have also tried the RadGridView.Rebind method, also to no avail.  

    Could you please advise on a way to cause the CellTemplateSelector to be re-evaluated for existing data - or if indeed it is even possible.

    I am using the Silverlight 4 2010 Q1 release of your toolkit.

    Thanks and regards
    Nathan

  2. Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 04 Aug 2010 Link to this post

    Hello Nathan,

     Please try the approach demonstrated in this blog post and let me know about the result. 

    Sincerely yours,
    Vlad
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. Michael Lawrence
    Michael Lawrence avatar
    11 posts
    Member since:
    Jul 2006

    Posted 04 Aug 2010 Link to this post

    Hi Vlad

    Thanks for your response.

    This link seems to be just a basic tutorial on using MVVM with the RadGridView.  It really doesn't deal with template selectors at all, and while the editing capabilities of the grid are interesting, I don't think they are really relevant to my problem.  This aside, I am using an MVVM approach with the data grid and using INotifyPropertyChanged and ObservableCollection already, so I don't believe my general approach is the problem here.

    I have managed to work around the problem by setting the IsBusy flag on the RadGridView, removing the existing items from the underlying data-bound collection and re-adding them, and then clearing IsBusy at the end of the process.  This ensures that the template selector is re-evaluated.  That said, I worry a bit about potential screen flicker (growing and shrinking table rows etc) with this approach but I haven't noticed it yet.

    If there is a better way of achieving this with the RadGridView, please let me know - as this workaround I am using is really a bit of a hack IMHO and I would like a more elegant solution if possible.

    Thanks
    Nathan
  4. Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 04 Aug 2010 Link to this post

    Hello,

     The project actually shows how to force the grid to reapply (in a smart way) various settings like sorting, grouping, etc. after a value is changed outside of the grid. Please check the section related to CommitEdit() method of Items.

    Greetings,
    Vlad
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  5. Michael Lawrence
    Michael Lawrence avatar
    11 posts
    Member since:
    Jul 2006

    Posted 04 Aug 2010 Link to this post

    Hi Vlad

    Yes, I have had a look at the editing related code you talked about.  I have tried performing edits like in the example to try and trick the grid into re-applying the selectors.  Now, I have no grouping or sorting in my data, and the data that is actually changing and which I wish to trigger the re-application of the selector on is not in the collection of data that the RadGridView is bound to.  So, the RadGridView has no way of knowing that the change has occurred unless I tell it - which is where my problem starts.

    Look at the snippet below.  I have a user control which is bound to class A.  Class A contains a collection of items of class B - and this is what the RadGridView is bound to.  The RadGridView has a column in which it uses a CellTemplateSelector to evaluate a property ( SomeObject) on class A.  As rows are added to the collection that the grid is bound to (SomeItems), the CellTemplateSelector is applied - no problem.  However, when SomeObject changes, the RadGridView does not re-apply the CellTemplateSelector.  Of course it doesn't - how is it to know?  The point is, how do I tell it to...  

    // Assume the classes and properties implement and utilise INotifyPropertyChanged
     
    public class A : ViewModelBase
    {
        public SomeObjectType SomeObject { get; set; }
        public ObservableCollection<B> Stuff SomeItems { get; set; }
    }
     
    public class B : ViewModelBase
    {
        // Some properties the RadGridView columns are bound to
    }


    I have tried attempting to force RadGridView to do this by using the BeginEdit / CommitEdit example you have directed me towards, applying it to every item in the RadGridView.Items collection every time that SomeObject changes - but it DOES NOT trigger the CellTemplateSelector to be re-evaluated.

    Any ideas would be welcome.

    Thanks
    Nathan
  6. Answer
    Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 04 Aug 2010 Link to this post

    Hello Nathan,

     I've attached small example project. Let me know how it goes. 

    Sincerely yours,
    Vlad
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  7. Michael Lawrence
    Michael Lawrence avatar
    11 posts
    Member since:
    Jul 2006

    Posted 04 Aug 2010 Link to this post

    Hi Vlad

    Thanks for the sample.  It demonstrated what needed to be done.  For anyone interested, here is a summary of what you need to do to get CellTemplateSelector's to re-fire based on an external trigger:

    1. A CellTemplateSelector needs to be specified on the column.  Yeah, kinda obvious, I know.

    2. The column with the template selector MUST be bound to a property on the data bound collection (ie, a property of an item within the collection) - even though the data templates that the CellTemplateSelector refers to also specify the binding.  The DataContext of each DataTemplate returned via the CellTemplateSelector will be the row level object - NOT the binding that is associated with the column.
     
    3. On requiring the CellTemplateSelector to be re-evaluated, the property that the column is bound to needs to fire a PropertyChanged event (INotifyPropertyChanged pattern) - EVEN IF IT HASN'T CHANGED.  This is a little bit messy because if you are triggering some other logic off that event firing, it is going to get tripped incorrectly.  I guess that needs to be managed manually.

    If you follow this approach, the CellTemplateSelector will re-fire.  This approach is quite nice in that it all feeds off the underlying data and changes that occur on it, but I can't help but feel that it would be nice if there was a more direct way to force column actions (such as sorting, grouping, and template selectors) rather than tricking the grid into thinking the data has changed.  Perhaps a direct call on the RadGridView - eg, something like RadGridView.InvalidateColumn(string columnName) with some overloads to restrict impacted rows.

    Anyway, thanks Vlad.  Your help was much appreciated.

    Cheers
    Nathan
  8. Reza
    Reza avatar
    1 posts
    Member since:
    Nov 2011

    Posted 29 Jan 2012 Link to this post

    u dont need to use this above troblesome method to your purpose. just use cellstyleSelector instead . cellstyleSelectors will be called on  propertyChanged of any property of an item(if item type has been generated at clinet using ria services ,or has been implemented INotifyPropertyChanged interface somehow). just set your TargetType of style tag "telerik:GridViewCell" and set the "ContentTemplate" property using setter tag to a DataTemplate comprised of any control u wish.
    . xaml example:

     

     

     

     

    <styles:TrainingCoursesResultCellStyle x:Key="trainingCoursesResultCellStyle">
            <styles:TrainingCoursesResultCellStyle.IsReadOnly>
                <Style TargetType="telerik:GridViewCell" >
                    <Setter Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <CoreControls:LabeledCombo LableWidth="0" IsReadOnly="True" SelectedValue="{Binding Result,Mode=TwoWay}" ItemsSource="{StaticResource ResultsSRLOR}" DisplayMemberPath="Name" SelectedValuePath="BaseValueID"/>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </styles:TrainingCoursesResultCellStyle.IsReadOnly>
            <styles:TrainingCoursesResultCellStyle.IsNotReadOnly>
                <Style TargetType="telerik:GridViewCell" >
                    <Setter Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <CoreControls:LabeledCombo LableWidth="0" IsReadOnly="False" SelectedValue="{Binding Result,Mode=TwoWay}" ItemsSource="{StaticResource ResultsSRLOR}" DisplayMemberPath="Name" SelectedValuePath="BaseValueID"/>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </styles:TrainingCoursesResultCellStyle.IsNotReadOnly>
        </styles:TrainingCoursesResultCellStyle>

    as u can see in this example we've got two styles, one makes a customed comboBox readOnly anotherone makes the same but with IsReadOnly attribute set to false.

    Reza

  9. Doug
    Doug avatar
    30 posts
    Member since:
    Feb 2005

    Posted 14 Mar 2012 Link to this post

    Reza,

    Your comments on using CellStyleSelector instead of CellTemplateSelector is awesome!  I was having a refresh problem similar to the OP and after replacing the template selector with a style selector, BAM, it started refreshing as I would expect.

    Thanks for posting the alternative solution!

    -Doug-
Back to Top