Skip to content

Commit

Permalink
Bam. Connections are saving. We're up and running.
Browse files Browse the repository at this point in the history
  • Loading branch information
rquackenbush committed Feb 11, 2019
1 parent 6a2adf7 commit 0b07336
Show file tree
Hide file tree
Showing 15 changed files with 585 additions and 22 deletions.
91 changes: 91 additions & 0 deletions src/NModbus.Tools.Base/Behaviors/CloseableBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interactivity;

namespace NModbus.Tools.Base.Behaviors
{
/// <summary>
/// Provides a simple interface for windows that should be closeable from their view model.
/// </summary>
public class CloseableBehavior : Behavior<Window>
{
private ICloseableViewModel _closeable;

/// <summary>
/// Called after the behavior is attached to an AssociatedObject.
/// </summary>
/// <remarks>
/// Override this to hook up functionality to the AssociatedObject.
/// </remarks>
protected override void OnAttached()
{
AssociatedObject.Closing += AssociatedObject_Closing;
AssociatedObject.DataContextChanged += AssociatedObject_DataContextChanged;
AssociatedObject.Closed += AssociatedObject_Closed;

_closeable = this.AssociatedObject.DataContext as ICloseableViewModel;

if (_closeable != null)
_closeable.Close += Closeable_Close;

base.OnAttached();
}

/// <summary>
/// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
/// </summary>
/// <remarks>
/// Override this to unhook functionality from the AssociatedObject.
/// </remarks>
protected override void OnDetaching()
{
base.OnDetaching();

AssociatedObject.Closing -= AssociatedObject_Closing;
AssociatedObject.DataContextChanged -= AssociatedObject_DataContextChanged;
AssociatedObject.Closed -= AssociatedObject_Closed;
}

void AssociatedObject_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (_closeable != null)
_closeable.Close -= Closeable_Close;

_closeable = e.NewValue as ICloseableViewModel;

if (_closeable != null)
_closeable.Close += Closeable_Close;
}

void Closeable_Close(object sender, CloseEventArgs e)
{
//https://social.msdn.microsoft.com/Forums/vstudio/en-US/c95f1acb-5dee-4670-b779-b07b06afafff/where-is-modal-property?forum=wpf
if (System.Windows.Interop.ComponentDispatcher.IsThreadModal)
{
AssociatedObject.DialogResult = e.DialogResult;
}

AssociatedObject.Close();
}

void AssociatedObject_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (_closeable != null)
{
if (!_closeable.CanClose())
{
e.Cancel = true;
}
}
}

void AssociatedObject_Closed(object sender, System.EventArgs e)
{
_closeable?.Closed();
}
}
}
46 changes: 46 additions & 0 deletions src/NModbus.Tools.Base/Behaviors/ICloseableViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;

namespace NModbus.Tools.Base.Behaviors
{
/// <summary>
///
/// </summary>
public interface ICloseableViewModel
{
/// <summary>
/// Fired when the view model requests that its container be closed.
/// </summary>
event EventHandler<CloseEventArgs> Close;

/// <summary>
/// Returns true if the container can be closed, false otherwise.
/// </summary>
/// <returns></returns>
bool CanClose();

/// <summary>
/// Called when the view has been closed.
/// </summary>
void Closed();
}

/// <summary>
///
/// </summary>
public class CloseEventArgs : EventArgs
{
/// <summary>
///
/// </summary>
/// <param name="dialogResult"></param>
public CloseEventArgs(bool? dialogResult)
{
this.DialogResult = dialogResult;
}

/// <summary>
///
/// </summary>
public bool? DialogResult { get; set; }
}
}
78 changes: 78 additions & 0 deletions src/NModbus.Tools.Base/ConnectionSelectionService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using Newtonsoft.Json;
using NModbus.Tools.Base.Model;
using NModbus.Tools.Base.View;
using NModbus.Tools.Base.ViewModel;
using NModbus.Tools.Interfaces;
using System;
using System.IO;
using System.Windows;

namespace NModbus.Tools.Base
{
public class ConnectionSelectionService : IConnectionSelectionService
{
private static readonly string FilePath;

static ConnectionSelectionService()
{
FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NModbus Tools", "connections.json");
}

public Connection GetConnection()
{
var connections = GetConnections();

var viewModel = new ConnectionSelectionViewModel(connections);

var view = new ConnectionSelectionDialog
{
DataContext = viewModel
};

if (view.ShowDialog() == true)
{
SaveConnections(viewModel.ToModel());

return viewModel.SelectedConnection.ToModel();
}

return null;
}

private void SaveConnections(SavedConnections connections)
{
var json = JsonConvert.SerializeObject(connections);

var directory = Path.GetDirectoryName(FilePath);

Directory.CreateDirectory(directory);

File.WriteAllText(FilePath, json);
}

private SavedConnections GetConnections()
{
try
{
var json = File.ReadAllText(FilePath);

var connections = JsonConvert.DeserializeObject<SavedConnections>(json);

if (connections.Connections == null)
{
connections.Connections = new Connection[] { };
}

return connections;
}
catch(Exception)
{
return new SavedConnections
{
Connections = new Connection[] { }
};
}

}
}
}
Binary file added src/NModbus.Tools.Base/Images/AddLink_16x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/NModbus.Tools.Base/Images/Link_16xMD.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/NModbus.Tools.Base/Images/RemoveLink_16x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 35 additions & 8 deletions src/NModbus.Tools.Base/Model/ConnectionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,33 @@

namespace NModbus.Tools.Base.Model
{
public class ConnectionFactory
public class ConnectionFactory : IModbusMasterFactory
{
private const int TcpConnectionTimeoutMilliseconds = 10 * 1000;
private readonly Connection _connection;

public IModbusMaster CreateAsync(Connection connection)
public ConnectionFactory(Connection connection)
{
_connection = connection;
}

public IModbusMaster Create()
{
var factory = new ModbusFactory();

switch (connection.Type)
switch (_connection.Type)
{
case ConnectionType.Rtu:
{
var serialPort = CreateAndOpenSerialPort(connection);
var serialPort = CreateAndOpenSerialPort(_connection);

var transport = new SerialPortAdapter(serialPort);

return factory.CreateRtuMaster(transport);
}
case ConnectionType.Ascii:
{
var serialPort = CreateAndOpenSerialPort(connection);
var serialPort = CreateAndOpenSerialPort(_connection);

var transport = new SerialPortAdapter(serialPort);

Expand All @@ -35,9 +41,9 @@ public IModbusMaster CreateAsync(Connection connection)
{
var tcpClient = new TcpClient();

if (!tcpClient.ConnectAsync(connection.HostName, connection.Port).Wait(TcpConnectionTimeoutMilliseconds))
if (!tcpClient.ConnectAsync(_connection.HostName, _connection.Port).Wait(TcpConnectionTimeoutMilliseconds))
{
throw new TimeoutException($"Timed out trying to connect to TCP Modbus device at {connection.HostName}:{connection.Port}");
throw new TimeoutException($"Timed out trying to connect to TCP Modbus device at {_connection.HostName}:{_connection.Port}");
}

return factory.CreateMaster(tcpClient);
Expand All @@ -49,7 +55,7 @@ public IModbusMaster CreateAsync(Connection connection)
return factory.CreateMaster(udpClient);
}
default:
throw new ArgumentException($"{nameof(connection.Type)} had an unepected value '{connection.Type}'.");
throw new ArgumentException($"{nameof(_connection.Type)} had an unepected value '{_connection.Type}'.");
}
}

Expand All @@ -70,5 +76,26 @@ private SerialPort CreateAndOpenSerialPort(Connection connection)

return serialPort;
}

public override string ToString()
{
switch (_connection.Type)
{
case ConnectionType.Tcp:
return $"TCP {_connection.HostName}:{_connection.Port}";

case ConnectionType.Udp:
return $"UDP {_connection.HostName}:{_connection.Port}";

case ConnectionType.Rtu:
return $"RTU {_connection.SerialPortName} ({_connection.Baud})";

case ConnectionType.Ascii:
return $"ASCII {_connection.SerialPortName} ({_connection.Baud})";

default:
return "Unknown Type";
}
}
}
}
24 changes: 23 additions & 1 deletion src/NModbus.Tools.Base/NModbus.Tools.Base.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,26 @@
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
<Reference Include="Xceed.Wpf.AvalonDock, Version=3.5.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Extended.Wpf.Toolkit.3.5.0\lib\net40\Xceed.Wpf.AvalonDock.dll</HintPath>
</Reference>
<Reference Include="Xceed.Wpf.AvalonDock.Themes.Aero, Version=3.5.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Extended.Wpf.Toolkit.3.5.0\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll</HintPath>
</Reference>
<Reference Include="Xceed.Wpf.AvalonDock.Themes.Metro, Version=3.5.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Extended.Wpf.Toolkit.3.5.0\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll</HintPath>
</Reference>
<Reference Include="Xceed.Wpf.AvalonDock.Themes.VS2010, Version=3.5.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Extended.Wpf.Toolkit.3.5.0\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll</HintPath>
</Reference>
<Reference Include="Xceed.Wpf.Toolkit, Version=3.5.0.0, Culture=neutral, PublicKeyToken=3e4669d2f30244f4, processorArchitecture=MSIL">
<HintPath>..\packages\Extended.Wpf.Toolkit.3.5.0\lib\net40\Xceed.Wpf.Toolkit.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Behaviors\CloseableBehavior.cs" />
<Compile Include="Behaviors\ICloseableViewModel.cs" />
<Compile Include="ConnectionSelectionService.cs" />
<Compile Include="CrcExtensions.cs" />
<Compile Include="FunctionCodeNameFactory.cs" />
<Compile Include="FunctionCode.cs" />
Expand Down Expand Up @@ -99,12 +117,16 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Page Include="View\ConnectionSelectionDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Resource Include="Images\AddLink_16x.png" />
<Resource Include="Images\Link_16xMD.png" />
<Resource Include="Images\RemoveLink_16x.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Loading

0 comments on commit 0b07336

Please sign in to comment.