I am designing an interface using WinUI3. And I want to use a list of AppBarButton
to show the connection status via the Icon
of the AppBarButton
.
Because the status would change, I use two FontIcon
named disconnectedIcon
and connectedIcon
, and set the Icon
property to one of them to show the current connection status.
A ContentDialog
named connectDialog
will pop up after clicking tester1ConnectionButton
or tester2ConnectionButton
to have the user fill in the name of the machine(optional) and the IP address of the machine.
After clicking Connect
button in the connectDialog
, the process will start connecting. Once the connection done, the Icon
of the button will set to connectedIcon
. Vice versa.
However, this error pops up sometimes when running the code which sets the Icon
property (Not only the ones pop up the connectDialog
):
System.ArgumentException: 'Value does not fall within the expected range.'
Here are the codes:
MainWindow.xaml
<Window
x:Class="TesterWinUI3_240606.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TesterWinUI3_240606"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid RowDefinitions="auto,*,auto,auto,auto,*,auto,auto" ColumnDefinitions="auto, auto, auto, *">
<!--Upper part-->
<Grid Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3">
<Border BorderBrush="{ThemeResource ControlStrongStrokeColorDefaultBrush}" BorderThickness="2.5" CornerRadius="3" Margin="5">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
<!--Title at the top-->
<TextBlock Text="Connection" FontSize="16" FontWeight="Bold" Margin="5"/>
<!--Connection settings-->
<AppBarElementContainer VerticalAlignment="Center">
<StackPanel Orientation="Vertical">
<TextBlock Text="Handler" Margin="5"/>
<AppBarButton x:Name="handlerConnectionButton" Label="Disconnected" Width="80" Click="handlerConnectionButton_Click">
<FontIcon Glyph=""/>
</AppBarButton>
</StackPanel>
</AppBarElementContainer>
<AppBarSeparator/>
<AppBarElementContainer VerticalAlignment="Center">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="tester1NameTextBlock" Text="TESTER 1" Margin="5"/>
<AppBarButton x:Name="tester1ConnectionButton" Label="Disconnected" Width="80" Click="tester1ConnectionButton_Click">
<FontIcon Glyph=""/>
<!--<FontIcon Glyph=""/>-->
</AppBarButton>
</StackPanel>
</AppBarElementContainer>
<AppBarElementContainer VerticalAlignment="Center">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="tester2NameTextBlock" Text="TESTER 2" Margin="5"/>
<AppBarButton x:Name="tester2ConnectionButton" Label="Disconnected" Width="80" Click="tester2ConnectionButton_Click">
<FontIcon Glyph=""/>
</AppBarButton>
</StackPanel>
</AppBarElementContainer>
</StackPanel>
</Border>
</Grid>
<!-- Other UI -->
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System.Drawing.Text;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.ApplicationModel.DataTransfer;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace TesterWinUI3_240606
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : Window
{
// ...
// Flags for connection status
private bool isHandlerConnected = false;
private bool isTester1Connected = false;
private bool isTester2Connected = false;
FontIcon disconnectedIcon;
FontIcon connectedIcon;
private string tester1Name = "TESTER 1";
private string tester2Name = "TESTER 2";
public MainWindow()
{
this.InitializeComponent();
// ...
// Icon
// Reference:https://stackoverflow.com/questions/34724792/how-to-programmatically-create-textblock-using-segoe-mdl2-assets-font-in-wpf
disconnectedIcon = new FontIcon();
disconnectedIcon.Glyph = "\uF78A"; // -> CancelMedium, unicode character code
disconnectedIcon.FontFamily = new FontFamily("Segoe MDL2 Assets");
//{
// Glyph = "\uF78A", // -> CancelMedium, unicode character code
// //Glyph = "\xF78A", // -> CancelMedium, hex character code
// //Glyph = "\xEB90", // -> StatusErrorFull, hex character code
// FontFamily = new FontFamily("Segoe MDL2 Assets"),
//};
connectedIcon = new FontIcon();
connectedIcon.Glyph = "\uF78C"; // -> AcceptMedium, unicode character code
connectedIcon.FontFamily = new FontFamily("Segoe MDL2 Assets");
//{
// Glyph = "\uF78C",
// //Glyph = "\xF78C", // -> AcceptMedium, hex character code
// //Glyph = "\xEC61", // -> CompletedSolid, hex character code
// FontFamily = new FontFamily("Segoe MDL2 Assets"),
//};
}
// Other methods...
private void handlerConnectionButton_Click(object sender, RoutedEventArgs e)
{
if (isHandlerConnected == true)
{
// Disconnect from handler
isHandlerConnected = false;
handlerConnectionButton.Label = "Disconnected";
handlerConnectionButton.Icon = disconnectedIcon;
//handlerConnectionButton.Content = "Disconnected";
return;
}
// Connect to handler
isHandlerConnected = true;
handlerConnectionButton.Label = "Connected";
handlerConnectionButton.Icon = connectedIcon;
//handlerConnectionButton.Content = "Connected";
}
private async void tester1ConnectionButton_Click(object sender, RoutedEventArgs e)
{
if (isTester1Connected == true)
{
// Disconnect from TESTER 1
isTester1Connected = false;
tester1ConnectionButton.Label = "Disconnected";
tester1ConnectionButton.Icon = disconnectedIcon;
//tester1ConnectionButton.Content = "Disconnected";
return;
}
// Connect to TESTER 1
ContentDialog connectDialog = new ContentDialog
{
XamlRoot = Content.XamlRoot,
Title = "Connect to TESTER 1",
Content = new StackPanel
{
Orientation = Orientation.Vertical,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Center,
Children =
{
new TextBlock { Text = "Name the TESTER:" },
new TextBox { Name = "tester1NameTextBox", PlaceholderText = tester1Name },
new TextBlock { Text = "Enter the IP address of TESTER:" },
new TextBox { Name = "tester1IP"}
},
Padding = new Thickness(5),
},
PrimaryButtonText = "Connect",
CloseButtonText = "Cancel",
DefaultButton = ContentDialogButton.Primary,
};
ContentDialogResult result = await connectDialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
TextBox nameTextBox = (TextBox)((StackPanel)connectDialog.Content).Children[1];
TextBox ipTextBox = (TextBox)((StackPanel)connectDialog.Content).Children[3];
tester1Name = nameTextBox.Text.Trim();
string ip = ipTextBox.Text.Trim();
if (string.IsNullOrEmpty(ip) == false)
{
// Connect to TESTER 1
isTester1Connected = true;
tester1ConnectionButton.Label = "Connected";
tester1ConnectionButton.Icon = connectedIcon;
//tester1ConnectionButton.Content = "Connected";
if (string.IsNullOrEmpty(stest1Name) == false)
{
tester1NameTextBlock.Text = tester1Name;
}
}
}
}
private async void tester2ConnectionButton_Click(object sender, RoutedEventArgs e)
{
if (isTester2Connected == true)
{
// Disconnect from TESTER 2
isTester2Connected = false;
tester2ConnectionButton.Label = "Disconnected";
tester2ConnectionButton.Icon = disconnectedIcon;
//tester2ConnectionButton.Content = "Disconnected";
return;
}
// Connect to TESTER 2
ContentDialog connectDialog = new ContentDialog
{
XamlRoot = Content.XamlRoot,
Title = "Connect to TESTER 2",
Content = new StackPanel
{
Orientation = Orientation.Vertical,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Center,
Children =
{
new TextBlock { Text = "Name the TESTER:" },
new TextBox { Name = "tester2NameTextBox", PlaceholderText = tester2Name },
new TextBlock { Text = "Enter the IP address of TESTER:" },
new TextBox { Name = "tester2IP"}
},
Padding = new Thickness(5),
},
PrimaryButtonText = "Connect",
CloseButtonText = "Cancel",
DefaultButton = ContentDialogButton.Primary,
};
ContentDialogResult result = await connectDialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
TextBox nameTextBox = (TextBox)((StackPanel)connectDialog.Content).Children[1];
TextBox ipTextBox = (TextBox)((StackPanel)connectDialog.Content).Children[3];
tester2Name = nameTextBox.Text.Trim();
string ip = ipTextBox.Text.Trim();
if (string.IsNullOrEmpty(ip) == false)
{
// Connect to TESTER 2
isTester2Connected = true;
tester2ConnectionButton.Label = "Connected";
tester2ConnectionButton.Icon = connectedIcon;
//tester2ConnectionButton.Content = "Connected";
if (string.IsNullOrEmpty(tester2Name) == false)
{
tester2NameTextBlock.Text = tester2Name;
}
}
}
}
}
}
The only information I know is that it happens sometimes after it step in the if-
block:
if (result == ContentDialogResult.Primary)
Is there a solution to fix this error?
It can be reproduced stably by making two AppBarButton.Icon
properties refer to the same FontIcon
resource. You can make every AppBarButton.Icon
has its own FontIcon
resource.