wpfxamlmvvmcode-behinddynamicresource

How to change DynamicResource in WPF


I have a UserControl with that XAML:

<StackPanel>
    <Label HorizontalContentAlignment="Center">
        <Rectangle Name="iconContainer" Height="120" Width="120" Fill="#FF045189">
            <Rectangle.OpacityMask>
                <VisualBrush Visual="{DynamicResource appbar_disconnect}"/>
            </Rectangle.OpacityMask>
        </Rectangle>
    </Label>
    <TextBlock Name="tBlockPortStatus" Foreground="#FF7C7676" FontWeight="Bold" FontSize="15" Margin="3" TextAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap">PORT STATUS (Testing wrapping text abilities for this control)</TextBlock>
</StackPanel>

I need to change the icon(named appbar_disconnect) and use another DynamicResource (ex. appbar_connect) using Code Behind or MVVM. How can I achieve this? Regards


Solution

  • Your case looks like it would be better handled using a Trigger than a DynamicResource, but if you insisted on using DynamicResource, you basically need to define your states' icons/images as resources in the App.xaml file:

     <Application.Resources>
        <Image Source="Icons/disconnect.png" x:Key="AppbarDisconnect"/>
        <Image Source="Icons/connect.png" x:Key="AppbarConnect"/>
        <Image Source="Icons/undefined.png" x:Key="AppbarStatus"/>
    </Application.Resources>
    

    Assuming your UserControl looks like that:

    <StackPanel>
        <Label HorizontalContentAlignment="Center">
            <Rectangle Name="IconContainer" Height="120" Width="120" Fill="#FF045189">
                <Rectangle.OpacityMask>
                    <VisualBrush Visual="{DynamicResource AppbarStatus}"/>
                </Rectangle.OpacityMask>
            </Rectangle>
        </Label>
        <TextBlock Name="TBlockPortStatus" Foreground="#FF7C7676" FontWeight="Bold" FontSize="15" Margin="3" TextAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap">PORT STATUS (Testing wrapping text abilities for this control)</TextBlock>
    </StackPanel>
    

    You could update the AppbarStatus resource on a specific event (from the code behind or from the viewmodel) like so:

    Application.Current.Resources["AppbarStatus"] = Application.Current.Resources["AppbarDisconnect"];
    

    Update

    In case you want to use a DataTrigger, just add a property to hold the connection-status to your user control:

    private bool _connetionStatus;
        public bool ConnectionStatus
        {
            get { return _connetionStatus; }
            set
            {
                if (value == _connetionStatus) return;
                _connetionStatus = value;
                OnPropertyChanged();
            }
        }
    

    The DataTrigger should be self explanatory:

     <StackPanel>
            <Label HorizontalContentAlignment="Center">
                <Rectangle Name="IconContainer" Height="120" Width="120" Fill="#FF045189">
                    <Rectangle.Style>
                        <Style TargetType="Rectangle">
                            <Setter Property="OpacityMask">
                                <Setter.Value>
                                    <VisualBrush Visual="{DynamicResource AppbarDisconnect}"/>
                                </Setter.Value>
                            </Setter>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding ConnectionStatus}" Value="true">
                                    <Setter Property="OpacityMask">
                                        <Setter.Value>
                                            <VisualBrush Visual="{DynamicResource AppbarConnect}"/>
                                        </Setter.Value>
                                    </Setter>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Rectangle.Style>
    
                </Rectangle>
            </Label>
            <TextBlock Name="TBlockPortStatus" Foreground="#FF7C7676" FontWeight="Bold" FontSize="15" Margin="3" TextAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap">PORT STATUS (Testing wrapping text abilities for this control)</TextBlock>
        </StackPanel>