Search code examples
c#wpfcustom-controlscontroltemplatedatatrigger

Fired datatrigger is not changing custom control's property(ControlTemplate)


I Want to change a DependcyProperty(Named is as MessageTemplateProperty) which is in CustomControl and Type is Controltemplate .

But I can't set the value to it using datatrigger

But another DependcyProperty(named as IsShowMessageProperty) which is in CustomControl and Type is bool can be set using datatrigger.

Who can explain it ,Why, and How to solve it.

The Custom Code as follow:

public class MessageOverLay : ContentControl
{
    static MessageOverLay()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MessageOverLay),
            new FrameworkPropertyMetadata(typeof(MessageOverLay)));
    }

    #region DependcyProperties

    // Template attached property

    public static readonly DependencyProperty MessageTemplateProperty =
        DependencyProperty.Register("MessageTemplate", typeof(ControlTemplate), typeof(MessageOverLay),
            new FrameworkPropertyMetadata(MessageTemplateChanged));

    public ControlTemplate MessageTemplate
    {
        set{SetValue(MessageTemplateProperty, value);}
        get{return (ControlTemplate)GetValue(MessageTemplateProperty);}
     }

    // IsVisible attached property

    public static readonly DependencyProperty IsShowMessageProperty =
        DependencyProperty.Register("IsShowMessage", typeof(bool), typeof(MessageOverLay),
            new PropertyMetadata(IsShowMessageChanged));

    public bool IsShowMessage
    {
        get{return (bool)GetValue(IsShowMessageProperty);}
        set{SetValue(IsShowMessageProperty, value);}
    }


    #endregion DependcyProperties



}

The Custom Default Theme Generic.xaml

 <Style TargetType="{x:Type controls:MessageOverLay}">
      <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:MessageOverLay">
                <AdornerDecorator>
                    <Grid>
                        <ContentPresenter  x:Name="PART_Conent"
                                        VerticalAlignment="Stretch"
                                        HorizontalAlignment="Stretch"

                                         Content="{TemplateBinding Content}" />
                        <Control x:Name="Part_MessageControl" Template="{TemplateBinding MessageTemplate}" 
                                 Visibility="{TemplateBinding IsShowMessage,Converter={StaticResource BooleanToVisibilityConverter}}" />
                    </Grid>
                </AdornerDecorator>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="MessageTemplate">
        <Setter.Value>
            <ControlTemplate>
                <Grid HorizontalAlignment="Left" VerticalAlignment="Bottom">
                    <Grid Width="150" Height="100" Margin="5  0 0 10">
                        <Rectangle Stroke="Black" Fill="Yellow" RadiusX="6" RadiusY="6" Margin="0 20 0 0" />
                        <TextBlock Text="What are you doing?" Margin="5 25 0 0" />
                        <Button Content="Cancel" Margin="5" VerticalAlignment="Bottom" HorizontalAlignment="Right" />
                        <Button Content="OK" Margin="5" VerticalAlignment="Bottom" HorizontalAlignment="Left" />
                    </Grid>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

I Want to use it as follow:

Demo XAML:

  <Window ...>
<Window.Resources>
    <ControlTemplate x:Key="GenderPopupTemplate">
        <Grid HorizontalAlignment="Left" VerticalAlignment="Bottom">
            <Grid Width="200" Height="100" Margin=" 5 0 0 10">              
                <TextBlock Text="Please Select Gender " Margin="5 25 0 0" />
                <Button Content="Male" Margin="5" VerticalAlignment="Bottom" HorizontalAlignment="Left"
                        Command="{Binding SelectedGenderCommand}" />
                <Button Content="FeMale" Margin="5" VerticalAlignment="Bottom" HorizontalAlignment="Right"
                        Command="{Binding SelectedGenderCommand}" />
            </Grid>
        </Grid>
    </ControlTemplate>

    <ControlTemplate x:Key="FacePopupTemplate">
        <Grid HorizontalAlignment="Left" VerticalAlignment="Bottom">
            <Grid Width="200" Height="100" Margin="5 10 0 0">
                <TextBlock Text="Do you like your Face,Now?" Margin="5 25 0 0" />
                <Button Content="OK" Margin="5" VerticalAlignment="Bottom" HorizontalAlignment="Left"
                        Command="{Binding OKCommand}" />
            </Grid>
        </Grid>
    </ControlTemplate>
</Window.Resources>

    <controls:MessageOverLay  HorizontalAlignment="Stretch"
                              VerticalAlignment="Stretch"
                              MessageTemplate="{StaticResource GenderPopupTemplate}"
                             IsShowMessage="True">
        <controls:MessageOverLay.Style>
            <Style TargetType="{x:Type controls:MessageOverLay}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding MessageBoxType}" Value="{x:Static viewModels:MessageBoxTypes.SelectView}">
                        <Setter Property="MessageTemplate" Value="{StaticResource GenderPopupTemplate}"></Setter>
                        <Setter Property="Height" Value="350"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding MessageBoxType}" Value="{x:Static viewModels:MessageBoxTypes.MessageView}">
                        <Setter Property="MessageTemplate" Value="{StaticResource FacePopupTemplate}"></Setter>
                        <Setter Property="Height" Value="150"/>
                    </DataTrigger>

                </Style.Triggers>
            </Style>
        </controls:MessageOverLay.Style>
        <Grid  Background="SeaGreen" 
               HorizontalAlignment="Stretch"
                              VerticalAlignment="Stretch">
            <TextBlock Text="Content"/>
        </Grid>
    </controls:MessageOverLay>

I want to change the MessageTemplate when the Propery MessageBoxType of MainWindowViewModel changed. But I can't archive it.

The other related code

Demo C# Code:

public class MainWindowViewModel : BindableBase
{
    public ICommand SelectedGenderCommand { get; }

    public ICommand OKCommand { get; }

    private MessageBoxTypes _messageBoxType;

    public MessageBoxTypes MessageBoxType
    {
        get { return _messageBoxType; }
        set { SetProperty(ref _messageBoxType, value); }
    }

    private string _title = "Prism Unity Application";

    public string Title
    {
        get { return _title; }
        set { SetProperty(ref _title, value); }
    }

    public MainWindowViewModel()
    {
        MessageBoxType = MessageBoxTypes.SelectView;

        SelectedGenderCommand = new DelegateCommand<object>(SelectedGender);

        OKCommand = new DelegateCommand<object>(OK);
    }

    private void OK(object obj)
    {
        MessageBoxType = MessageBoxTypes.SelectView;
    }

    private void SelectedGender(object obj)
    {
        MessageBoxType = MessageBoxTypes.MessageView;
    }
}

public enum MessageBoxTypes
{
    SelectView,
    MessageView,
    ConfirmView
}

Update:

Here is the full demo code in github ,Please check it.


Solution

  • When a dependency property is to be set by a Style Setter, there must be no direct assignment of a so-called local value, as you do in

    <controls:MessageOverLay MessageTemplate="{StaticResource GenderPopupTemplate}" ...>
    

    The directly assigned local value always has higher precedence than any value from Style Setters (and other possible sources), so that the Setter has no effect. More details can be found here: Dependency Property Value Precedence.

    Replace the direct assignment be another Style Setter:

     <controls:MessageOverLay  ...>
        <controls:MessageOverLay.Style>
            <Style TargetType="{x:Type controls:MessageOverLay}">
    
                <Setter Property="MessageTemplate"
                        Value="{StaticResource GenderPopupTemplate}"/>
    
                <Style.Triggers>
                    ...
                </Style.Triggers>
            </Style>
        </controls:MessageOverLay.Style>
        ...
    </controls:MessageOverLay>