Adding Resource to GVRowItem dynamically in RowLoaded

6 posts, 0 answers
  1. Kinjal
    Kinjal avatar
    12 posts
    Member since:
    Jan 2007

    Posted 27 Aug 2010 Link to this post

    Hi,

    I have a need of supplying some formatting info for each row based on certain criteria. This formatting info is not main data so, it doesn't make sense to set the formatInfo object as DataContext.

    My idea was/is to add appropriate formatInfo object to Resource of current row (effectively, adding a key-object to e.Row.Resources, say 'formatObject' as key, and object of formatInfo based on the criteria) in RowLoaded event handler.
    I wanted to make use of the added Resource 'formatObject' in Row Template. But due to the resulted error it seems that the template is used before RowLoaded event gets opportunity to add the resource.

    What is proper way to supply 'StaticResource' to row dynamically.?
    ________________________________________________________________________________________
    Part II of the story:

    Without setting binding to 'formatObject' in the template, is wrote code to add the formatInfo object to Resources. It failed with strange error.

    Following is code in the event handler, so we are on same page if the description is not good enough.
    if (!(e.Row is GridViewHeaderRow))
    {
        if (e.DataElement != null)
        {
            if (e.Row.Resources.Contains("formatObject"))
                e.Row.Resources["formatObject"] = ((Result)e.DataElement).Pass ? formatInfoPass : formatInfoFail;
            else
                e.Row.Resources.Add("formatObject", ((Result)e.DataElement).Pass ? formatInfoPass : formatInfoFail);
        }
    }

    The error is, 'Element is already the child of another element.' for the second row.
    Interestingly, on line, "e.Row.Resources.Add("formatObject", ((Result)e.DataElement).Pass ? formatInfoPass : formatInfoFail);"
    that is to say, that e.Row.Resources.Contains("formatObject") resulted false. (by the way, the Resources collection count was 0)


    I tried doing something similar, and it worked.
    <Button Width="100" Height="25" x:Name="b1">
        <Button.Resources>
            <SolidColorBrush x:Key="CurrentBackground" Color="Green"></SolidColorBrush>
        </Button.Resources>
        <Button.Content>
            <StackPanel Background="{StaticResource CurrentBackground}">
                <TextBlock Text="Button111"></TextBlock>
            </StackPanel>
        </Button.Content>
    </Button>
    <Button Width="100" Height="25" x:Name="b2">
        <Button.Resources>
            <SolidColorBrush x:Key="CurrentBackground" Color="Orange"></SolidColorBrush>
        </Button.Resources>
        <Button.Content>
            <StackPanel Background="{StaticResource CurrentBackground}">
                <TextBlock Text="Button2"></TextBlock>
            </StackPanel>
        </Button.Content>
    </Button>


    Please do let me know if anything is unclear.

    Regards,
    Kinjal
  2. Milan
    Admin
    Milan avatar
    1989 posts

    Posted 27 Aug 2010 Link to this post

    Hi Kinjal,

    Have you look at our Style and Template selectors which allow you to customize the UI using your custom logic. 


    Regards,
    Milan
    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. DevCraft banner
  4. Kinjal
    Kinjal avatar
    12 posts
    Member since:
    Jan 2007

    Posted 27 Aug 2010 Link to this post

    Hi Milan,

    Thanks for quick response. Sorry, by the way i was updating my question a bit while you already answered it. (please have a look at refined version of the previous post)

    Yes earlier i read about Style Selector, and i was happy that this would be solution to my problem.

    But soon i found that it is slightly complicated. In my case, i want rows to have style bindings to an object which has
    a> some common formatting properties, [say FontFamily etc] and
    b> list of row-formatting-info [say Row Background]

    So there is an indexer to which i got to pass index dynamically. [Otherwise i will end up with ten version of row-styles where everything is same other than index in the indexers. Development will be bad, and Maintenance will be very bad].

    I wanted to keep the thread isolated from this complexity so i manipulated the code in first post and presented simpler version, but now as we are talking about it, here is the sample binding.

    Background="{Binding Path=[resultSheetFormattingInfoObject].gradeFormattingInfo[0].BackgroundBrush, Source={StaticResource GenericObserveableDictionary}}"

    say if i am to prepare style (to be eventually selected by StyleSelector), i have to duplicate basically the same style/template for each grade like:

    Background="{Binding Path=[resultSheetFormattingInfoObject].gradeFormattingInfo[1].BackgroundBrush, Source={StaticResource GenericObserveableDictionary}}"

    Background="{Binding Path=[resultSheetFormattingInfoObject].gradeFormattingInfo[2].BackgroundBrush, Source={StaticResource GenericObserveableDictionary}}"

    Background="{Binding Path=[resultSheetFormattingInfoObject].gradeFormattingInfo[3].BackgroundBrush, Source={StaticResource GenericObserveableDictionary}}"

    and so on.. Because we cannot pass the dynamic indexer (a pointer to a field, or static resource etc) in PropertyPath.

    After eliminating these approaches, i came to idea of adding appropriate gradeFormattingInfo to Resources of rows (my previous post). This is similar to StyleSelector code, but more in RowLoaded event.

    Please share your ideas. And do let me know if you wish more description of any of the aspect.

    Regards,
    Kinjal.
  5. Milan
    Admin
    Milan avatar
    1989 posts

    Posted 03 Sep 2010 Link to this post

    Hi Kinjal,

    Excuse me for the delay. 

    I believe that there should be no problem implementing this functionality using the RowLoaded event. For example, you can setup the binding in the row loaded event like this:

    void playersGrid_RowLoaded(object sender, Telerik.Windows.Controls.GridView.RowLoadedEventArgs e)
    {
        var row = e.Row as GridViewRow;
      
        if (row != null)
        {
            var player = row.Item as Player;
            var backgroundBinding = new Binding();
            // this is similar to GenericObserveableDictionary
            backgroundBinding.Source = this.Resources["MyViewModel"];
      
            if (player.Position == Position.DF)
            {
                backgroundBinding.Path = new PropertyPath("BackgroundBrushes[0]");
            }
            else
            {
                backgroundBinding.Path = new PropertyPath("BackgroundBrushes[1]");
            }
      
            row.SetBinding(GridViewRow.BackgroundProperty, backgroundBinding);
        }
    }

    Another possibility is to use dynamically built styles. You can define a generic style like the following one and add it to the application as a resource:

    <Style x:Key="HighUnitPriceStyle" TargetType="telerik:GridViewRow">
                 <Setter Property="Background" Value="#stringToReplace#" />
    </Style>

    When you need to create a concrete style (in the StyleSelector) you load the style as string and replace "#stringToReplace#" with a corresponding value. In your case this will be the binding text. The replace will result in a string similar to this:

    <Style x:Key="HighUnitPriceStyle" TargetType="telerik:GridViewRow"
                 <Setter Property="Background" Value="Red" /> 
    </Style>

    Then you can transform this string into a style using XamlReader.Load and return the style using your Style Selector.

    Kind regards,

    Milan
    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
  6. Kinjal
    Kinjal avatar
    12 posts
    Member since:
    Jan 2007

    Posted 08 Sep 2010 Link to this post

    Hello Milan,

    Thanks for the reply.

    Since couple of days i was working on other tasks. Hence the delay, sorry.

    Regarding first part of your reply (the code in RowLoaded event handler), i think it is opposite to what i wanted to do.
    I want to add one object to Resources of the 'current' Row object (e.Row as in my first post in this thread).

    One thing i didn't get in second part (dynamic string replacement of setter values) is that how you mean to load styles from application resources as a string?

    Please let me know if anything is unclear.

    Good day!

    Regards,
    Kinjal.
  7. Milan
    Admin
    Milan avatar
    1989 posts

    Posted 14 Sep 2010 Link to this post

    Hi Kinjal,

    Excuse me for the delay as well. 

    I proposed the new RowLoaded event approach since the approach where you add to the Resources collection might be tricky and more difficult. Won't you be able to achieve the desired result following this approach?

    As for the second part of my previous reply, here is some more info about this approach:

    Imagine that this string represents a generic style/template that you are going to use:

    <Style x:Key="HighUnitPriceStyle" TargetType="telerik:GridViewRow"
                 <Setter Property="Background" Value="#stringToReplace#" /> 
    </Style>

    This generic style can be stores as string in in the application. For example:

    public const string GenericStyle = 
        "<Style x:Key=\"HighUnitPriceStyle\" TargetType=\"telerik:GridViewRow\">" +
         "<Setter Property=\"Background\" Value=\"stringToReplace#\" /></Style>";

    Ultimately the selector should look something like this:

    public class MySelector : StyleSelector
    {
        public const string GenericStyle =
            "<Style x:Key=\"HighUnitPriceStyle\" TargetType=\"telerik:GridViewRow\">" +
             "<Setter Property=\"Background\" Value=\"#stringToReplace#\" /></Style>";
      
        public override Style SelectStyle(object item, DependencyObject container)
        {
            var player = item as Player;
      
            if (player.Position == Position.DF)
            {
                return CreateStyle("Red");
            }
            else
            {
                return CreateStyle("Blue");
            }
        }
      
        private Style CreateStyle(string backgoundValue)
        {
            var styleString = GenericStyle.Replace("#stringToReplace#", backgoundValue);
            var style = XamlReader.Load(styleString) as Style;
      
            return style;
        }
    }


    All the best,
    Milan
    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
Back to Top
DevCraft banner