Reputation: 25
I'm working on a CustomControl in WPF. I want to Implement a CardControl. I have two Contents "Front" and "Back" and I want to flip between them. But I can't define a Working Trigger in the Style to flip between the contents...
First I created a Custom Control, with DependencyProperties:
public class Card : Control {
#region initializer
static Card() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(Card), new FrameworkPropertyMetadata(typeof(Card)));
}
#endregion
#region dependencyProperties
public FrameworkElement CustomContent {
get { return (FrameworkElement)GetValue(CustomContentProperty); }
set { SetValue(CustomContentProperty, value); }
}
public static DependencyProperty CustomContentProperty =
DependencyProperty.Register(nameof(CustomContent), typeof(FrameworkElement), typeof(Card), new PropertyMetadata());
public FrameworkElement Front {
get { return (FrameworkElement)GetValue(FrontProperty); }
set { SetValue(FrontProperty, value); }
}
public static DependencyProperty FrontProperty =
DependencyProperty.Register(nameof(Front), typeof(FrameworkElement), typeof(Card), new PropertyMetadata());
public FrameworkElement Back {
get { return (FrameworkElement)GetValue(BackProperty); }
set { SetValue(BackProperty, value); }
}
public static DependencyProperty BackProperty =
DependencyProperty.Register(nameof(Back), typeof(FrameworkElement), typeof(Card), new PropertyMetadata());
public bool IsDetailed {
get { return (bool)GetValue(IsDetailedProperty); }
set { SetValue(IsDetailedProperty, value); }
}
public static readonly DependencyProperty IsDetailedProperty =
DependencyProperty.Register(nameof(IsDetailed), typeof(bool), typeof(Card), new PropertyMetadata(false));
public CornerRadius CornerRadius {
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(Card));
#endregion
Then I defined the Style in Generic.xaml:
<Style TargetType="{x:Type local:Card}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Card}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:Card}}, Path=CustomContent,
Converter={StaticResource Debugger}, UpdateSourceTrigger=PropertyChanged}"/>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource
AncestorType={x:Type local:Card}},
Path=isDetailed,
Converter={StaticResource Debugger}}"
Value="True">
<Setter Property="CustomContent"
Value="{Binding RelativeSource={RelativeSource
AncestorType={x:Type local:Card}},
Path=Back}"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource
AncestorType={x:Type local:Card}},
Path=isDetailed}"
Value="False">
<Setter Property="CustomContent"
Value="{Binding RelativeSource={RelativeSource
AncestorType={x:Type local:Card}},
Path=Front}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And I Implemented a Simple CardControl for Test-Purposes with a Button, which flips the isDetailed state:
<StackPanel>
<CustomCharts:Card Name="TestCard">
<CustomCharts:Card.CustomContent>
<TextBlock Text="Hello World!"/>
</CustomCharts:Card.CustomContent>
<CustomCharts:Card.Front>
<TextBlock Text="Wow vordere sache!"/>
</CustomCharts:Card.Front>
<CustomCharts:Card.Back>
<TextBlock Text="Wow hintere sache!"/>
</CustomCharts:Card.Back>
</CustomCharts:Card>
<Button Click="Button_Click" Width="50" Height="20" Content="Test"/>
</StackPanel>
private void Button_Click( object sender, RoutedEventArgs e ) {
this.TestCard.IsDetailed= !this.TestCard.IsDetailed;
}
Any Help is apreciated, I'm stuck...
Upvotes: 0
Views: 624
Reputation: 35681
you can benefit a lot if declare Front
and Back
with object
type, not FrameworkElement
- mostly because it will allow easy bidnings. you can keep rich visual appearance if you add corresponding templates for those two properties.
public class Card : Control
{
static Card()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Card), new FrameworkPropertyMetadata(typeof(Card)));
}
public object Front
{
get { return (object)GetValue(FrontProperty); }
set { SetValue(FrontProperty, value); }
}
public static readonly DependencyProperty FrontProperty =
DependencyProperty.Register("Front", typeof(object), typeof(Card), new PropertyMetadata(null));
public DataTemplate FrontTemplate
{
get { return (DataTemplate)GetValue(FrontTemplateProperty); }
set { SetValue(FrontTemplateProperty, value); }
}
public static readonly DependencyProperty FrontTemplateProperty =
DependencyProperty.Register("FrontTemplate", typeof(DataTemplate), typeof(Card), new PropertyMetadata(null));
public object Back
{
get { return (object)GetValue(BackProperty); }
set { SetValue(BackProperty, value); }
}
public static readonly DependencyProperty BackProperty =
DependencyProperty.Register("Back", typeof(object), typeof(Card), new PropertyMetadata(null));
public DataTemplate BackTemplate
{
get { return (DataTemplate)GetValue(BackTemplateProperty); }
set { SetValue(BackTemplateProperty, value); }
}
public static readonly DependencyProperty BackTemplateProperty =
DependencyProperty.Register("BackTemplate", typeof(DataTemplate), typeof(Card), new PropertyMetadata(null));
public bool IsDetailed
{
get { return (bool)GetValue(IsDetailedProperty); }
set { SetValue(IsDetailedProperty, value); }
}
public static readonly DependencyProperty IsDetailedProperty =
DependencyProperty.Register(nameof(IsDetailed), typeof(bool), typeof(Card), new PropertyMetadata(false));
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), typeof(Card), new PropertyMetadata(new CornerRadius(0)));
}
Use Trigger on IsDetailed property to flip Fron and Back:
<Style TargetType="{x:Type local:Card}">
<Setter Property="Background" Value="Khaki"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Card}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ContentPresenter x:Name="presenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsDetailed" Value="True">
<Setter TargetName="presenter" Property="Content"
Value="{Binding Front, RelativeSource={RelativeSource TemplatedParent}}"/>
<Setter TargetName="presenter" Property="ContentTemplate"
Value="{Binding FrontTemplate, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<Trigger Property="IsDetailed" Value="False">
<Setter TargetName="presenter" Property="Content"
Value="{Binding Back, RelativeSource={RelativeSource TemplatedParent}}"/>
<Setter TargetName="presenter" Property="ContentTemplate"
Value="{Binding BackTemplate, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
use TemplateBindings inside Template, and RelativeSource TemplatedParent with normal Binding in Setters (TemplateBinding is not supported in Setter).
And here is two examples of usage - with and without binding:
<StackPanel DataContext="{x:Static sys:DateTime.Now}">
<CheckBox Name="chk_1"/>
<local:Card Front="Front"
Back="Back"
IsDetailed="{Binding IsChecked, ElementName=chk_1}"/>
<CheckBox Name="chk_2"/>
<local:Card Front="{Binding DayOfWeek}"
Back="{Binding TimeOfDay}"
IsDetailed="{Binding IsChecked, ElementName=chk_2}">
<local:Card.FrontTemplate>
<DataTemplate>
<TextBlock Foreground="Red" FontWeight="Bold" FontSize="20"
Text="{Binding}" TextDecorations="Underline"/>
</DataTemplate>
</local:Card.FrontTemplate>
<local:Card.BackTemplate>
<DataTemplate>
<TextBlock Foreground="Blue" FontWeight="Bold" FontSize="20"
Text="{Binding}" TextDecorations="Underline"/>
</DataTemplate>
</local:Card.BackTemplate>
</local:Card>
</StackPanel>
result:
Upvotes: 1