Skip to content

Commit

Permalink
feat: 添加支持圆角的 ToggleButton, 修复 TransitioningContentControl 模板应用较晚导致的内…
Browse files Browse the repository at this point in the history
…容不显示 bug
  • Loading branch information
SlimeNull committed Apr 15, 2024
1 parent ea36bb4 commit 935ea55
Show file tree
Hide file tree
Showing 14 changed files with 273 additions and 30 deletions.
9 changes: 9 additions & 0 deletions EleCho.WpfSuite/Controls/ConditionalControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public DataTemplate ContentTemplateWhenFalse
set { SetValue(ContentTemplateWhenFalseProperty, value); }
}

public IContentTransition Transition
{
get { return (IContentTransition)GetValue(TransitionProperty); }
set { SetValue(TransitionProperty, value); }
}

public object ComputedContent
{
get { return (object)GetValue(ComputedContentProperty); }
Expand Down Expand Up @@ -86,6 +92,9 @@ public DataTemplate ComputedContentTemplate
public static readonly DependencyProperty ContentTemplateWhenTrueProperty =
DependencyProperty.Register(nameof(ContentTemplateWhenTrue), typeof(DataTemplate), typeof(ConditionalControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure));

public static readonly DependencyProperty TransitionProperty =
TransitioningContentControl.TransitionProperty.AddOwner(typeof(ConditionalControl));

protected override Size MeasureOverride(Size constraint)
{
var condition = Condition;
Expand Down
5 changes: 3 additions & 2 deletions EleCho.WpfSuite/Controls/ConditionalControlResources.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter ContentTemplate="{TemplateBinding ComputedContentTemplate}"
Content="{TemplateBinding ComputedContent}"/>
<ws:TransitioningContentControl Transition="{TemplateBinding Transition}"
Content="{TemplateBinding ComputedContent}"
ContentTemplate="{TemplateBinding ComputedContentTemplate}"/>
</Border>
</ControlTemplate>
</Setter.Value>
Expand Down
34 changes: 34 additions & 0 deletions EleCho.WpfSuite/Controls/ToggleButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace EleCho.WpfSuite
{
public class ToggleButton : System.Windows.Controls.Primitives.ToggleButton
{
static ToggleButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ToggleButton), new FrameworkPropertyMetadata(typeof(ToggleButton)));
}

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

public static readonly DependencyProperty CornerRadiusProperty =
Border.CornerRadiusProperty.AddOwner(typeof(ToggleButton));
}
}
60 changes: 60 additions & 0 deletions EleCho.WpfSuite/Controls/ToggleButtonResources.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ws="https://github.com/OrgEleCho/EleCho.WpfSuite">

<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" StrokeDashArray="1 2" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" SnapsToDevicePixels="true" StrokeThickness="1"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
<SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
<SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
<SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
<SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
<SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
<SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
<SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
<SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
<Style TargetType="{x:Type ws:ToggleButton}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ws:ToggleButton}">
<Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsDefaulted" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
<Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
20 changes: 14 additions & 6 deletions EleCho.WpfSuite/Controls/TransitioningContentControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@ static TransitioningContentControl()
private Panel? _contentsPanel;
private UIElement? _lastOldControl;
private CancellationTokenSource? _lastTaskCancellation;
private object? _pendingNewContent;

public override void OnApplyTemplate()
{
base.OnApplyTemplate();

_contentsPanel = (Panel)GetTemplateChild("PART_Contents");

if (_pendingNewContent is not null)
{
_ = this.ApplyContentChangeAsync(null, _pendingNewContent);
}
}

public object? Content
Expand Down Expand Up @@ -61,13 +67,13 @@ public IContentTransition? Transition


public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(nameof(Content), typeof(object), typeof(TransitioningContentControl), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnContentChanged)));
DependencyProperty.Register(nameof(Content), typeof(object), typeof(TransitioningContentControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnContentChanged)));

public static readonly DependencyProperty ContentTemplateProperty =
DependencyProperty.Register(nameof(ContentTemplate), typeof(DataTemplate), typeof(TransitioningContentControl), new FrameworkPropertyMetadata(null));
DependencyProperty.Register(nameof(ContentTemplate), typeof(DataTemplate), typeof(TransitioningContentControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure));

public static readonly DependencyProperty ContentTemplateSelectorProperty =
DependencyProperty.Register(nameof(ContentTemplateSelector), typeof(DataTemplateSelector), typeof(TransitioningContentControl), new FrameworkPropertyMetadata(null));
DependencyProperty.Register(nameof(ContentTemplateSelector), typeof(DataTemplateSelector), typeof(TransitioningContentControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure));

public static readonly DependencyProperty TransitionProperty =
DependencyProperty.Register(nameof(Transition), typeof(IContentTransition), typeof(TransitioningContentControl), new FrameworkPropertyMetadata(null));
Expand All @@ -76,15 +82,16 @@ private static void OnContentChanged(DependencyObject d, DependencyPropertyChang
{
if (d is TransitioningContentControl transitioningContentControl)
{
_ = transitioningContentControl.OnContentChanged(e.OldValue, e.NewValue);
_ = transitioningContentControl.ApplyContentChangeAsync(e.OldValue, e.NewValue);
}
}

private async Task OnContentChanged(object oldContent, object newContent)
private async Task ApplyContentChangeAsync(object? oldContent, object newContent)
{
if (_contentsPanel is null)
{
throw new InvalidOperationException("Can not find 'PART_Contents' in control template");
_pendingNewContent = newContent;
return;
}

if (_lastOldControl is not null)
Expand Down Expand Up @@ -124,6 +131,7 @@ private async Task OnContentChanged(object oldContent, object newContent)

_contentsPanel.Children.Add(newContentElement);
_lastOldControl = oldContentElement;
_pendingNewContent = null;
if (Transition is IContentTransition transition &&
oldContentElement is FrameworkElement oldContentFrameworkElement)
{
Expand Down
2 changes: 2 additions & 0 deletions EleCho.WpfSuite/EleCho.WpfSuite.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<Page Remove="Controls\ImageResources.xaml" />
<Page Remove="Controls\ScrollViewerResources.xaml" />
<Page Remove="Controls\TextBoxResources.xaml" />
<Page Remove="Controls\ToggleButtonResources.xaml" />
<Page Remove="Controls\TransitioningControlResources.xaml" />
</ItemGroup>

Expand All @@ -43,6 +44,7 @@
<ItemGroup>
<Resource Include="Controls\ButtonResources.xaml" />
<Resource Include="Controls\FrameResources.xaml" />
<Resource Include="Controls\ToggleButtonResources.xaml" />
<Resource Include="Controls\TransitioningControlResources.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down
1 change: 1 addition & 0 deletions EleCho.WpfSuite/Themes/Generic.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/TextBoxResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/FrameResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/ButtonResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/ToggleButtonResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
6 changes: 6 additions & 0 deletions WpfTest/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ public MainWindow()
PageType = typeof(ImageTestPage)
},
new NavigationItem()
{
Title = "ConditionalControl test",
Description = "",
PageType = typeof(ConditionalControlTestPage)
},
new NavigationItem()
{
Title = "TextBox test",
Description = "",
Expand Down
3 changes: 2 additions & 1 deletion WpfTest/Tests/CollectionTestPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
</ws:ValueConverterGroup>
</Page.Resources>

<ws:ScrollViewer ScrollWithWheelDelta="True">
<ws:ScrollViewer ScrollWithWheelDelta="True"
VerticalScrollBarVisibility="Auto">
<Grid Margin="28 12 28 28">
<ws:StackPanel Spacing="12">
<TextBlock Text="Collection test"
Expand Down
90 changes: 90 additions & 0 deletions WpfTest/Tests/ConditionalControlTestPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<Page x:Class="WpfTest.Tests.ConditionalControlTestPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfTest.Tests"
xmlns:ws="https://github.com/OrgEleCho/EleCho.WpfSuite"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:Background="White"
Title="ConditionalControlTestPage">

<ws:ScrollViewer ScrollWithWheelDelta="True"
VerticalScrollBarVisibility="Auto">
<ws:StackPanel Margin="28 12 28 28"
Spacing="12">
<TextBlock Text="ConditionalControl Test"
FontSize="26"
Margin="0 0 0 12"/>
<ws:ConditionalControl Condition="{Binding ElementName=ConditionButton,Path=IsChecked}"
ContentWhenTrue="{Binding ElementName=ContentWhenTrueBox,Path=Text}"
ContentWhenFalse="{Binding ElementName=ContentWhenFalseBox,Path=Text}">
<ws:ConditionalControl.Transition>
<ws:SlideFadeTransition Orientation="Vertical"
Distance="10"/>
</ws:ConditionalControl.Transition>
<ws:ConditionalControl.ContentTemplateWhenTrue>
<DataTemplate>
<Border BorderBrush="Green"
BorderThickness="3"
CornerRadius="3"
Padding="5">
<ws:StackPanel Spacing="4">
<TextBlock Text="Current value is true"/>
<TextBlock>
<Run Text="Content:"/>
<Run Text="{Binding Mode=OneWay}"/>
</TextBlock>
</ws:StackPanel>
</Border>
</DataTemplate>
</ws:ConditionalControl.ContentTemplateWhenTrue>
<ws:ConditionalControl.ContentTemplateWhenFalse>
<DataTemplate>
<Border BorderBrush="Red"
BorderThickness="3"
CornerRadius="3"
Padding="5">
<ws:StackPanel Spacing="4">
<TextBlock Text="Current value is true"/>
<TextBlock>
<Run Text="Content:"/>
<Run Text="{Binding Mode=OneWay}"/>
</TextBlock>
</ws:StackPanel>
</Border>
</DataTemplate>
</ws:ConditionalControl.ContentTemplateWhenFalse>
</ws:ConditionalControl>

<GroupBox Header="Options"
Padding="8">
<ws:FlexPanel Direction="Column"
MainSpacing="8"
ItemsAlignment="Start">
<ws:ToggleButton x:Name="ConditionButton"
Content="Toggle Condition"
Padding="5 3"
CornerRadius="3"/>
<StackPanel>
<TextBlock Text="ContentWhenTrue:"/>
<ws:TextBox x:Name="ContentWhenTrueBox"
Placeholder="ContentWhenTrue"
Text="TrueContent"
MinWidth="150"
Padding="5 3"/>
</StackPanel>
<StackPanel>
<TextBlock Text="ContentWhenFalse:"/>
<ws:TextBox x:Name="ContentWhenFalseBox"
Placeholder="ContentWhenTrue"
Text="FalseContent"
MinWidth="150"
Padding="5 3"/>
</StackPanel>
</ws:FlexPanel>
</GroupBox>
</ws:StackPanel>
</ws:ScrollViewer>
</Page>
28 changes: 28 additions & 0 deletions WpfTest/Tests/ConditionalControlTestPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfTest.Tests
{
/// <summary>
/// ConditionalControlTestPage.xaml 的交互逻辑
/// </summary>
public partial class ConditionalControlTestPage : Page
{
public ConditionalControlTestPage()
{
InitializeComponent();
}
}
}
Loading

0 comments on commit 935ea55

Please sign in to comment.