Dreamine.PLC.Wpf 1.0.1
Dreamine.PLC.Wpf 산업 자동화 및 I/O 기능을 제공합니다.
로딩중...
검색중...
일치하는것 없음
PlcMonitorViewModel.cs
이 파일의 문서화 페이지로 가기
1using System.Collections.ObjectModel;
2using System.ComponentModel;
3using System.Globalization;
4using System.Runtime.CompilerServices;
5using System.Windows.Input;
6using Dreamine.PLC.Abstractions.Clients;
7using Dreamine.PLC.Abstractions.Connections;
8using Dreamine.PLC.Core.Clients;
9using Dreamine.PLC.Core.Devices;
10using Dreamine.MVVM.ViewModels;
13
15
24public sealed class PlcMonitorViewModel : INotifyPropertyChanged, IAsyncDisposable
25{
34 private readonly DefaultPlcAddressParser _addressParser = new();
43 private IPlcClient _client;
52 private string _channelName = "InMemory PLC";
61 private string _addressText = "D100";
70 private string _countText = "4";
79 private string _bitValuesText = "1,0,1,0";
88 private string _wordValuesText = "100,200,300,400";
97 private string _statusMessage = "Ready.";
106 private PlcConnectionState _state = PlcConnectionState.Disconnected;
107
117 : this(new InMemoryPlcClient(), "InMemory PLC")
118 {
119 }
120
153 public PlcMonitorViewModel(IPlcClient client, string channelName = "PLC")
154 {
155 _client = client ?? throw new ArgumentNullException(nameof(client));
156 _client.StateChanged += OnClientStateChanged;
157 _state = _client.State;
158 _channelName = channelName;
159
160 ConnectCommand = new AsyncRelayCommand(ConnectAsync);
161 DisconnectCommand = new AsyncRelayCommand(DisconnectAsync);
162 ReadBitsCommand = new AsyncRelayCommand(ReadBitsAsync);
163 ReadWordsCommand = new AsyncRelayCommand(ReadWordsAsync);
164 WriteBitsCommand = new AsyncRelayCommand(WriteBitsAsync);
165 WriteWordsCommand = new AsyncRelayCommand(WriteWordsAsync);
166 ClearLogCommand = new RelayCommand(ClearLog);
167 }
168
177 public event PropertyChangedEventHandler? PropertyChanged;
178
187 public ObservableCollection<PlcOperationLogItem> Logs { get; } = [];
188
197 public ICommand ConnectCommand { get; }
198
207 public ICommand DisconnectCommand { get; }
208
217 public ICommand ReadBitsCommand { get; }
218
227 public ICommand ReadWordsCommand { get; }
228
237 public ICommand WriteBitsCommand { get; }
238
247 public ICommand WriteWordsCommand { get; }
248
257 public ICommand ClearLogCommand { get; }
258
267 public string ChannelName
268 {
269 get => _channelName;
270 set => SetField(ref _channelName, value);
271 }
272
281 public string AddressText
282 {
283 get => _addressText;
284 set => SetField(ref _addressText, value);
285 }
286
295 public string CountText
296 {
297 get => _countText;
298 set => SetField(ref _countText, value);
299 }
300
309 public string BitValuesText
310 {
311 get => _bitValuesText;
312 set => SetField(ref _bitValuesText, value);
313 }
314
323 public string WordValuesText
324 {
325 get => _wordValuesText;
326 set => SetField(ref _wordValuesText, value);
327 }
328
337 public PlcConnectionState State
338 {
339 get => _state;
340 private set => SetField(ref _state, value);
341 }
342
351 public string StatusMessage
352 {
353 get => _statusMessage;
354 set => SetField(ref _statusMessage, value);
355 }
356
397 public void SetClient(IPlcClient client, string channelName)
398 {
399 ArgumentNullException.ThrowIfNull(client);
400
401 _client.StateChanged -= OnClientStateChanged;
402 _client = client;
403 _client.StateChanged += OnClientStateChanged;
404 ChannelName = channelName;
405 State = _client.State;
406 AddLog("Client", string.Empty, string.Empty, true, $"Client changed: {channelName}");
407 }
408
457 public void AppendLog(string operation, string address, string values, bool isSuccess, string message)
458 {
459 AddLog(operation, address, values, isSuccess, message);
460 }
461
478 public async ValueTask DisposeAsync()
479 {
480 _client.StateChanged -= OnClientStateChanged;
481 await _client.DisposeAsync().ConfigureAwait(false);
482 }
483
500 private async Task ConnectAsync()
501 {
502 var result = await _client.ConnectAsync().ConfigureAwait(true);
503 StatusMessage = result.IsSuccess ? "Connected." : result.Message ?? "Connect failed.";
504 AddLog("Connect", string.Empty, string.Empty, result.IsSuccess, StatusMessage);
505 }
506
523 private async Task DisconnectAsync()
524 {
525 var result = await _client.DisconnectAsync().ConfigureAwait(true);
526 StatusMessage = result.IsSuccess ? "Disconnected." : result.Message ?? "Disconnect failed.";
527 AddLog("Disconnect", string.Empty, string.Empty, result.IsSuccess, StatusMessage);
528 }
529
546 private async Task ReadBitsAsync()
547 {
548 if (!TryCreateReadRequest(out var address, out var count))
549 {
550 return;
551 }
552
553 var result = await _client.ReadBitsAsync(address, count).ConfigureAwait(true);
554 var values = result.Value is null ? string.Empty : string.Join(',', result.Value.Select(x => x ? "1" : "0"));
555 StatusMessage = result.IsSuccess ? $"Read bits: {values}" : result.Message ?? "Read bits failed.";
556 AddLog("ReadBits", address.ToString(), values, result.IsSuccess, StatusMessage);
557 }
558
575 private async Task ReadWordsAsync()
576 {
577 if (!TryCreateReadRequest(out var address, out var count))
578 {
579 return;
580 }
581
582 var result = await _client.ReadWordsAsync(address, count).ConfigureAwait(true);
583 var values = result.Value is null ? string.Empty : string.Join(',', result.Value.Select(x => x.ToString(CultureInfo.InvariantCulture)));
584 StatusMessage = result.IsSuccess ? $"Read words: {values}" : result.Message ?? "Read words failed.";
585 AddLog("ReadWords", address.ToString(), values, result.IsSuccess, StatusMessage);
586 }
587
604 private async Task WriteBitsAsync()
605 {
606 if (!TryParseAddress(out var address))
607 {
608 return;
609 }
610
611 if (!TryParseBits(BitValuesText, out var values))
612 {
613 return;
614 }
615
616 var result = await _client.WriteBitsAsync(address, values).ConfigureAwait(true);
617 var valuesText = string.Join(',', values.Select(x => x ? "1" : "0"));
618 StatusMessage = result.IsSuccess ? $"Write bits: {valuesText}" : result.Message ?? "Write bits failed.";
619 AddLog("WriteBits", address.ToString(), valuesText, result.IsSuccess, StatusMessage);
620 }
621
638 private async Task WriteWordsAsync()
639 {
640 if (!TryParseAddress(out var address))
641 {
642 return;
643 }
644
645 if (!TryParseWords(WordValuesText, out var values))
646 {
647 return;
648 }
649
650 var result = await _client.WriteWordsAsync(address, values).ConfigureAwait(true);
651 var valuesText = string.Join(',', values.Select(x => x.ToString(CultureInfo.InvariantCulture)));
652 StatusMessage = result.IsSuccess ? $"Write words: {valuesText}" : result.Message ?? "Write words failed.";
653 AddLog("WriteWords", address.ToString(), valuesText, result.IsSuccess, StatusMessage);
654 }
655
664 private void ClearLog()
665 {
666 Logs.Clear();
667 StatusMessage = "Log cleared.";
668 }
669
702 private bool TryCreateReadRequest(out Abstractions.Devices.PlcAddress address, out int count)
703 {
704 address = default;
705 count = 0;
706
707 if (!TryParseAddress(out address))
708 {
709 return false;
710 }
711
712 if (!int.TryParse(CountText, NumberStyles.Integer, CultureInfo.InvariantCulture, out count) || count <= 0)
713 {
714 StatusMessage = "Count must be greater than zero.";
715 AddLog("Validate", AddressText, CountText, false, StatusMessage);
716 return false;
717 }
718
719 return true;
720 }
721
746 private bool TryParseAddress(out Abstractions.Devices.PlcAddress address)
747 {
748 var result = _addressParser.Parse(AddressText);
749 if (!result.IsSuccess)
750 {
751 address = default;
752 StatusMessage = result.Message ?? "Invalid PLC address.";
753 AddLog("Validate", AddressText, string.Empty, false, StatusMessage);
754 return false;
755 }
756
757 address = result.Value;
758 return true;
759 }
760
793 private bool TryParseBits(string text, out bool[] values)
794 {
795 values = [];
796 try
797 {
798 values = text.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
799 .Select(ParseBit)
800 .ToArray();
801 return values.Length > 0;
802 }
803 catch (Exception ex)
804 {
805 StatusMessage = ex.Message;
806 AddLog("Validate", AddressText, text, false, StatusMessage);
807 return false;
808 }
809 }
810
843 private bool TryParseWords(string text, out short[] values)
844 {
845 values = [];
846 try
847 {
848 values = text.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
849 .Select(x => short.Parse(x, CultureInfo.InvariantCulture))
850 .ToArray();
851 return values.Length > 0;
852 }
853 catch (Exception ex)
854 {
855 StatusMessage = ex.Message;
856 AddLog("Validate", AddressText, text, false, StatusMessage);
857 return false;
858 }
859 }
860
893 private static bool ParseBit(string text)
894 {
895 return text switch
896 {
897 "1" => true,
898 "0" => false,
899 _ when bool.TryParse(text, out var value) => value,
900 _ => throw new FormatException($"Invalid bit value: {text}")
901 };
902 }
903
952 private void AddLog(string operation, string address, string values, bool isSuccess, string message)
953 {
954 Logs.Insert(0, new PlcOperationLogItem
955 {
956 Time = DateTime.Now,
957 Operation = operation,
958 Address = address,
959 Values = values,
960 IsSuccess = isSuccess,
961 Message = message
962 });
963
964 while (Logs.Count > 500)
965 {
966 Logs.RemoveAt(Logs.Count - 1);
967 }
968 }
969
994 private void OnClientStateChanged(object? sender, PlcConnectionState e)
995 {
996 State = e;
997 }
998
1047 private bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
1048 {
1049 if (EqualityComparer<T>.Default.Equals(field, value))
1050 {
1051 return false;
1052 }
1053
1054 field = value;
1055 OnPropertyChanged(propertyName);
1056 return true;
1057 }
1058
1075 private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
1076 {
1077 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
1078 }
1079}
void OnPropertyChanged([CallerMemberName] string? propertyName=null)
void AppendLog(string operation, string address, string values, bool isSuccess, string message)
ObservableCollection< PlcOperationLogItem > Logs
bool TryCreateReadRequest(out Abstractions.Devices.PlcAddress address, out int count)
bool SetField< T >(ref T field, T value, [CallerMemberName] string? propertyName=null)
bool TryParseAddress(out Abstractions.Devices.PlcAddress address)
bool TryParseBits(string text, out bool[] values)
void OnClientStateChanged(object? sender, PlcConnectionState e)
void SetClient(IPlcClient client, string channelName)
void AddLog(string operation, string address, string values, bool isSuccess, string message)
readonly DefaultPlcAddressParser _addressParser
PlcMonitorViewModel(IPlcClient client, string channelName="PLC")
bool TryParseWords(string text, out short[] values)