Skip to content

Commit 0224099

Browse files
authored
Fix broken radio buttons (#62)
1 parent b309035 commit 0224099

10 files changed

+130
-83
lines changed

Source/App.axaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<StyleInclude Source="/Styles/NumericUpDown.axaml" />
3333
<StyleInclude Source="/Styles/ComboBox.axaml" />
3434
<StyleInclude Source="/Styles/CheckBox.axaml" />
35+
<StyleInclude Source="/Styles/RadioButton.axaml" />
3536

3637
<StyleInclude Source="/Styles/Text.axaml" />
3738

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using ReactiveUI;
2+
3+
namespace MQTTnetApp.Common;
4+
5+
public abstract class BaseSingleSelectionViewModel : BaseViewModel
6+
{
7+
readonly bool[] _states;
8+
9+
protected BaseSingleSelectionViewModel(int count)
10+
{
11+
_states = new bool[count];
12+
}
13+
14+
protected bool GetState(int index)
15+
{
16+
return _states[index];
17+
}
18+
19+
protected void UpdateStates(int changedStateIndex, bool changedStateValue)
20+
{
21+
if (!changedStateValue)
22+
{
23+
// Do not allow "unchecking" the value.
24+
return;
25+
}
26+
27+
for (var i = 0; i < _states.Length; i++)
28+
{
29+
if (i == changedStateIndex)
30+
{
31+
_states[i] = changedStateValue;
32+
}
33+
else
34+
{
35+
_states[i] = !changedStateValue;
36+
}
37+
}
38+
39+
// Notify all properties!
40+
this.RaisePropertyChanged(string.Empty);
41+
}
42+
}

Source/Controls/QualityOfServiceLevel/QualityOfServiceLevelSelectorView.axaml

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,17 @@
99
d:DataContext="{d:DesignInstance controls:QualityOfServiceLevelSelectorViewModel}"
1010
x:Class="MQTTnetApp.Controls.QualityOfServiceLevelSelectorView">
1111
<StackPanel Orientation="Horizontal">
12-
<StackPanel.Styles>
13-
<Style Selector="RadioButton">
14-
<Setter Property="Margin"
15-
Value="0,0,10,0" />
16-
</Style>
17-
</StackPanel.Styles>
12+
<CheckBox Content="At most once - 0"
13+
Classes="radio-button"
14+
IsChecked="{Binding Path=IsLevel0, Mode=TwoWay}" />
1815

19-
<RadioButton GroupName="QoS"
20-
Content="At most once (0)"
21-
IsChecked="{Binding Path=IsLevel0, Mode=TwoWay}" />
16+
<CheckBox Margin="10,0"
17+
Content="At lease once - 1"
18+
Classes="radio-button"
19+
IsChecked="{Binding Path=IsLevel1, Mode=TwoWay}" />
2220

23-
<RadioButton GroupName="QoS"
24-
Content="At lease once (1)"
25-
IsChecked="{Binding Path=IsLevel1, Mode=TwoWay}" />
26-
27-
<RadioButton GroupName="QoS"
28-
Content="Exactly once (2)"
29-
IsChecked="{Binding Path=IsLevel2, Mode=TwoWay}" />
21+
<CheckBox Content="Exactly once - 2"
22+
Classes="radio-button"
23+
IsChecked="{Binding Path=IsLevel2, Mode=TwoWay}" />
3024
</StackPanel>
3125
</UserControl>

Source/Controls/QualityOfServiceLevel/QualityOfServiceLevelSelectorViewModel.cs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,32 @@
11
using System;
22
using MQTTnet.Protocol;
33
using MQTTnetApp.Common;
4-
using ReactiveUI;
54

65
namespace MQTTnetApp.Controls;
76

8-
public sealed class QualityOfServiceLevelSelectorViewModel : BaseViewModel
7+
public sealed class QualityOfServiceLevelSelectorViewModel : BaseSingleSelectionViewModel
98
{
10-
bool _isLevel0 = true;
11-
bool _isLevel1;
12-
bool _isLevel2;
13-
14-
public QualityOfServiceLevelSelectorViewModel()
9+
public QualityOfServiceLevelSelectorViewModel() : base(3)
1510
{
1611
Value = MqttQualityOfServiceLevel.AtMostOnce;
1712
}
1813

1914
public bool IsLevel0
2015
{
21-
get => _isLevel0;
22-
set => this.RaiseAndSetIfChanged(ref _isLevel0, value);
16+
get => GetState(0);
17+
set => UpdateStates(0, value);
2318
}
2419

2520
public bool IsLevel1
2621
{
27-
get => _isLevel1;
28-
set => this.RaiseAndSetIfChanged(ref _isLevel1, value);
22+
get => GetState(1);
23+
set => UpdateStates(1, value);
2924
}
3025

3126
public bool IsLevel2
3227
{
33-
get => _isLevel2;
34-
set => this.RaiseAndSetIfChanged(ref _isLevel2, value);
28+
get => GetState(2);
29+
set => UpdateStates(2, value);
3530
}
3631

3732
public MqttQualityOfServiceLevel Value

Source/Controls/RetainHandling/RetainHandlingSelectorView.axaml

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,17 @@
99
d:DataContext="{d:DesignInstance controls:RetainHandlingSelectorViewModel}"
1010
x:Class="MQTTnetApp.Controls.RetainHandlingSelectorView">
1111
<StackPanel Orientation="Horizontal">
12-
<StackPanel.Styles>
13-
<Style Selector="RadioButton">
14-
<Setter Property="Margin"
15-
Value="0,0,10,0" />
16-
</Style>
17-
</StackPanel.Styles>
12+
<CheckBox IsChecked="{Binding IsSendAtSubscribe, Mode=TwoWay}"
13+
Classes="radio-button"
14+
Content="Send at subscribe (0)" />
1815

19-
<RadioButton IsChecked="{Binding IsSendAtSubscribe, Mode=TwoWay}"
20-
GroupName="RetainHandling"
21-
Content="Send at subscribe (0)" />
16+
<CheckBox Margin="10,0"
17+
IsChecked="{Binding IsSendAtSubscribeIfNewSubscriptionOnly, Mode=TwoWay}"
18+
Classes="radio-button"
19+
Content="Send at subscribe if new subscription only (1)" />
2220

23-
<RadioButton IsChecked="{Binding IsSendAtSubscribeIfNewSubscriptionOnly, Mode=TwoWay}"
24-
GroupName="RetainHandling"
25-
Content="Send at subscribe if new subscription only (1)" />
26-
27-
<RadioButton GroupName="RetainHandling"
28-
IsChecked="{Binding IsDoNotSendOnSubscribe, Mode=TwoWay}"
29-
Content="Do not send on subscribe (2)" />
21+
<CheckBox Classes="radio-button"
22+
IsChecked="{Binding IsDoNotSendOnSubscribe, Mode=TwoWay}"
23+
Content="Do not send on subscribe (2)" />
3024
</StackPanel>
3125
</UserControl>
Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,53 @@
11
using System;
22
using MQTTnet.Protocol;
33
using MQTTnetApp.Common;
4-
using ReactiveUI;
54

65
namespace MQTTnetApp.Controls;
76

8-
public sealed class RetainHandlingSelectorViewModel : BaseViewModel
7+
public sealed class RetainHandlingSelectorViewModel : BaseSingleSelectionViewModel
98
{
10-
bool _doNotSendOnSubscribe;
11-
bool _isSendAtSubscribe;
12-
bool _sendAtSubscribeIfNewSubscriptionOnly;
9+
const int DoNotSendOnSubscribeIndex = 0;
10+
const int SendAtSubscribeIndex = 1;
11+
const int SendAtSubscribeIfNewSubscriptionOnly = 2;
1312

14-
public RetainHandlingSelectorViewModel()
13+
public RetainHandlingSelectorViewModel() : base(3)
1514
{
1615
Value = MqttRetainHandling.SendAtSubscribe;
1716
}
1817

1918
public bool IsDoNotSendOnSubscribe
2019
{
21-
get => _doNotSendOnSubscribe;
22-
set => this.RaiseAndSetIfChanged(ref _doNotSendOnSubscribe, value);
20+
get => GetState(DoNotSendOnSubscribeIndex);
21+
set => UpdateStates(DoNotSendOnSubscribeIndex, value);
2322
}
2423

2524
public bool IsSendAtSubscribe
2625
{
27-
get => _isSendAtSubscribe;
28-
set => this.RaiseAndSetIfChanged(ref _isSendAtSubscribe, value);
26+
get => GetState(SendAtSubscribeIndex);
27+
set => UpdateStates(SendAtSubscribeIndex, value);
2928
}
3029

3130
public bool IsSendAtSubscribeIfNewSubscriptionOnly
3231
{
33-
get => _sendAtSubscribeIfNewSubscriptionOnly;
34-
set => this.RaiseAndSetIfChanged(ref _sendAtSubscribeIfNewSubscriptionOnly, value);
32+
get => GetState(SendAtSubscribeIfNewSubscriptionOnly);
33+
set => UpdateStates(SendAtSubscribeIfNewSubscriptionOnly, value);
3534
}
3635

3736
public MqttRetainHandling Value
3837
{
3938
get
4039
{
41-
if (_isSendAtSubscribe)
40+
if (IsSendAtSubscribe)
4241
{
4342
return MqttRetainHandling.SendAtSubscribe;
4443
}
4544

46-
if (_sendAtSubscribeIfNewSubscriptionOnly)
45+
if (IsSendAtSubscribeIfNewSubscriptionOnly)
4746
{
4847
return MqttRetainHandling.SendAtSubscribeIfNewSubscriptionOnly;
4948
}
5049

51-
if (_doNotSendOnSubscribe)
50+
if (IsDoNotSendOnSubscribe)
5251
{
5352
return MqttRetainHandling.DoNotSendOnSubscribe;
5453
}
@@ -58,9 +57,9 @@ public MqttRetainHandling Value
5857

5958
set
6059
{
61-
_isSendAtSubscribe = value == MqttRetainHandling.SendAtSubscribe;
62-
_doNotSendOnSubscribe = value == MqttRetainHandling.DoNotSendOnSubscribe;
63-
_sendAtSubscribeIfNewSubscriptionOnly = value == MqttRetainHandling.SendAtSubscribeIfNewSubscriptionOnly;
60+
IsSendAtSubscribe = value == MqttRetainHandling.SendAtSubscribe;
61+
IsDoNotSendOnSubscribe = value == MqttRetainHandling.DoNotSendOnSubscribe;
62+
IsSendAtSubscribeIfNewSubscriptionOnly = value == MqttRetainHandling.SendAtSubscribeIfNewSubscriptionOnly;
6463
}
6564
}
6665
}

Source/Pages/Publish/PayloadFormatIndicatorSelectorViewModel.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
11
using System;
22
using MQTTnet.Protocol;
33
using MQTTnetApp.Common;
4-
using ReactiveUI;
54

65
namespace MQTTnetApp.Pages.Publish;
76

8-
public sealed class PayloadFormatIndicatorSelectorViewModel : BaseViewModel
7+
public sealed class PayloadFormatIndicatorSelectorViewModel : BaseSingleSelectionViewModel
98
{
10-
bool _isCharacterData;
11-
bool _isUnspecified = true;
9+
const int CharacterDataIndex = 0;
10+
const int UnspecifiedIndex = 1;
11+
12+
public PayloadFormatIndicatorSelectorViewModel() : base(2)
13+
{
14+
IsUnspecified = true;
15+
}
1216

1317
public bool IsCharacterData
1418
{
15-
get => _isCharacterData;
16-
set => this.RaiseAndSetIfChanged(ref _isCharacterData, value);
19+
get => GetState(CharacterDataIndex);
20+
set => UpdateStates(CharacterDataIndex, value);
1721
}
1822

1923
public bool IsUnspecified
2024
{
21-
get => _isUnspecified;
22-
set => this.RaiseAndSetIfChanged(ref _isUnspecified, value);
25+
get => GetState(UnspecifiedIndex);
26+
set => UpdateStates(UnspecifiedIndex, value);
2327
}
2428

2529
public MqttPayloadFormatIndicator Value

Source/Pages/Publish/PublishItemView.axaml

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,14 @@
7171
Classes="value"
7272
Grid.Column="1"
7373
Orientation="Horizontal">
74-
<StackPanel.Styles>
75-
<Style Selector="RadioButton">
76-
<Setter Property="Margin"
77-
Value="0,0,10,0" />
78-
</Style>
79-
</StackPanel.Styles>
80-
<RadioButton Content="Unspecified"
81-
IsChecked="{Binding PayloadFormatIndicator.IsUnspecified}" />
82-
<RadioButton Content="Character data"
83-
IsChecked="{Binding PayloadFormatIndicator.IsCharacterData}" />
74+
75+
<CheckBox Classes="radio-button"
76+
Content="Unspecified"
77+
IsChecked="{Binding PayloadFormatIndicator.IsUnspecified}" />
78+
<CheckBox Classes="radio-button"
79+
Margin="10,0,0,0"
80+
Content="Character data"
81+
IsChecked="{Binding PayloadFormatIndicator.IsCharacterData}" />
8482
</StackPanel>
8583

8684
<!-- The payload -->
@@ -108,8 +106,8 @@
108106
Grid.Row="0"
109107
Content="Quality of service (QoS) level" />
110108
<controls:QualityOfServiceLevelSelectorView Grid.Column="1"
111-
Grid.Row="0"
112-
DataContext="{Binding QualityOfServiceLevel}" />
109+
Grid.Row="0"
110+
DataContext="{Binding QualityOfServiceLevel}" />
113111
<!-- Retain -->
114112
<Label Classes="caption"
115113
Grid.Column="0"

Source/Styles/CheckBox.axaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,10 @@
1616
Value="26" />
1717
</Style>
1818

19+
<!-- This is a fake radio button because the radio button from avalonia has binding bugs! -->
20+
<Style Selector="CheckBox.radio-button">
21+
<Setter Property="CornerRadius"
22+
Value="50" />
23+
</Style>
24+
1925
</Styles>

Source/Styles/RadioButton.axaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Styles xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
3+
<Design.PreviewWith>
4+
<Border Padding="20">
5+
<!-- Add Controls for Previewer Here -->
6+
</Border>
7+
</Design.PreviewWith>
8+
9+
<Style Selector="RadioButton">
10+
<Setter Property="MinHeight"
11+
Value="26" />
12+
</Style>
13+
14+
</Styles>

0 commit comments

Comments
 (0)