implemented copying data from MultiFormatDataView

master
Jonas Arnold 3 years ago
parent 4c628942e9
commit ba857805a7
  1. 78
      MultiTerm.Core/Helpers/ByteDataViewModelHelpers.cs
  2. 19
      MultiTerm.Core/ViewModel/ByteDataViewModel.cs
  3. 25
      MultiTerm.Core/ViewModel/MultiFormatDataViewModel.cs
  4. 43
      MultiTerm.Wpf.CustomControl/MultiFormatDataView/MultiFormatDataView.cs
  5. 14
      MultiTerm.Wpf.CustomControl/MultiFormatDataView/MultiFormatDataView.xaml

@ -0,0 +1,78 @@
using MultiTerm.Core.ViewModel;
using System.Text;
namespace MultiTerm.Core.Helpers;
public static class ByteDataViewModelHelpers
{
public static string GetCharacterStringOfBytesDataViewModels(IEnumerable<ByteDataViewModel> collection)
{
StringBuilder stringBuilder = new StringBuilder();
int prevLineIdentifier = collection.First().LineIdentifier;
foreach (var item in collection)
{
// add newline if line identifier increased
if(item.LineIdentifier > prevLineIdentifier)
{
stringBuilder.Append(Environment.NewLine);
}
prevLineIdentifier = item.LineIdentifier;
// add item as character
stringBuilder.Append(item.DisplayStringChar);
}
return stringBuilder.ToString();
}
public static string GetHexadecimalStringOfBytesDataViewModels(IEnumerable<ByteDataViewModel> collection)
{
StringBuilder stringBuilder = new StringBuilder();
int prevLineIdentifier = collection.First().LineIdentifier;
foreach (var item in collection)
{
// add newline if line identifier increased
if (item.LineIdentifier > prevLineIdentifier)
{
stringBuilder.Append(Environment.NewLine);
}
prevLineIdentifier = item.LineIdentifier;
// add item as hex byte
stringBuilder.Append(item.DisplayStringHex);
// add spacing if it is not the last item
if (item != collection.Last())
{
stringBuilder.Append(' ');
}
}
return stringBuilder.ToString();
}
public static string GetBinaryStringOfEBytesDataViewModels(IEnumerable<ByteDataViewModel> collection)
{
StringBuilder stringBuilder = new StringBuilder();
int prevLineIdentifier = collection.First().LineIdentifier;
foreach (var item in collection)
{
// add newline if line identifier increased
if (item.LineIdentifier > prevLineIdentifier)
{
stringBuilder.Append(Environment.NewLine);
}
prevLineIdentifier = item.LineIdentifier;
// add item as binary byte
stringBuilder.Append(item.DisplayStringBin);
// add spacing if it is not the last item
if (item != collection.Last())
{
stringBuilder.Append(' ');
}
}
return stringBuilder.ToString();
}
}

@ -1,15 +1,14 @@
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using MultiTerm.Protocols.Model; using MultiTerm.Protocols.Model;
using System.Text;
namespace MultiTerm.Core.ViewModel; namespace MultiTerm.Core.ViewModel;
public partial class ByteDataViewModel : ObservableObject, IDataViewModel, IComparable<ByteDataViewModel> public partial class ByteDataViewModel : ObservableObject, IDataViewModel, IComparable<ByteDataViewModel>, ICloneable
{ {
/// <summary> /// <summary>
/// Object of data model. /// Object of data model.
/// </summary> /// </summary>
private readonly ExtendedByte data; internal readonly ExtendedByte Data;
#region IDataViewModel Implementation #region IDataViewModel Implementation
@ -30,11 +29,6 @@ public partial class ByteDataViewModel : ObservableObject, IDataViewModel, IComp
#endregion #endregion
/// <summary>
/// Allows access to the low level data byte.
/// </summary>
public byte Byte => this.data.Byte;
/// <summary> /// <summary>
/// Instanciates new <see cref="ByteDataViewModel"/>. /// Instanciates new <see cref="ByteDataViewModel"/>.
/// Initializes internal variables with data according to <paramref name="extendedByte"/>. /// Initializes internal variables with data according to <paramref name="extendedByte"/>.
@ -43,7 +37,7 @@ public partial class ByteDataViewModel : ObservableObject, IDataViewModel, IComp
/// <param name="lineIdentifier">identifies line in which this byte is located</param> /// <param name="lineIdentifier">identifies line in which this byte is located</param>
public ByteDataViewModel(ExtendedByte extendedByte, int lineIdentifier) public ByteDataViewModel(ExtendedByte extendedByte, int lineIdentifier)
{ {
this.data = extendedByte; this.Data = extendedByte;
this.lineIdentifier = lineIdentifier; this.lineIdentifier = lineIdentifier;
this.DisplayStringChar = extendedByte.ToCharacterString(); this.DisplayStringChar = extendedByte.ToCharacterString();
this.DisplayStringHex = extendedByte.ToHexString(); this.DisplayStringHex = extendedByte.ToHexString();
@ -71,4 +65,11 @@ public partial class ByteDataViewModel : ObservableObject, IDataViewModel, IComp
} }
#endregion #endregion
#region ICloneable Implementation
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
} }

@ -2,6 +2,7 @@
using Common.Helpers; using Common.Helpers;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using MultiTerm.Core.Helpers;
using MultiTerm.Core.Types; using MultiTerm.Core.Types;
using MultiTerm.Protocols.Model; using MultiTerm.Protocols.Model;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
@ -149,6 +150,26 @@ public partial class MultiFormatDataViewModel : ObservableObject
} }
} }
public string GetSelectedDataAsString(FormatType format)
{
// nothing selected => return empty string
if(this.Selected == null || this.Selected.Count == 0) { return string.Empty; }
// shallow copy of the selected items
var selectedCopy = this.Selected.Select(item => (ByteDataViewModel)item.Clone()).ToList();
string dataAsString = string.Empty;
dataAsString = format switch
{
FormatType.Character => ByteDataViewModelHelpers.GetCharacterStringOfBytesDataViewModels(selectedCopy),
FormatType.Hexadecimal => ByteDataViewModelHelpers.GetHexadecimalStringOfBytesDataViewModels(selectedCopy),
FormatType.Binary => ByteDataViewModelHelpers.GetBinaryStringOfEBytesDataViewModels(selectedCopy),
_ => throw new ArgumentException($"'{GetSelectedDataAsString}()' does not have handling implemented for {nameof(FormatType)} {format}")
};
return dataAsString;
}
#region Collection Manipulation #region Collection Manipulation
/// <summary> /// <summary>
/// Function that reorders a given collection with item type <see cref="ByteDataViewModel"/> using the given <paramref name="newlineSeparatorType"/>. /// Function that reorders a given collection with item type <see cref="ByteDataViewModel"/> using the given <paramref name="newlineSeparatorType"/>.
@ -173,7 +194,7 @@ public partial class MultiFormatDataViewModel : ObservableObject
newCollection.Add(item); newCollection.Add(item);
stringBuilder.Append(item.DisplayStringChar); stringBuilder.Append(item.DisplayStringChar);
switch (ShouldIntroduceNewlineAfterThisByte(item.Byte, previousBytes, newlineSeparatorType)) switch (ShouldIntroduceNewlineAfterThisByte(item.Data.Byte, previousBytes, newlineSeparatorType))
{ {
case ShouldIntroduceNewlineAfterThisByteResult.NoNewline: case ShouldIntroduceNewlineAfterThisByteResult.NoNewline:
// a decision could be made, previousBytes can be cleared // a decision could be made, previousBytes can be cleared
@ -194,7 +215,7 @@ public partial class MultiFormatDataViewModel : ObservableObject
// first time that more bytes are required => create new list // first time that more bytes are required => create new list
previousBytes ??= new List<byte>(); previousBytes ??= new List<byte>();
// add current byte to list // add current byte to list
previousBytes.Add(item.Byte); previousBytes.Add(item.Data.Byte);
break; break;
default: default:

@ -9,6 +9,7 @@ using System.Linq;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Diagnostics; using System.Diagnostics;
using System.Windows.Input;
namespace MultiTerm.Wpf.CustomControl; namespace MultiTerm.Wpf.CustomControl;
@ -57,6 +58,9 @@ public class MultiFormatDataView : Control
public static readonly RoutedEvent ClearRequestedEvent; public static readonly RoutedEvent ClearRequestedEvent;
public static readonly DependencyProperty CopyCommandProperty =
DependencyProperty.Register("CopyCommand",
typeof(RoutedCommand), typeof(MultiFormatDataView));
/// <summary> /// <summary>
/// .NET Property for <see cref="DataSourceProperty"/>. /// .NET Property for <see cref="DataSourceProperty"/>.
@ -114,8 +118,29 @@ public class MultiFormatDataView : Control
add { this.AddHandler(ClearRequestedEvent, value); } add { this.AddHandler(ClearRequestedEvent, value); }
remove { this.RemoveHandler(ClearRequestedEvent, value); } remove { this.RemoveHandler(ClearRequestedEvent, value); }
} }
private static RoutedCommand? copyCommand;
/// <summary>
/// .NET Property for <see cref="CopyCommandProperty"/>
/// </summary>
public static RoutedCommand? CopyCommand
{
get { return copyCommand; }
}
#endregion #endregion
public MultiFormatDataView()
{
// register copy command
copyCommand = new RoutedCommand("CopyCommand", typeof(MultiFormatDataView));
var binding = new CommandBinding
{
Command = copyCommand
};
binding.Executed += CopyCommand_Executed; ;
CommandBindings.Add(binding);
}
static MultiFormatDataView() static MultiFormatDataView()
{ {
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiFormatDataView), new FrameworkPropertyMetadata(typeof(MultiFormatDataView))); DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiFormatDataView), new FrameworkPropertyMetadata(typeof(MultiFormatDataView)));
@ -229,6 +254,24 @@ public class MultiFormatDataView : Control
RaiseEvent(args); RaiseEvent(args);
} }
private void CopyCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
switch (e.Parameter.ToString())
{
case "Character":
Clipboard.SetText(this.DataSource.GetSelectedDataAsString(Core.Types.FormatType.Character));
break;
case "Hexadecimal":
Clipboard.SetText(this.DataSource.GetSelectedDataAsString(Core.Types.FormatType.Hexadecimal));
break;
case "Binary":
Clipboard.SetText(this.DataSource.GetSelectedDataAsString(Core.Types.FormatType.Binary));
break;
default:
throw new ArgumentException($"'{CopyCommand_Executed}()' does not have handling implemented for CommandParameter={e.Parameter}");
}
}
#region Selected Items handling #region Selected Items handling
private void ItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e) private void ItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {

@ -22,6 +22,13 @@
<!-- Value Converters --> <!-- Value Converters -->
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/> <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<!-- Context Menu Style -->
<ContextMenu x:Key="CopyDifferentFormatsContextMenu" Background="White" >
<MenuItem Header="Copy as Characters" Command="{x:Static local:MultiFormatDataView.CopyCommand}" CommandParameter="Character"/>
<MenuItem Header="Copy as Hexadecimal" Command="{x:Static local:MultiFormatDataView.CopyCommand}" CommandParameter="Hexadecimal"/>
<MenuItem Header="Copy as Binary" Command="{x:Static local:MultiFormatDataView.CopyCommand}" CommandParameter="Binary"/>
</ContextMenu>
<!-- Data Template for Data Container --> <!-- Data Template for Data Container -->
<DataTemplate x:Key="dataContainerTemplate" DataType="vm:IDataViewModel"> <DataTemplate x:Key="dataContainerTemplate" DataType="vm:IDataViewModel">
<StackPanel Orientation="Vertical" Margin="0" x:Name="ItemStackPanel"> <StackPanel Orientation="Vertical" Margin="0" x:Name="ItemStackPanel">
@ -170,7 +177,8 @@
TextWrapping="Wrap" TextWrapping="Wrap"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="true" ScrollViewer.CanContentScroll="true"
ScrollViewer.PanningMode="VerticalOnly"> ScrollViewer.PanningMode="VerticalOnly"
ContextMenu="{StaticResource CopyDifferentFormatsContextMenu}">
<!-- Show only when other checkboxes than "Characters" is checked --> <!-- Show only when other checkboxes than "Characters" is checked -->
<TextBox.Style> <TextBox.Style>
@ -189,7 +197,6 @@
</Style.Triggers> </Style.Triggers>
</Style> </Style>
</TextBox.Style> </TextBox.Style>
</TextBox> </TextBox>
<!-- MultiFormat Items Control --> <!-- MultiFormat Items Control -->
@ -203,7 +210,8 @@
VirtualizingPanel.CacheLengthUnit="Item" VirtualizingPanel.CacheLengthUnit="Item"
VirtualizingPanel.VirtualizationMode="Standard" VirtualizingPanel.VirtualizationMode="Standard"
ItemTemplate="{StaticResource dataContainerTemplate}" ItemTemplate="{StaticResource dataContainerTemplate}"
SelectionMode="Extended"> SelectionMode="Extended"
ContextMenu="{StaticResource CopyDifferentFormatsContextMenu}">
<!-- Hide when only "Characters" checkbox is checked --> <!-- Hide when only "Characters" checkbox is checked -->
<ListView.Style> <ListView.Style>

Loading…
Cancel
Save