Skip to content

Commit 201cf19

Browse files
committed
Add RichButton
1 parent bf276dc commit 201cf19

5 files changed

Lines changed: 387 additions & 0 deletions

File tree

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
using System.Windows.Input;
2+
3+
namespace DevWinUI;
4+
5+
public partial class RichButton : Control
6+
{
7+
private const string PART_Button = "PART_Button";
8+
private const string PART_TitleStackPanel = "PART_TitleStackPanel";
9+
10+
private Button button;
11+
private StackPanel stackPanel;
12+
13+
public event EventHandler<RoutedEventArgs> Click;
14+
15+
public ICommand Command
16+
{
17+
get { return (ICommand)GetValue(CommandProperty); }
18+
set { SetValue(CommandProperty, value); }
19+
}
20+
21+
public static readonly DependencyProperty CommandProperty =
22+
DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(RichButton), new PropertyMetadata(null));
23+
24+
public object CommandParameter
25+
{
26+
get { return (object)GetValue(CommandParameterProperty); }
27+
set { SetValue(CommandParameterProperty, value); }
28+
}
29+
30+
public static readonly DependencyProperty CommandParameterProperty =
31+
DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(RichButton), new PropertyMetadata(null));
32+
33+
public object ActionIcon
34+
{
35+
get { return (object)GetValue(ActionIconProperty); }
36+
set { SetValue(ActionIconProperty, value); }
37+
}
38+
39+
public static readonly DependencyProperty ActionIconProperty =
40+
DependencyProperty.Register(nameof(ActionIcon), typeof(object), typeof(RichButton), new PropertyMetadata(null));
41+
42+
public object Icon
43+
{
44+
get { return (object)GetValue(IconProperty); }
45+
set { SetValue(IconProperty, value); }
46+
}
47+
48+
public static readonly DependencyProperty IconProperty =
49+
DependencyProperty.Register(nameof(Icon), typeof(object), typeof(RichButton), new PropertyMetadata(null, OnPropertyChanged));
50+
51+
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
52+
{
53+
var ctl = (RichButton)d;
54+
if (ctl != null)
55+
{
56+
ctl.UpdateMargin();
57+
}
58+
}
59+
60+
public object Title
61+
{
62+
get { return (object)GetValue(TitleProperty); }
63+
set { SetValue(TitleProperty, value); }
64+
}
65+
66+
public static readonly DependencyProperty TitleProperty =
67+
DependencyProperty.Register(nameof(Title), typeof(object), typeof(RichButton), new PropertyMetadata(null, OnPropertyChanged));
68+
69+
public object SubTitle
70+
{
71+
get { return (object)GetValue(SubTitleProperty); }
72+
set { SetValue(SubTitleProperty, value); }
73+
}
74+
75+
public static readonly DependencyProperty SubTitleProperty =
76+
DependencyProperty.Register(nameof(SubTitle), typeof(object), typeof(RichButton), new PropertyMetadata(null, OnPropertyChanged));
77+
78+
public Brush TitleForeground
79+
{
80+
get { return (Brush)GetValue(TitleForegroundProperty); }
81+
set { SetValue(TitleForegroundProperty, value); }
82+
}
83+
84+
public static readonly DependencyProperty TitleForegroundProperty =
85+
DependencyProperty.Register(nameof(TitleForeground), typeof(Brush), typeof(RichButton), new PropertyMetadata(null));
86+
87+
public Brush SubTitleForeground
88+
{
89+
get { return (Brush)GetValue(SubTitleForegroundProperty); }
90+
set { SetValue(SubTitleForegroundProperty, value); }
91+
}
92+
93+
public static readonly DependencyProperty SubTitleForegroundProperty =
94+
DependencyProperty.Register(nameof(SubTitleForeground), typeof(Brush), typeof(RichButton), new PropertyMetadata(null));
95+
96+
public RichButtonDisplayMode DisplayMode
97+
{
98+
get { return (RichButtonDisplayMode)GetValue(DisplayModeProperty); }
99+
set { SetValue(DisplayModeProperty, value); }
100+
}
101+
102+
public static readonly DependencyProperty DisplayModeProperty =
103+
DependencyProperty.Register(nameof(DisplayMode), typeof(RichButtonDisplayMode), typeof(RichButton), new PropertyMetadata(RichButtonDisplayMode.Subtle, OnDisplayModeChanged));
104+
105+
private static void OnDisplayModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
106+
{
107+
var ctl = (RichButton)d;
108+
if (ctl != null)
109+
{
110+
ctl.UpdateDisplayMode();
111+
}
112+
}
113+
114+
115+
protected override void OnApplyTemplate()
116+
{
117+
base.OnApplyTemplate();
118+
119+
button = GetTemplateChild(PART_Button) as Button;
120+
stackPanel = GetTemplateChild(PART_TitleStackPanel) as StackPanel;
121+
122+
button.Click -= OnClick;
123+
button.Click += OnClick;
124+
125+
UpdateDisplayMode();
126+
127+
UpdateMargin();
128+
}
129+
private void UpdateMargin()
130+
{
131+
if (stackPanel == null)
132+
return;
133+
134+
if (Icon != null && (Title != null || SubTitle != null))
135+
stackPanel.Margin = new(16, 0, 0, 0);
136+
else if (Icon != null)
137+
stackPanel.Margin = new(0, 0, 0, 0);
138+
else
139+
stackPanel.Margin = new(0, 0, 0, 0);
140+
}
141+
142+
private void OnClick(object sender, RoutedEventArgs e)
143+
{
144+
Click?.Invoke(this, e);
145+
}
146+
147+
private void UpdateDisplayMode()
148+
{
149+
if (button == null)
150+
return;
151+
152+
switch (DisplayMode)
153+
{
154+
case RichButtonDisplayMode.Normal:
155+
button.Style = Application.Current.Resources["DefaultButtonStyle"] as Style;
156+
157+
break;
158+
case RichButtonDisplayMode.Subtle:
159+
button.Style = Application.Current.Resources["SubtleButtonStyle"] as Style;
160+
161+
break;
162+
case RichButtonDisplayMode.ReadOnly:
163+
button.Style = Application.Current.Resources["NoEffectSubtleButtonStyle"] as Style;
164+
165+
break;
166+
}
167+
}
168+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace DevWinUI;
2+
3+
public enum RichButtonDisplayMode
4+
{
5+
Normal,
6+
Subtle,
7+
ReadOnly
8+
}

dev/DevWinUI.Controls/Themes/Generic.xaml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ Themes\Styles\Controls\ProfileControl.xaml
145145
Themes\Styles\Controls\ProgressButton.xaml
146146
Themes\Styles\Controls\ProgressRing.xaml
147147
Themes\Styles\Controls\RedirectVisualView.xaml
148+
Themes\Styles\Controls\RichButton.xaml
148149
Themes\Styles\Controls\SegmentedSlider.xaml
149150
Themes\Styles\Controls\SelectableTextBlock.xaml
150151
Themes\Styles\Controls\SelectorBarSegmented.xaml
@@ -8979,6 +8980,57 @@ Themes\Styles\Controls\WaveProgressBar.xaml
89798980
</Setter.Value>
89808981
</Setter>
89818982
</Style>
8983+
<Style x:Key="NoEffectSubtleButtonStyle" TargetType="Button">
8984+
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
8985+
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
8986+
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
8987+
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
8988+
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
8989+
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
8990+
<Setter Property="HorizontalAlignment" Value="Left" />
8991+
<Setter Property="VerticalAlignment" Value="Center" />
8992+
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
8993+
<Setter Property="FontWeight" Value="Normal" />
8994+
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
8995+
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
8996+
<Setter Property="FocusVisualMargin" Value="-3" />
8997+
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
8998+
<Setter Property="Template">
8999+
<Setter.Value>
9000+
<ControlTemplate TargetType="Button">
9001+
<ContentPresenter xmlns:local="using:Microsoft.UI.Xaml.Controls" x:Name="ContentPresenter" Padding="{TemplateBinding Padding}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" local:AnimatedIcon.State="Normal" AutomationProperties.AccessibilityView="Raw" Background="{TemplateBinding Background}" BackgroundSizing="{TemplateBinding BackgroundSizing}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" CornerRadius="{TemplateBinding CornerRadius}" Foreground="{TemplateBinding Foreground}">
9002+
<ContentPresenter.BackgroundTransition>
9003+
<BrushTransition Duration="0:0:0.083" />
9004+
</ContentPresenter.BackgroundTransition>
9005+
<VisualStateManager.VisualStateGroups>
9006+
<VisualStateGroup x:Name="CommonStates">
9007+
<VisualState x:Name="Normal" />
9008+
<VisualState x:Name="PointerOver" />
9009+
<VisualState x:Name="Pressed" />
9010+
<VisualState x:Name="Disabled">
9011+
<Storyboard>
9012+
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
9013+
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
9014+
</ObjectAnimationUsingKeyFrames>
9015+
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
9016+
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
9017+
</ObjectAnimationUsingKeyFrames>
9018+
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
9019+
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
9020+
</ObjectAnimationUsingKeyFrames>
9021+
</Storyboard>
9022+
<VisualState.Setters>
9023+
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
9024+
<Setter Target="ContentPresenter.(controls:AnimatedIcon.State)" Value="Normal" />
9025+
</VisualState.Setters>
9026+
</VisualState>
9027+
</VisualStateGroup>
9028+
</VisualStateManager.VisualStateGroups>
9029+
</ContentPresenter>
9030+
</ControlTemplate>
9031+
</Setter.Value>
9032+
</Setter>
9033+
</Style>
89829034
<Style x:Key="HeaderNavigationButtonStyle" TargetType="Button">
89839035
<Setter Property="HorizontalAlignment" Value="Stretch" />
89849036
<Setter Property="VerticalAlignment" Value="Stretch" />
@@ -14839,6 +14891,31 @@ Themes\Styles\Controls\WaveProgressBar.xaml
1483914891
</Setter>
1484014892
</Style>
1484114893
<Style TargetType="local:RedirectVisualView" BasedOn="{StaticResource DefaultRedirectVisualViewStyle}" />
14894+
<Style x:Key="DefaultRichButtonStyle" TargetType="local:RichButton">
14895+
<Setter Property="TitleForeground" Value="{ThemeResource TextFillColorPrimaryBrush}" />
14896+
<Setter Property="SubTitleForeground" Value="{ThemeResource TextFillColorTertiaryBrush}" />
14897+
<Setter Property="Template">
14898+
<Setter.Value>
14899+
<ControlTemplate TargetType="local:RichButton">
14900+
<Button x:Name="PART_Button" Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}" IsEnabled="{TemplateBinding IsEnabled}" Style="{StaticResource SubtleButtonStyle}">
14901+
<Grid>
14902+
<Grid.ColumnDefinitions>
14903+
<ColumnDefinition Width="Auto" />
14904+
<ColumnDefinition Width="*" />
14905+
<ColumnDefinition Width="Auto" />
14906+
</Grid.ColumnDefinitions>
14907+
<ContentPresenter x:Name="PART_IconPresenter" Content="{TemplateBinding Icon}" Visibility="{Binding Icon, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource NullToVisibilityConverter}}" />
14908+
<StackPanel x:Name="PART_TitleStackPanel" Grid.Column="1" VerticalAlignment="Center" Orientation="Vertical" Spacing="5">
14909+
<ContentPresenter VerticalAlignment="Center" Content="{TemplateBinding Title}" FontWeight="SemiBold" Foreground="{TemplateBinding TitleForeground}" TextWrapping="Wrap" Visibility="{Binding Title, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource NullToVisibilityConverter}}" />
14910+
<ContentPresenter VerticalAlignment="Center" Content="{TemplateBinding SubTitle}" FontSize="{StaticResource CaptionTextBlockFontSize}" FontWeight="Normal" Foreground="{TemplateBinding SubTitleForeground}" TextWrapping="Wrap" Visibility="{Binding SubTitle, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource NullToVisibilityConverter}}" />
14911+
</StackPanel>
14912+
<ContentPresenter x:Name="PART_ActionIconPresenter" Grid.Column="2" Margin="32,0,0,0" Content="{TemplateBinding ActionIcon}" Visibility="{Binding ActionIcon, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource NullToVisibilityConverter}}" />
14913+
</Grid>
14914+
</Button>
14915+
</ControlTemplate>
14916+
</Setter.Value>
14917+
</Setter>
14918+
</Style>
1484214919
<Style x:Key="DefaultSegmentedSliderStyle" TargetType="local:SegmentedSlider">
1484314920
<Setter Property="Template">
1484414921
<Setter.Value>
@@ -17209,6 +17286,7 @@ Themes\Styles\Controls\WaveProgressBar.xaml
1720917286
</Style>
1721017287
<Style TargetType="local:ProgressButton" BasedOn="{StaticResource DefaultProgressButtonStyle}" />
1721117288
<Style TargetType="local:ProgressRing" BasedOn="{StaticResource DefaultProgressRingStyle}" />
17289+
<Style TargetType="local:RichButton" BasedOn="{StaticResource DefaultRichButtonStyle}" />
1721217290
<Style TargetType="local:SegmentedSlider" BasedOn="{StaticResource DefaultSegmentedSliderStyle}" />
1721317291
<Style TargetType="local:SettingsGroup" BasedOn="{StaticResource DefaultSettingsGroupStyle}" />
1721417292
<Style TargetType="local:Shield" BasedOn="{StaticResource DefaultShieldStyle}" />

dev/DevWinUI.Controls/Themes/Styles/CommonStyles/Button.xaml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,4 +354,80 @@
354354
</Setter>
355355
</Style>
356356

357+
<Style x:Key="NoEffectSubtleButtonStyle" TargetType="Button">
358+
<Setter Property="Background" Value="{ThemeResource SubtleButtonBackground}" />
359+
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
360+
<Setter Property="Foreground" Value="{ThemeResource SubtleButtonForeground}" />
361+
<Setter Property="BorderBrush" Value="{ThemeResource SubtleButtonBorderBrush}" />
362+
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
363+
<Setter Property="Padding" Value="{StaticResource ButtonPadding}" />
364+
<Setter Property="HorizontalAlignment" Value="Left" />
365+
<Setter Property="VerticalAlignment" Value="Center" />
366+
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
367+
<Setter Property="FontWeight" Value="Normal" />
368+
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
369+
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
370+
<Setter Property="FocusVisualMargin" Value="-3" />
371+
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
372+
<Setter Property="Template">
373+
<Setter.Value>
374+
<ControlTemplate TargetType="Button">
375+
<ContentPresenter xmlns:local="using:Microsoft.UI.Xaml.Controls"
376+
x:Name="ContentPresenter"
377+
Padding="{TemplateBinding Padding}"
378+
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
379+
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
380+
local:AnimatedIcon.State="Normal"
381+
AutomationProperties.AccessibilityView="Raw"
382+
Background="{TemplateBinding Background}"
383+
BackgroundSizing="{TemplateBinding BackgroundSizing}"
384+
BorderBrush="{TemplateBinding BorderBrush}"
385+
BorderThickness="{TemplateBinding BorderThickness}"
386+
Content="{TemplateBinding Content}"
387+
ContentTemplate="{TemplateBinding ContentTemplate}"
388+
ContentTransitions="{TemplateBinding ContentTransitions}"
389+
CornerRadius="{TemplateBinding CornerRadius}"
390+
Foreground="{TemplateBinding Foreground}">
391+
<ContentPresenter.BackgroundTransition>
392+
<BrushTransition Duration="0:0:0.083" />
393+
</ContentPresenter.BackgroundTransition>
394+
395+
<VisualStateManager.VisualStateGroups>
396+
<VisualStateGroup x:Name="CommonStates">
397+
<VisualState x:Name="Normal" />
398+
399+
<VisualState x:Name="PointerOver" />
400+
401+
<VisualState x:Name="Pressed" />
402+
403+
<VisualState x:Name="Disabled">
404+
405+
<Storyboard>
406+
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
407+
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBackgroundDisabled}" />
408+
</ObjectAnimationUsingKeyFrames>
409+
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
410+
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonBorderBrushDisabled}" />
411+
</ObjectAnimationUsingKeyFrames>
412+
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
413+
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SubtleButtonForegroundDisabled}" />
414+
</ObjectAnimationUsingKeyFrames>
415+
</Storyboard>
416+
<VisualState.Setters>
417+
<!-- DisabledVisual Should be handled by the control, not the animated icon. -->
418+
<Setter Target="ContentPresenter.(controls:AnimatedIcon.State)" Value="Normal" />
419+
420+
</VisualState.Setters>
421+
</VisualState>
422+
423+
</VisualStateGroup>
424+
425+
</VisualStateManager.VisualStateGroups>
426+
</ContentPresenter>
427+
428+
</ControlTemplate>
429+
</Setter.Value>
430+
</Setter>
431+
</Style>
432+
357433
</ResourceDictionary>

0 commit comments

Comments
 (0)