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 MultiTerm.Protocols.Model;
using System.Text;
namespace MultiTerm.Core.ViewModel;
public partial class ByteDataViewModel : ObservableObject, IDataViewModel, IComparable<ByteDataViewModel>
public partial class ByteDataViewModel : ObservableObject, IDataViewModel, IComparable<ByteDataViewModel>, ICloneable
{
/// <summary>
/// Object of data model.
/// </summary>
private readonly ExtendedByte data;
internal readonly ExtendedByte Data;
#region IDataViewModel Implementation
@ -30,11 +29,6 @@ public partial class ByteDataViewModel : ObservableObject, IDataViewModel, IComp
#endregion
/// <summary>
/// Allows access to the low level data byte.
/// </summary>
public byte Byte => this.data.Byte;
/// <summary>
/// Instanciates new <see cref="ByteDataViewModel"/>.
/// 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>
public ByteDataViewModel(ExtendedByte extendedByte, int lineIdentifier)
{
this.data = extendedByte;
this.Data = extendedByte;
this.lineIdentifier = lineIdentifier;
this.DisplayStringChar = extendedByte.ToCharacterString();
this.DisplayStringHex = extendedByte.ToHexString();
@ -71,4 +65,11 @@ public partial class ByteDataViewModel : ObservableObject, IDataViewModel, IComp
}
#endregion
#region ICloneable Implementation
public object Clone()
{
return this.MemberwiseClone();
}
#endregion
}

@ -2,6 +2,7 @@
using Common.Helpers;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MultiTerm.Core.Helpers;
using MultiTerm.Core.Types;
using MultiTerm.Protocols.Model;
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
/// <summary>
/// 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);
stringBuilder.Append(item.DisplayStringChar);
switch (ShouldIntroduceNewlineAfterThisByte(item.Byte, previousBytes, newlineSeparatorType))
switch (ShouldIntroduceNewlineAfterThisByte(item.Data.Byte, previousBytes, newlineSeparatorType))
{
case ShouldIntroduceNewlineAfterThisByteResult.NoNewline:
// 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
previousBytes ??= new List<byte>();
// add current byte to list
previousBytes.Add(item.Byte);
previousBytes.Add(item.Data.Byte);
break;
default:

@ -9,6 +9,7 @@ using System.Linq;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;
namespace MultiTerm.Wpf.CustomControl;
@ -57,6 +58,9 @@ public class MultiFormatDataView : Control
public static readonly RoutedEvent ClearRequestedEvent;
public static readonly DependencyProperty CopyCommandProperty =
DependencyProperty.Register("CopyCommand",
typeof(RoutedCommand), typeof(MultiFormatDataView));
/// <summary>
/// .NET Property for <see cref="DataSourceProperty"/>.
@ -114,8 +118,29 @@ public class MultiFormatDataView : Control
add { this.AddHandler(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
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()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiFormatDataView), new FrameworkPropertyMetadata(typeof(MultiFormatDataView)));
@ -229,6 +254,24 @@ public class MultiFormatDataView : Control
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
private void ItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

@ -22,6 +22,13 @@
<!-- Value Converters -->
<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 -->
<DataTemplate x:Key="dataContainerTemplate" DataType="vm:IDataViewModel">
<StackPanel Orientation="Vertical" Margin="0" x:Name="ItemStackPanel">
@ -170,7 +177,8 @@
TextWrapping="Wrap"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.CanContentScroll="true"
ScrollViewer.PanningMode="VerticalOnly">
ScrollViewer.PanningMode="VerticalOnly"
ContextMenu="{StaticResource CopyDifferentFormatsContextMenu}">
<!-- Show only when other checkboxes than "Characters" is checked -->
<TextBox.Style>
@ -189,7 +197,6 @@
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<!-- MultiFormat Items Control -->
@ -203,7 +210,8 @@
VirtualizingPanel.CacheLengthUnit="Item"
VirtualizingPanel.VirtualizationMode="Standard"
ItemTemplate="{StaticResource dataContainerTemplate}"
SelectionMode="Extended">
SelectionMode="Extended"
ContextMenu="{StaticResource CopyDifferentFormatsContextMenu}">
<!-- Hide when only "Characters" checkbox is checked -->
<ListView.Style>

Loading…
Cancel
Save