Skip to content

Commit 4a99e96

Browse files
committed
feat: add ImageToggledButton
1 parent b265be3 commit 4a99e96

File tree

7 files changed

+303
-3
lines changed

7 files changed

+303
-3
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<UserControl
2+
x:Class="Atc.Wpf.Sample.SamplesWpfTheming.InputButton.ImageToggledButton"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:atc="https://github.com/atc-net/atc-wpf/tree/main/schemas"
6+
xmlns:atcValueConverters="https://github.com/atc-net/atc-wpf/tree/main/schemas/value-converters"
7+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
8+
xmlns:fontIcons="clr-namespace:Atc.Wpf.FontIcons;assembly=Atc.Wpf.FontIcons"
9+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
10+
d:DesignHeight="450"
11+
d:DesignWidth="800"
12+
mc:Ignorable="d">
13+
14+
<atc:AutoGrid Columns="*" Rows="Auto,*">
15+
16+
<GroupBox
17+
Margin="0,0,0,10"
18+
Padding="10"
19+
Header="Features">
20+
21+
<StackPanel>
22+
<atc:LabelCheckBox
23+
x:Name="CbIsBusy"
24+
HideAreas="All"
25+
LabelText="IsBusy" />
26+
27+
<atc:LabelToggleSwitch
28+
x:Name="CbIsPrimary"
29+
HideAreas="All"
30+
LabelText="State"
31+
OffText="Secondary"
32+
OnText="Primary" />
33+
</StackPanel>
34+
35+
</GroupBox>
36+
37+
<GroupBox Header="Usage">
38+
<ScrollViewer>
39+
<atc:GridEx Columns="*,10,*" ShowGridLines="True">
40+
<atc:UniformSpacingPanel
41+
Grid.Column="0"
42+
Margin="10"
43+
Orientation="Vertical"
44+
Spacing="10">
45+
46+
<atc:UniformSpacingPanel
47+
ItemWidth="100"
48+
Orientation="Horizontal"
49+
Spacing="10">
50+
51+
<atc:UniformSpacingPanel Orientation="Vertical" Spacing="10">
52+
53+
<atc:ImageToggledButton
54+
HorizontalContentAlignment="Left"
55+
ImageBorderSpacing="5"
56+
ImageContentSpacing="10"
57+
IsBusy="{Binding ElementName=CbIsBusy, Path=IsChecked}"
58+
IsToggled="{Binding ElementName=CbIsPrimary, Path=IsOn}"
59+
OffContent="State Off"
60+
OffImageSource="/Assets/error.png"
61+
OnContent="State On"
62+
OnImageSource="/Assets/ok.png" />
63+
64+
<atc:ImageToggledButton
65+
IsBusy="{Binding ElementName=CbIsBusy, Path=IsChecked}"
66+
IsToggled="{Binding ElementName=CbIsPrimary, Path=IsOn}"
67+
OffContent="Login"
68+
OffSvgImageSource="/Atc.Wpf.Sample;component/Assets/eggeaster.svg"
69+
OnContent="Logout"
70+
OnSvgImageSource="/Atc.Wpf.Sample;component/Assets/a.svg" />
71+
72+
</atc:UniformSpacingPanel>
73+
74+
</atc:UniformSpacingPanel>
75+
76+
</atc:UniformSpacingPanel>
77+
<atc:UniformSpacingPanel
78+
Grid.Column="2"
79+
Margin="10"
80+
Orientation="Vertical"
81+
Spacing="10">
82+
83+
<atc:UniformSpacingPanel
84+
ItemWidth="100"
85+
Orientation="Horizontal"
86+
Spacing="10">
87+
88+
<atc:UniformSpacingPanel Orientation="Vertical" Spacing="10">
89+
90+
<atc:ImageToggledButton
91+
IsBusy="{Binding Path=IsBusy}"
92+
IsToggled="{Binding Path=IsConnected}"
93+
OffCommand="{Binding Path=ConnectCommand}"
94+
OffContent="Login"
95+
OffImageSource="{Binding Source={x:Static fontIcons:FontMaterialDesignType.Login}, Converter={x:Static atcValueConverters:FontIconImageSourceValueConverter.Instance}, ConverterParameter={StaticResource AtcApps.Brushes.ThemeForeground}}"
96+
OnCommand="{Binding Path=DisconnectCommand}"
97+
OnContent="Logout"
98+
OnImageSource="{Binding Source={x:Static fontIcons:FontMaterialDesignType.Logout}, Converter={x:Static atcValueConverters:FontIconImageSourceValueConverter.Instance}, ConverterParameter={StaticResource AtcApps.Brushes.Accent}}" />
99+
100+
</atc:UniformSpacingPanel>
101+
102+
</atc:UniformSpacingPanel>
103+
104+
</atc:UniformSpacingPanel>
105+
</atc:GridEx>
106+
</ScrollViewer>
107+
</GroupBox>
108+
</atc:AutoGrid>
109+
110+
</UserControl>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
namespace Atc.Wpf.Sample.SamplesWpfTheming.InputButton;
2+
3+
public partial class ImageToggledButton
4+
{
5+
public ImageToggledButton()
6+
{
7+
InitializeComponent();
8+
9+
DataContext = this;
10+
}
11+
12+
[DependencyProperty]
13+
private bool isBusy;
14+
15+
[DependencyProperty]
16+
private bool isConnected;
17+
18+
[RelayCommand]
19+
private async Task Connect()
20+
{
21+
IsBusy = true;
22+
23+
await Task
24+
.Delay(2_000)
25+
.ConfigureAwait(false);
26+
27+
await Application.Current.Dispatcher
28+
.InvokeAsyncIfRequired(() =>
29+
{
30+
IsConnected = true;
31+
IsBusy = false;
32+
})
33+
.ConfigureAwait(false);
34+
}
35+
36+
[RelayCommand]
37+
private async Task Disconnect()
38+
{
39+
IsBusy = true;
40+
41+
await Task
42+
.Delay(500)
43+
.ConfigureAwait(false);
44+
45+
await Application.Current.Dispatcher
46+
.InvokeAsyncIfRequired(() =>
47+
{
48+
IsConnected = false;
49+
IsBusy = false;
50+
})
51+
.ConfigureAwait(false);
52+
}
53+
}

sample/Atc.Wpf.Sample/SamplesWpfThemingTreeView.xaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
Header="ImageButton"
3030
IsExpanded="True"
3131
SamplePath="InputButton.ImageButtonView" />
32+
<sample:SampleTreeViewItem
33+
Header="ImageToggledButton"
34+
IsExpanded="True"
35+
SamplePath="InputButton.ImageToggledButton" />
3236
<TreeViewItem
3337
Header="ToggleButton"
3438
IsEnabled="False"

src/Atc.Wpf.Controls/BaseControls/ImageButton.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace Atc.Wpf.Controls.BaseControls;
22

3-
public sealed partial class ImageButton : Button
3+
public partial class ImageButton : Button
44
{
55
[DependencyProperty(
66
DefaultValue = null,
@@ -20,7 +20,7 @@ public sealed partial class ImageButton : Button
2020
private double imageBorderSpacing;
2121

2222
[DependencyProperty]
23-
private ImageSource imageSource;
23+
private ImageSource? imageSource;
2424

2525
[DependencyProperty(DefaultValue = "")]
2626
private string svgImageSource;
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
namespace Atc.Wpf.Controls.BaseControls;
2+
3+
public sealed partial class ImageToggledButton : ImageButton
4+
{
5+
[DependencyProperty(
6+
DefaultValue = false,
7+
PropertyChangedCallback = nameof(OnToggledChanged))]
8+
private bool isToggled;
9+
10+
[DependencyProperty]
11+
private object? onContent;
12+
13+
[DependencyProperty]
14+
private object? offContent;
15+
16+
[DependencyProperty]
17+
private ImageSource? onImageSource;
18+
19+
[DependencyProperty]
20+
private ImageSource? offImageSource;
21+
22+
[DependencyProperty(DefaultValue = "")]
23+
private string onSvgImageSource;
24+
25+
[DependencyProperty(DefaultValue = "")]
26+
private string offSvgImageSource;
27+
28+
[DependencyProperty]
29+
private Color? onSvgImageOverrideColor;
30+
31+
[DependencyProperty]
32+
private Color? offSvgImageOverrideColor;
33+
34+
[DependencyProperty]
35+
private ICommand? onCommand;
36+
37+
[DependencyProperty]
38+
private ICommand? offCommand;
39+
40+
static ImageToggledButton()
41+
{
42+
DefaultStyleKeyProperty.OverrideMetadata(
43+
typeof(ImageToggledButton),
44+
new FrameworkPropertyMetadata(typeof(ImageButton)));
45+
}
46+
47+
public ImageToggledButton()
48+
{
49+
// Initialise with the Off state visual when loaded.
50+
Loaded += (_, _) => ApplyVisualState(IsToggled);
51+
}
52+
53+
protected override void OnClick()
54+
{
55+
base.OnClick();
56+
57+
IsToggled = !IsToggled;
58+
59+
ExecuteCurrentCommand();
60+
}
61+
62+
private static void OnToggledChanged(
63+
DependencyObject d,
64+
DependencyPropertyChangedEventArgs e)
65+
{
66+
var ctl = (ImageToggledButton)d;
67+
ctl.ApplyVisualState((bool)e.NewValue);
68+
}
69+
70+
private void ApplyVisualState(
71+
bool toggled)
72+
{
73+
if (toggled)
74+
{
75+
// ON state
76+
if (OnContent is not null)
77+
{
78+
SetCurrentValue(ContentProperty, OnContent);
79+
}
80+
81+
if (OnImageSource is not null)
82+
{
83+
SetCurrentValue(ImageSourceProperty, OnImageSource);
84+
}
85+
86+
if (!string.IsNullOrEmpty(OnSvgImageSource))
87+
{
88+
SetCurrentValue(SvgImageSourceProperty, OnSvgImageSource);
89+
}
90+
91+
if (OnSvgImageOverrideColor is not null)
92+
{
93+
SetCurrentValue(SvgImageOverrideColorProperty, OnSvgImageOverrideColor);
94+
}
95+
}
96+
else
97+
{
98+
// OFF state
99+
if (OffContent is not null)
100+
{
101+
SetCurrentValue(ContentProperty, OffContent);
102+
}
103+
104+
if (OffImageSource is not null)
105+
{
106+
SetCurrentValue(ImageSourceProperty, OffImageSource);
107+
}
108+
109+
if (!string.IsNullOrEmpty(OffSvgImageSource))
110+
{
111+
SetCurrentValue(SvgImageSourceProperty, OffSvgImageSource);
112+
}
113+
114+
if (OffSvgImageOverrideColor is not null)
115+
{
116+
SetCurrentValue(SvgImageOverrideColorProperty, OffSvgImageOverrideColor);
117+
}
118+
}
119+
}
120+
121+
private void ExecuteCurrentCommand()
122+
{
123+
var cmd = IsToggled
124+
? OffCommand
125+
: OnCommand;
126+
127+
if (cmd?.CanExecute(parameter: null) == true)
128+
{
129+
cmd.Execute(parameter: null);
130+
}
131+
}
132+
}

src/Atc.Wpf.Controls/Styles/Controls.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
<Style BasedOn="{StaticResource AtcApps.Styles.NumericBox}" TargetType="{x:Type baseControls:NumericBox}" />
2020
<Style BasedOn="{StaticResource AtcApps.Styles.ImageButton}" TargetType="{x:Type baseControls:ImageButton}" />
21+
<Style BasedOn="{StaticResource AtcApps.Styles.ImageButton}" TargetType="{x:Type baseControls:ImageToggledButton}" />
2122
<Style BasedOn="{StaticResource AtcApps.Styles.DecimalBox}" TargetType="{x:Type baseControls:DecimalBox}" />
2223
<Style BasedOn="{StaticResource AtcApps.Styles.IntegerBox}" TargetType="{x:Type baseControls:IntegerBox}" />
2324
<Style BasedOn="{StaticResource AtcApps.Styles.ToggleSwitch}" TargetType="{x:Type baseControls:ToggleSwitch}" />

src/Atc.Wpf/Controls/Media/SvgImage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ private static void OnSourceChanged(
314314
}
315315

316316
var uri = e.NewValue?.ToString();
317-
if (string.IsNullOrEmpty(uri))
317+
if (string.IsNullOrEmpty(uri) || uri.StartsWith("System.", StringComparison.Ordinal))
318318
{
319319
return;
320320
}

0 commit comments

Comments
 (0)