locked
Modify a resource dictionary element from code and update UI RRS feed

  • Question

  • Hi,

    In my application, I have a resource disctionary which I have places in a dll. In this dll, I have added few colors in the ResourceDictionary.

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
                        
    
        <SolidColorBrush x:Key="StatusTrue" Color="Red"/>
        <SolidColorBrush x:Key="StatusFalse" Color="Green"/>
        
    </ResourceDictionary>


    I have a userControl in which I want to update the color which is binded to a ListBoxItem background color.

    <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Border Name="border"                             AllowDrop="False" >
                            <Border.Style>
                                <Style TargetType="Border">
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding State, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="False" >
                                            <Setter Property="Background" Value="{StaticResource StatusFalse}"/>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding State, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True" >
                                            <Setter Property="Background" Value="{StaticResource StatusTrue}"/>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Border.Style>

    Now on some color selection from user, I am changing the color in the resource dictionary. This new color is getting updated in the resource dictionary also but UI is not getting updated.

    ResourceDictionary myResourceDictionary = default(ResourceDictionary);
    
            public SolidColorBrush SetInResourceDictionary(string colorParam, Color colorValue)
            {
                SolidColorBrush brush = default(SolidColorBrush);
    
                try
                {
                    if (myResourceDictionary == null)
                    {
                        myResourceDictionary = new ResourceDictionary();
                    }
    
                    myResourceDictionary.Source =
                        new Uri("/myResourcesDll;component/ColorResourceDictionary.xaml",
                                UriKind.RelativeOrAbsolute);
                    myResourceDictionary[colorParam] = (GetColorBrush(colorValue) as SolidColorBrush);
                    brush = (SolidColorBrush)myResourceDictionary[colorParam];
                }
                catch (Exception exp)
                {
                    MessageBox.Show(exp.Message + exp.StackTrace);
                }
    
                return brush;
            }

    What mistake I am doing here?

    Thanks,

    IamHuM

    Friday, May 15, 2015 1:27 PM

Answers

  • >>Is there any other way to handle this?

    No, you need to modify the very same resource that has been added and applied to the UserControl. You cannot modify some other instance of the resource.

    >>Also the ResourceDictioney object added in mergedDictionary and the new ResourceDictionry created in the 'SetInResourceDictionary' method will be the same object right?

    No, you are creating a new ResourceDictionary in the 'SetInResourceDictionary' method. This is not the same one as you define in the XAML markup.

    So you have to add a new ResourceDictionary to the Resources.MergedDictionaries of the UC or change the resource as I showed you in my previous post:

    this.Resources["StatusFalse"] = Brushes.Yellow;

    Calling some method in another assembly that does something with some other instance of the ResourceDictionary or resource won't work here. You need override or operate on the resource that is used by the UC and the only way to do this is to add a new ResourceDictionay to the UC or change the resource itself as described above.

    Please close the your thread by marking all helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread and please don't ask the same question twice.

    • Proposed as answer by Xavier Xie-MSFT Thursday, May 21, 2015 7:50 AM
    • Marked as answer by Barry Wang Friday, May 22, 2015 1:38 AM
    Saturday, May 16, 2015 7:59 AM

All replies

  • Use the DynamicResource markup extension if you want to be able to update the Background at runtime:

    <Setter Property="Background" Value="{DynamicResource StatusFalse}"/>

    A StaticResource will be resolved and assigned to the property during the loading of the XAML. It will only be assigned once and any changes to resource dictionary ignored:
    http://stackoverflow.com/questions/200839/whats-the-difference-between-staticresource-and-dynamicresource-in-wpf

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Friday, May 15, 2015 2:24 PM
  • Try DynamicResource rather than StaticResource.

    StaticResource is read once.

    <DataTrigger Binding="{Binding State, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True" >
               <Setter Property="Background" Value="{DynamicResource StatusTrue}"/>
    </DataTrigger>

    You also have to be a bit careful setting the brush in the resourcedictionary.

    This works:

    Application.Current.Resources["PossibleErrorBrush"] = Application.Current.Resources["PossibleErrorOKBrush"];


    Hope that helps.

    Technet articles: Uneventful MVVM; All my Technet Articles

    Friday, May 15, 2015 2:25 PM
  • Thanks the response.

    I tried with DynamicResource also but still giving me the same issue. Does creating a new ResourceDictionary object will create any issue here.

    myResourceDictionary = new ResourceDictionary();

    I mean will it create another instance of the ResourceDictionary which is different than what I created in the UserControl XAML?

    <UserControl.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary x:Name="colorResources" Source="pack://application:,,,/myResourcesDll;component/ColorResourceDictionary.xaml"></ResourceDictionary>
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
    </UserControl.Resources>

    What can be the issue...?

    Thanks,

    IamHuM

    Friday, May 15, 2015 5:43 PM
  • You need to add the new ResourceDictionary that contains the new resources with the same x:Key attributes to the same UserControl:

    ResourceDictionary myResourceDictionary = new ResourceDictionary();
                        myResourceDictionary.Source =
                            new Uri("dict.xaml",
                                    UriKind.RelativeOrAbsolute);
                        myResourceDictionary["StatusFalse"] = Brushes.Black; //change resource
                        this.Resources.MergedDictionaries.Add(myResourceDictionary);

    Otherwise the resources that are defined in the resource dictionary that is defined in the XAML markup of the UserControl will take precedence over any other resources with same keys.

    Or you could just override the value of the resource directly in the UC:

    this.Resources["StatusFalse"] = Brushes.Yellow;

    Please remember to mark helpful posts as answer and then start a new thread if you have a new question.

    Friday, May 15, 2015 6:21 PM
  • Magnus,

    Actually I have created a separate dll 'myResourcesDll' to store the resources in resource dictionary. The UserControl where I am using this ResourceDictionary is in another application assembly 'MyApp.exe'.

    This method 'SetInResourceDictionary' which I am using to update the color in the ResourceDictionary is also present in the 'myResourcesDll'.

    I want to avoid setting these colors in the UserControl code .cs files. Is there any other way to handle this?

    Also the ResourceDictioney object added in mergedDictionary and the new ResourceDictionry created in the 'SetInResourceDictionary' method will be the same object right?

    Thanks in advance,

    IamHuM


    • Edited by IamHuM Saturday, May 16, 2015 6:09 AM More Info
    Saturday, May 16, 2015 5:51 AM
  • >>Is there any other way to handle this?

    No, you need to modify the very same resource that has been added and applied to the UserControl. You cannot modify some other instance of the resource.

    >>Also the ResourceDictioney object added in mergedDictionary and the new ResourceDictionry created in the 'SetInResourceDictionary' method will be the same object right?

    No, you are creating a new ResourceDictionary in the 'SetInResourceDictionary' method. This is not the same one as you define in the XAML markup.

    So you have to add a new ResourceDictionary to the Resources.MergedDictionaries of the UC or change the resource as I showed you in my previous post:

    this.Resources["StatusFalse"] = Brushes.Yellow;

    Calling some method in another assembly that does something with some other instance of the ResourceDictionary or resource won't work here. You need override or operate on the resource that is used by the UC and the only way to do this is to add a new ResourceDictionay to the UC or change the resource itself as described above.

    Please close the your thread by marking all helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread and please don't ask the same question twice.

    • Proposed as answer by Xavier Xie-MSFT Thursday, May 21, 2015 7:50 AM
    • Marked as answer by Barry Wang Friday, May 22, 2015 1:38 AM
    Saturday, May 16, 2015 7:59 AM
  • The resource dictionaries are pulled into memory and stored in a sort of a dictionary in application.current.resources when you do that merging in app.xaml.

    These are not synonymous, application.current.resources is the product of merging rather than the same resource dictionary. ( Totally different things.)

    That is what is used when you use a dynamic or static resource.

    This is used by everything pulled into memory by an exe.

    Let's call this the main.exe so at least I know what I'm talking about.

    Main.exe is the entry point, the thing that is running and the thing containing app.xaml which will merge resource dictionaries.

    If you want to switch stuff around you do the equivalent of:

    Application.Current.Resources["DynamicResourceKey"] = Application.Current.Resources["PossibleErrorOKBrush"];

    Note

    You don't change the whatever in a resource dictionary, you change it in application.current.resources. 

    The control doesn't know about resource dictionaries, it knows about the product of them which is merged into application.resources.

    If you merge two resource dictionaries which both have the same key then you end up with one entry in there, with the value of the second resource dictionary.


    Hope that helps.

    Technet articles: Uneventful MVVM; All my Technet Articles


    Saturday, May 16, 2015 8:00 AM