【问题标题】:Wpf Custom Control: How to implement CustomContentWpf 自定义控件:如何实现 CustomContent
【发布时间】:2020-10-02 06:51:00
【问题描述】:

我正在处理 WPF 中的 CustomControl。我想实现一个 CardControl。我有两个内容“前”和“后”,我想在它们之间翻转。 但是我不能在样式中定义一个工作触发器来在内容之间翻转......

首先我创建了一个带有 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

然后我在 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>

我用一个按钮实现了一个用于测试目的的简单 CardControl,它会翻转 isDetailed 状态:

<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;
}

感谢任何帮助,我被困住了......

【问题讨论】:

    标签: c# wpf triggers custom-controls datatrigger


    【解决方案1】:

    如果使用object 类型而不是FrameworkElement 声明FrontBack,您将受益匪浅——主要是因为它可以轻松投标。如果为这两个属性添加相应的模板,则可以保持丰富的视觉外观。

    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)));
    }
    

    在 IsDetailed 属性上使用触发器来前后翻转:

    <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>
    

    在 Template 中使用 TemplateBindings,在 Setter 中使用具有普通 Binding 的 RelativeSource TemplatedParent(Setter 中不支持 TemplateBinding)。

    这里有两个用法示例 - 有和没有绑定:

    <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>
    

    结果:

    【讨论】:

    • 谢谢!我想,我已经尝试过这样的事情,目标名称为presenter,但现在它就像一个魅力!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多