Axel Bouttelgier
Axel Bouttelgier

Reputation: 173

wpf ResourceDictionary not applied to ContentControl

I have a wpf application, here i've made a contentcontroller that has a label and a button. this will be used as an overlay when something is loading. the .cs file

namespace VLC.WPF.Controls
{
    public class LoadingOverlay : ContentControl
    {
    }
}

the .xaml file

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:VLC.WPF.Controls">
    <Style TargetType="local:LoadingOverlay">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid>
                        <Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
                            <ContentPresenter Content="{Binding OverlayContent}"/>
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>

        </Setter>
    </Style>
</ResourceDictionary>

all of this will be used like this

<UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/../Controls/LoadingOverlay.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>

    <controls:LoadingOverlay>
        <controls:LoadingOverlay.Resources>
            <Style TargetType="controls:LoadingOverlay">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted}" Value="True">
                        <Setter Property="Visibility" Value="Hidden"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </controls:LoadingOverlay.Resources>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                <TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
                <Button x:Name="Cancel" Content="Annuleren"/>
            </StackPanel>
    </controls:LoadingOverlay>

in various usercontrols, it's functioning correctly but the styly doesn't appear to load.

What could be wrong here? the code looks alright so i think it should be loading but it isn't.

Upvotes: 0

Views: 940

Answers (3)

trippedOverXaml
trippedOverXaml

Reputation: 171

in your style try adding the TargetType to your ControlTemplate like this

<ControlTemplate TargetType="local:LoadingOverlay">

What I don't understand is why are you setting the styling in the UserControl Resources and not using Keys to reference styles in your ResourceDictionary. It would keep your overall code much cleaner and you wouldn't have to change each control if you have to make a minor change later... for example:

<Style x:Key="overlayOne" TargetType="local:LoadingOverlay">
    <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="local:LoadingOverlay">
            <Grid>
              <Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
                 <ContentPresenter Content="{Binding OverlayContent}"/>
              </Grid>
            </Grid>
         </ControlTemplate>
       </Setter.Value>
      </Setter>
    <Style.Triggers>
      <DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
         <Setter Property="Visibility" Value="Hidden"/>
      </DataTrigger>
    </Style.Triggers>
</Style>

And when you call the control in your page

<local:LoadingOverlay Style="{DynamicResource overlayOne}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
            <Button x:Name="Cancel" Content="Annuleren"/>
        </StackPanel>
</local:LoadingOverlay>

and if you find you need to alter the style for another page, instead of doing an inline style for the control - after the originally defined style try this:

<Style x:Key="overlayTwo" TargetType="local:LoadingOverlay" BasedOn="{StaticResource overlayOne}">
     <Style.Triggers>
        <DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
           <Setter Property="Background" Value="Green"/>
        </DataTrigger>
      </Style.Triggers>
</Style>

This style uses all the information you have already defined and adds another data trigger, or you could override what is there, change other elements in style such the font size or colors.

Then, you just have to use this key when defining your control

<local:LoadingOverlay Style="{DynamicResource overlayTwo}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
            <Button x:Name="Cancel" Content="Annuleren"/>
        </StackPanel>
</local:LoadingOverlay>

Sorry for the long winded answer, but I see this being a potential problem if you have a lot of these controls on different pages and by not keeping all of your styling in the ResourceDictionary

P.S. If your content is going to be the same that could also be part of the style like below

<Style x:Key="overlayOne" TargetType="local:LoadingOverlay">
    <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="local:LoadingOverlay">
            <Grid>
              <Grid Background="Black" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.8">
                 <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
            <Button x:Name="Cancel" Content="Annuleren"/>
        </StackPanel>
              </Grid>
            </Grid>
         </ControlTemplate>
       </Setter.Value>
      </Setter>
    <Style.Triggers>
      <DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted, RelativeSource={RelativeSource Self}} Value="True">
         <Setter Property="Visibility" Value="Hidden"/>
      </DataTrigger>
    </Style.Triggers>
</Style>

And then you only need on your page

<local:LoadingOverlay Style="{DynamicResource overlayOne}"/>

Upvotes: 1

Amaury Lev&#233;
Amaury Lev&#233;

Reputation: 1512

You actually override the style within the LoadingOverlay resources.

Replace <Style TargetType="controls:LoadingOverlay"> by the following <Style TargetType="{x:Type controls:LoadingOverlay}" BasedOn="{StaticResource {x:Type controls:LoadingOverlay}}"> and voila!

Upvotes: 1

Glen Thomas
Glen Thomas

Reputation: 10764

The resource must be defined before the UI element that will be using it. If a control uses a style resource, that style must be higher in the visual tree.

Move the style to the UserControl resources

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/../Controls/LoadingOverlay.xaml"/>
        </ResourceDictionary.MergedDictionaries>
        <Style TargetType="controls:LoadingOverlay">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=RefreshNotifyTask.IsCompleted}" Value="True">
                    <Setter Property="Visibility" Value="Hidden"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</UserControl.Resources>

<controls:LoadingOverlay>
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
        <TextBlock Foreground="White" FontSize="20" Text="Artikelen vernieuwen ..." />
        <Button x:Name="Cancel" Content="Annuleren"/>
    </StackPanel>
</controls:LoadingOverlay>

Upvotes: 0

Related Questions