簡體   English   中英

WPF 切角元件

[英]WPF Cut Corner Element

我正在嘗試創建類似於下圖 WPF 中的內容。此控件旨在成為我應用程序中所有內容的基本視圖,並將位於具有背景(可能是某種漸變)的 Window 控件內。

要求如下:

  • 三邊圓角(左上、左下、右下)
  • 切掉右上角的選項卡看角,“剪切區域”后面的背景是透明的,所以顯示 Window 的背景漸變(讓它看起來真的被切掉了)
  • 標題區域應該是一個內容容器,這樣我就可以在里面放任何東西,比如圖標和文本
  • 內容區域需要有一個最小高度,然后在內部內容超過它時增長(不是動態 - 只是支持其中任何元素的高度)

我已經為此奮斗了幾個小時,但作為 WPF 的新手,我開始發現自己在原地打轉。 我認為 WPF 的靈活性有很大的好處,但對於剛起步的人來說,這幾乎是令人生畏的。

任何幫助將非常感激! 謝謝!

內容布局

試試這個開始吧:

<Grid Width="100" Height="100">  
    <Border Background="Green" CornerRadius="8,0,8,8">
      <Border.Clip>
        <PathGeometry>
          <PathGeometry.Figures>
            <PathFigure StartPoint="0,0">
              <PathFigure.Segments>
                <LineSegment Point="90,0"/>
                <LineSegment Point="100,10"/>
                <LineSegment Point="100,100"/>
                <LineSegment Point="0,100"/>
              </PathFigure.Segments>
            </PathFigure>
          </PathGeometry.Figures>
        </PathGeometry>
      </Border.Clip>
    </Border>
  </Grid>

虎斑貓

我不知道如何'填充'剪輯,所以我用代碼制作了剪輯。 如果您需要更多幫助來添加更多屬性來控制顏色等,請告訴我。

碼:

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

    public double DogEar
    {
        get { return (double)GetValue(DogEarProperty); }
        set { SetValue(DogEarProperty, value); }
    }

    public static readonly DependencyProperty DogEarProperty =
        DependencyProperty.Register("DogEar",
        typeof(double), 
        typeof(Tabby),
        new UIPropertyMetadata(8.0, DogEarPropertyChanged));

    private static void DogEarPropertyChanged(
        DependencyObject obj, 
        DependencyPropertyChangedEventArgs e)
    {
        ((Tabby)obj).InvalidateVisual();
    }

    public Tabby()
    {
        this.SizeChanged += new SizeChangedEventHandler(Tabby_SizeChanged);
    }

    void Tabby_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        var clip = new PathGeometry();
        clip.Figures = new PathFigureCollection();
        clip.Figures.Add(
            new PathFigure(
                new Point(0, 0),
                new[] {
                    new LineSegment(new Point(this.ActualWidth - DogEar, 0), true),
                    new LineSegment(new Point(this.ActualWidth, DogEar), true), 
                    new LineSegment(new Point(this.ActualWidth, this.ActualHeight), true),
                    new LineSegment(new Point(0, this.ActualHeight), true) },
                true)
        );
        this.Clip = clip;
    }
}

Generic.xaml

<Style TargetType="{x:Type local:Tabby}">
    <Setter Property="Padding"
            Value="5" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:Tabby}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="auto" />
                        <RowDefinition Height="auto" />
                    </Grid.RowDefinitions>
                    <Border CornerRadius="3,0,0,0"
                            BorderBrush="Black"
                            BorderThickness="1"
                            Background="Black">
                        <ContentPresenter Content="{TemplateBinding Header}"
                                          Margin="{TemplateBinding Padding}" />
                    </Border>
                    <Border CornerRadius="0,0,3,3"
                            BorderBrush="Black"
                            BorderThickness="1"
                            Background="White"
                            Grid.Row="1">

                        <ContentPresenter Content="{TemplateBinding Content}"
                                          Margin="{TemplateBinding Padding}" />
                    </Border>
                </Grid>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

使用它:

<my:Tabby DogEar="12"
          x:Name="tabby1">
    <my:Tabby.Header>
        <TextBlock Foreground="White">Header</TextBlock>
    </my:Tabby.Header>
    <my:Tabby.Content>
        <TextBlock Text="Content can be anything" />
    </my:Tabby.Content>
</my:Tabby>

這是我使用自定義控件放在一起的一些代碼。

控制代碼:

using System;
using System.Windows;
using System.Windows.Controls;

namespace Test
{
    public class ContentCard : HeaderedContentControl
    {
        static ContentCard()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ContentCard), new FrameworkPropertyMetadata(typeof(ContentCard)));
        }
    }
}

控制xaml(在Themes / Generic.xaml文件夾中)

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:test="clr-namespace:Test">
    <Style TargetType="{x:Type test:ContentCard}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type test:ContentCard}">
                    <Grid  Background="Transparent">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="30" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="20" />
                        </Grid.ColumnDefinitions>

                        <Border Grid.Row="0" Grid.Column="0" Background="{TemplateBinding Background}" CornerRadius="10,0,0,0" Height="30">
                            <ContentControl Content="{TemplateBinding Header}" VerticalAlignment="Center" Margin="10,0,0,0" />
                        </Border>
                        <Path Grid.Row="0" Grid.Column="1" Fill="{TemplateBinding Background}" Data="M0,0 L20,15 L20,30 L0,30 L0,0Z"/>
                        <Border Grid.Row="1" Grid.ColumnSpan="2" BorderBrush="{TemplateBinding Background}" BorderThickness="1,0,1,1" CornerRadius="0,0,10,10" Padding="5" Background="White">
                            <ContentControl Content="{TemplateBinding Content}" />
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

這是你如何使用它:

<test:ContentCard Grid.RowSpan="4" Grid.ColumnSpan="2" Margin="200" Background="Black">
    <test:ContentCard.Header>
        <TextBlock Text="Title" Foreground="White" />
    </test:ContentCard.Header>
    <test:ContentCard.Content>
        <TextBlock Text="This is some content" Foreground="Black" />
    </test:ContentCard.Content>
</test:ContentCard>

謝謝你的帖子,這真是太棒了! 我已經修改以制作我自己的切角邊框 class 和下面相同的用法

public class CornerCutBorder : Border
{

    public CornerRadius CornerCutSize
    {
        get { return (CornerRadius)GetValue(CornerCutSizeProperty); }
        set { SetValue(CornerCutSizeProperty, value); }
    }

    public static readonly DependencyProperty CornerCutSizeProperty = DependencyProperty.Register("CornerCutSize", typeof(CornerRadius),typeof(CornerCutBorder),new UIPropertyMetadata(new CornerRadius(), DogEarPropertyChanged));

    private static void DogEarPropertyChanged(DependencyObject obj,DependencyPropertyChangedEventArgs e)
    {
        ((CornerCutBorder)obj).Resized();
    }

    public CornerCutBorder()
    {
        this.SizeChanged += new SizeChangedEventHandler(Border_SizeChanged);
    }

    void Border_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        Resized();
    }

    void Resized()
    {
        var clip = new PathGeometry();

        clip.Figures = new PathFigureCollection();
        RectangleGeometry rectangleGeometry = new RectangleGeometry(new Rect()
        {
            Width = this.ActualWidth,
            Height = this.ActualHeight
        });

        clip.AddGeometry(rectangleGeometry);

        if (CornerCutSize.TopLeft > 0)
        {
            clip.Figures.Add(
            new PathFigure(
                new Point(0, 0),
                new[] {
                new LineSegment(new Point(CornerCutSize.TopLeft, 0), true),
                new LineSegment(new Point(0, CornerCutSize.TopLeft), true) },
                true)
            );
        }

        if (CornerCutSize.TopRight > 0)
        {
            clip.Figures.Add(
            new PathFigure(
                new Point(this.ActualWidth - CornerCutSize.TopRight, 0),
                new[] {
                new LineSegment(new Point(this.ActualWidth, 0), true),
                new LineSegment(new Point(this.ActualWidth, CornerCutSize.TopRight), true) },
                true)
            );
        }

        if (CornerCutSize.BottomLeft > 0)
        {
            clip.Figures.Add(
            new PathFigure(
                new Point(0, this.ActualHeight - CornerCutSize.BottomLeft),
                new[] {
                new LineSegment(new Point(0, this.ActualHeight), true),
                new LineSegment(new Point(CornerCutSize.BottomLeft, this.ActualHeight), true) },
                true)
            );
        }

        if (CornerCutSize.BottomRight > 0)
        {
            clip.Figures.Add(
            new PathFigure(
                new Point(this.ActualWidth - CornerCutSize.BottomRight, this.ActualHeight),
                new[] {
                new LineSegment(new Point(this.ActualWidth, this.ActualHeight), true),
                new LineSegment(new Point(this.ActualWidth, this.ActualHeight-CornerCutSize.BottomRight), true) },
                true)
            );
        }

        this.Clip = clip;
    }
}


<local:CornerCutBorder CornerCutSize="30,100,100,50" Width="600" Height="400" BorderThickness="2" Background="Red" ></local:CornerCutBorder>

樣品 output

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM