created initial functionality for WPF UI

main
Jonas Arnold 4 years ago
parent 2859e25164
commit 9df44435af
  1. BIN
      ADIS_Csharp/RobotClientWpf/Assets/cog.png
  2. BIN
      ADIS_Csharp/RobotClientWpf/Assets/robot-industrial.png
  3. 19
      ADIS_Csharp/RobotClientWpf/ChallengeFactory.cs
  4. 15
      ADIS_Csharp/RobotClientWpf/IUiService.cs
  5. 47
      ADIS_Csharp/RobotClientWpf/MainWindow.xaml
  6. 110
      ADIS_Csharp/RobotClientWpf/MainWindow.xaml.cs
  7. 27
      ADIS_Csharp/RobotClientWpf/NLog.config
  8. 14
      ADIS_Csharp/RobotClientWpf/RobotClientWpf.csproj
  9. 103
      ADIS_Csharp/RobotClientWpf/Utilities/UIAccessHelpers.cs
  10. 13
      ADIS_Csharp/RobotClientWpf/Views/ConfigView.xaml
  11. 28
      ADIS_Csharp/RobotClientWpf/Views/ConfigView.xaml.cs
  12. 13
      ADIS_Csharp/RobotClientWpf/Views/MainView.xaml
  13. 28
      ADIS_Csharp/RobotClientWpf/Views/MainView.xaml.cs
  14. 33
      ADIS_Csharp/RobotLib/Communication/MqttPublisherSubscriber.cs

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

@ -0,0 +1,19 @@
using RobotLib;
using RobotLib.Communication;
namespace RobotClientWpf
{
internal class ChallengeFactory
{
public MqttPublisherSubscriber PublisherSubscriber { get; }
public Robot RobotStationary { get; }
public Robot RobotMobile { get; }
public ChallengeFactory()
{
this.PublisherSubscriber = MqttPublisherSubscriber.Instance;
//this.RobotStationary = new Robot(this.PublisherSubscriber);
//this.RobotMobile = new Robot(this.PublisherSubscriber);
}
}
}

@ -0,0 +1,15 @@
namespace RobotClientWpf
{
public interface IUiService
{
void DisplayBottomMessage(MessageSeverity severity, string message);
}
public enum MessageSeverity
{
Unknown = 0,
Success,
Warning,
Error,
Information
}
}

@ -4,11 +4,50 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RobotClientWpf"
mc:Ignorable="d"
Title="RobotClientWpf" Height="450" Width="800">
xmlns:views="clr-namespace:RobotClientWpf.Views"
mc:Ignorable="d" FontSize="15"
Title="Challenge UI" Height="700" Width="1200" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
<Grid>
<Button x:Name="buttonBuzz" Content="Beep" HorizontalAlignment="Left" Margin="246,86,0,0" VerticalAlignment="Top" Click="buttonBuzz_Click"/>
<Label x:Name="labelBattery" Content="Battery: 1.25V" HorizontalAlignment="Left" Margin="22,27,0,0" VerticalAlignment="Top"/>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="5">
<Label HorizontalAlignment="Center">MQTT Broker IP: </Label>
<TextBox x:Name="tbIp" Width="120" Height="25" FontSize="15" TextAlignment="Left" Margin="10 0 0 0">192.168.156.156</TextBox>
<Button x:Name="btnConnectDisconnect" Content="Connect" Width="100" Margin="20 0 0 0" Click="btnConnectDisconnect_Click"></Button>
</StackPanel>
<TabControl Grid.Row="1" x:Name="tabControlMain">
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Header" Value="{Binding Header}" />
</Style>
</TabControl.ItemContainerStyle>
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="/Assets/robot-industrial.png" Height="18" />
<TextBlock Text=" Main" Foreground="Green" FontSize="16" />
</StackPanel>
</TabItem.Header>
<views:MainView/>
</TabItem>
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Image Source="/Assets/cog.png" Height="18" />
<TextBlock Text=" Config" Foreground="Blue" FontSize="16"/>
</StackPanel>
</TabItem.Header>
<views:ConfigView/>
</TabItem>
</TabControl>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock x:Name="tbBottomMessage" FontSize="15" Margin="10 5"/>
</StackPanel>
</Grid>
</Window>

@ -1,17 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
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;
using RobotClientWpf.Utilities;
using RobotLib;
namespace RobotClientWpf
@ -21,11 +13,24 @@ namespace RobotClientWpf
/// </summary>
public partial class MainWindow : Window
{
private ChallengeFactory challenge;
private bool manualDisconnect;
public MainWindow()
{
InitializeComponent();
Robot.Instance.Connect("host", 1818);
Robot.Instance.Battery.BatteryChanged += BatteryChanged;
this.challenge = new ChallengeFactory();
this.challenge.PublisherSubscriber.ConnectionStateChanged += PublisherSubscriber_ConnectionStateChanged;
}
private void PublisherSubscriber_ConnectionStateChanged(object? sender, bool e)
{
if(e == false)
{
if (manualDisconnect == true) manualDisconnect = false; return;
this.DisplayBottomMessage(MessageSeverity.Error, "Connection to MQTT broker lost.");
this.SetIpFieldsState(true, true, "Connect");
}
}
private void BatteryChanged(object? sender, BatteryEventArgs e)
@ -37,13 +42,90 @@ namespace RobotClientWpf
}
else
{
labelBattery.Content = $"Battery: {e.Voltage} V";
//labelBattery.Content = $"Battery: {e.Voltage} V";
}
}
private void buttonBuzz_Click(object sender, RoutedEventArgs e)
{
Robot.Instance.Buzzer.Beep(300, 500);
//Robot.Instance.Buzzer.Beep(300, 500);
}
private void btnConnectDisconnect_Click(object sender, RoutedEventArgs e)
{
Task.Run(delegate ()
{
this.ClearBottomMessage();
if (this.challenge.PublisherSubscriber.IsConnected) // is connected => disconnect
{
manualDisconnect = true; // prevent wrong message
this.challenge.PublisherSubscriber.Disconnect();
this.DisplayBottomMessage(MessageSeverity.Success, "Disconnected from MQTT broker.");
this.SetIpFieldsState(true, true, "Connect");
}
else // is not yet connected => connect
{
this.SetIpFieldsState(false, false, "Connecting...");
string ipAddress = UIAccessHelpers.GetTextboxText(tbIp);
if (IPAddress.TryParse(ipAddress, out _))
{
var connectionSuccess = this.challenge.PublisherSubscriber.Connect(ipAddress);
if (connectionSuccess)
{
this.DisplayBottomMessage(MessageSeverity.Success, "Successfully connected to MQTT broker.");
this.SetIpFieldsState(false, true, "Disconnect");
}
else
{
this.DisplayBottomMessage(MessageSeverity.Error, $"Failed to connect to MQTT broker on address {ipAddress}.");
this.SetIpFieldsState(true, true, "Connect");
}
}
else
{
this.DisplayBottomMessage(MessageSeverity.Error, $"Unable to parse MQTT Broker IP address {ipAddress}.");
this.SetIpFieldsState(true, true, "Connect");
}
}
});
}
private void SetIpFieldsState(bool ipTextbox, bool connectDisconnectButton, string buttonText)
{
UIAccessHelpers.SetButtonState(btnConnectDisconnect, connectDisconnectButton);
UIAccessHelpers.SetTextboxState(tbIp, ipTextbox);
UIAccessHelpers.SetButtonContent(btnConnectDisconnect, buttonText);
}
public void DisplayBottomMessage(MessageSeverity severity, string message)
{
Brush col;
switch (severity)
{
case MessageSeverity.Success:
col = Brushes.Green;
break;
case MessageSeverity.Warning:
col = Brushes.Orange;
break;
case MessageSeverity.Error:
col = Brushes.Red;
break;
case MessageSeverity.Information:
col = Brushes.Blue;
break;
case MessageSeverity.Unknown:
default:
col = Brushes.DarkGray;
break;
}
UIAccessHelpers.SetTextblockTextAndForegroundColor(tbBottomMessage, message, col);
}
private void ClearBottomMessage()
{
this.DisplayBottomMessage(MessageSeverity.Information, "");
}
}
}

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target xsi:type="RichTextBox"
name="String"
layout="Layout"
height="Integer"
autoScroll="Boolean"
maxLines="Integer"
showMinimized="Boolean"
toolWindow="Boolean"
controlName="String"
formName="String"
width="Integer"
useDefaultRowColoringRules="Boolean">
<word-coloring backgroundColor="String" fontColor="String" ignoreCase="Boolean"
regex="String" style="Enum" text="String"
wholeWords="Boolean"/>
<!-- repeated -->
<row-coloring backgroundColor="String" condition="Condition" fontColor="String"
style="Enum"/>
<!-- repeated -->
</target>
</targets>
</nlog>

@ -7,8 +7,22 @@
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<None Remove="Assets\cog.png" />
<None Remove="Assets\robot-industrial.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RobotLib\RobotLib.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="Assets\cog.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
<Resource Include="Assets\robot-industrial.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
</ItemGroup>
</Project>

@ -0,0 +1,103 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace RobotClientWpf.Utilities
{
public static class UIAccessHelpers
{
public static void SetButtonState(ButtonBase button, bool enabled)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
SetButtonState(button, enabled);
}));
}
else
{
button.IsEnabled = enabled;
}
}
public static void SetButtonContent(ButtonBase button, string content)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
SetButtonContent(button, content);
}));
}
else
{
button.Content = content;
}
}
public static string GetTextboxText(TextBox textBox)
{
string text = String.Empty;
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
text = GetTextboxText(textBox);
})).Wait();
}
else
{
text = textBox.Text;
}
return text;
}
public static void SetTextboxState(TextBoxBase textBox, bool enabled)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
SetTextboxState(textBox, enabled);
}));
}
else
{
textBox.IsEnabled = enabled;
}
}
public static void SetTextboxText(TextBox textBox, string text)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
SetTextboxText(textBox, text);
}));
}
else
{
textBox.Text = text;
}
}
public static void SetTextblockTextAndForegroundColor(TextBlock textBlock, string text, Brush foregroundColor)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
SetTextblockTextAndForegroundColor(textBlock, text, foregroundColor);
}));
}
else
{
textBlock.Text = text;
textBlock.Foreground = foregroundColor;
}
}
}
}

@ -0,0 +1,13 @@
<UserControl x:Class="RobotClientWpf.Views.ConfigView"
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:RobotClientWpf.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Label Content="Config" HorizontalAlignment="Left" Margin="190,132,0,0" VerticalAlignment="Top"/>
</Grid>
</UserControl>

@ -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 RobotClientWpf.Views
{
/// <summary>
/// Interaction logic for ConfigView.xaml
/// </summary>
public partial class ConfigView : UserControl
{
public ConfigView()
{
InitializeComponent();
}
}
}

@ -0,0 +1,13 @@
<UserControl x:Class="RobotClientWpf.Views.MainView"
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:RobotClientWpf.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Label Content="Main" HorizontalAlignment="Left" Margin="443,192,0,0" VerticalAlignment="Top"/>
</Grid>
</UserControl>

@ -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 RobotClientWpf.Views
{
/// <summary>
/// Interaction logic for MainView.xaml
/// </summary>
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
}
}

@ -21,10 +21,28 @@ namespace RobotLib.Communication
/// </summary>
public event EventHandler<SubscribedMsgArrivedEventArgs> NewMessageArrived;
/// <summary>
/// Event to catch for the connection state to the broker.
/// </summary>
public event EventHandler<bool> ConnectionStateChanged;
/// <summary>
/// Connection state to the broker.
/// </summary>
public bool IsConnected { get ; private set; }
public bool IsConnected
{
get { return _isConnected; }
private set
{
// generate event if the value has changed
if(_isConnected != value)
{
this.ConnectionStateChanged?.Invoke(this, value);
}
_isConnected = value;
}
}
private bool _isConnected;
private MqttPublisherSubscriber()
{ }
@ -63,6 +81,8 @@ namespace RobotLib.Communication
client.ConnectionClosed += Client_ConnectionClosed;
// generate a clientID and connect to Broker
string clientId = Guid.NewGuid().ToString();
try
{
if (String.IsNullOrEmpty(username) || String.IsNullOrEmpty(password))
{
client.Connect(clientId);
@ -71,6 +91,12 @@ namespace RobotLib.Communication
{
client.Connect(clientId, username, password);
}
}
catch (Exception ex)
{
log.Error(ex.Message);
}
success = client.IsConnected;
log.Info($"Connecting done. Success = {success}");
}
@ -83,7 +109,12 @@ namespace RobotLib.Communication
{
if (IsConnected == false) return;
try
{
client.Disconnect();
}
catch { }
log.Info($"Disconnect was called.");
IsConnected = false;
}

Loading…
Cancel
Save