introduced clear button in MultiFormatDataView and cleaned up custom controls

master
Jonas Arnold 3 years ago
parent 676465a5c1
commit 907dac42f8
  1. 4
      MultiTerm.Core/ViewModel/CommunicationDataViewModel.cs
  2. 29
      MultiTerm.Wpf.CustomControl/ExtendedTabControl/ExtendedTabControl.cs
  3. 107
      MultiTerm.Wpf.CustomControl/MultiFormatDataView/MultiFormatDataView.cs
  4. 1
      MultiTerm.Wpf.CustomControl/MultiFormatDataView/MultiFormatDataView.xaml
  5. 38
      MultiTerm.Wpf.CustomControl/MultiFormatTextBox/MultiFormatTextBox.cs
  6. 1
      MultiTerm.Wpf/MultiTerm.Wpf.csproj
  7. 16
      MultiTerm.Wpf/View/SendReceiveView.xaml

@ -93,13 +93,13 @@ public partial class CommunicationDataViewModel : ObservableObject
} }
[RelayCommand] [RelayCommand]
private void ClearReceivedCharacters() private void ClearReceivedData()
{ {
this.ReceivedData = new ObservableCollection<DataViewModel>(); this.ReceivedData = new ObservableCollection<DataViewModel>();
} }
[RelayCommand] [RelayCommand]
private void ClearSentCharacters() private void ClearSentData()
{ {
this.SentData = new ObservableCollection<DataViewModel>(); this.SentData = new ObservableCollection<DataViewModel>();
} }

@ -3,35 +3,6 @@ using System.Windows.Controls;
namespace MultiTerm.Wpf.CustomControl; namespace MultiTerm.Wpf.CustomControl;
/// <summary>
/// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
///
/// Step 1a) Using this custom control in a XAML file that exists in the current project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:MultiTerm.Wpf.Controls"
///
///
/// Step 1b) Using this custom control in a XAML file that exists in a different project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:MultiTerm.Wpf.Controls;assembly=MultiTerm.Wpf.Controls"
///
/// You will also need to add a project reference from the project where the XAML file lives
/// to this project and Rebuild to avoid compilation errors:
///
/// Right click on the target project in the Solution Explorer and
/// "Add Reference"->"Projects"->[Browse to and select this project]
///
///
/// Step 2)
/// Go ahead and use your control in the XAML file.
///
/// <MyNamespace:ExtendedTabControl/>
///
/// </summary>
public class ExtendedTabControl : TabControl public class ExtendedTabControl : TabControl
{ {
public static readonly RoutedEvent AddButtonClickedEvent; public static readonly RoutedEvent AddButtonClickedEvent;

@ -2,50 +2,18 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
namespace MultiTerm.Wpf.CustomControl; namespace MultiTerm.Wpf.CustomControl;
/// <summary>
/// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
///
/// Step 1a) Using this custom control in a XAML file that exists in the current project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:MultiTerm.Wpf.CustomControl.MultiFormatDataView"
///
///
/// Step 1b) Using this custom control in a XAML file that exists in a different project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:MultiTerm.Wpf.CustomControl.MultiFormatDataView;assembly=MultiTerm.Wpf.CustomControl.MultiFormatDataView"
///
/// You will also need to add a project reference from the project where the XAML file lives
/// to this project and Rebuild to avoid compilation errors:
///
/// Right click on the target project in the Solution Explorer and
/// "Add Reference"->"Projects"->[Browse to and select this project]
///
///
/// Step 2)
/// Go ahead and use your control in the XAML file.
///
/// <MyNamespace:MultiFormatDataView/>
///
/// </summary>
public class MultiFormatDataView : Control public class MultiFormatDataView : Control
{ {
private static readonly Dictionary<StackPanel, MultiFormatDataView> itemParentPairs = new(); private static readonly Dictionary<StackPanel, MultiFormatDataView> itemParentPairs = new();
private const string itemsControlTemplateName = "itemsControl"; private const string itemsControlTemplateName = "itemsControl";
private const string buttonClearTemplateName = "btnClear";
private ListBox? itemsControl; private ListBox? itemsControl;
private List<DataViewModel> currentSelectedItems = new(); private List<DataViewModel> currentSelectedItems = new();
@ -80,6 +48,8 @@ public class MultiFormatDataView : Control
typeof(MultiFormatDataView), typeof(MultiFormatDataView),
new UIPropertyMetadata(false, OnItemUnloaded)); new UIPropertyMetadata(false, OnItemUnloaded));
public static readonly RoutedEvent ClearRequestedEvent;
/// <summary> /// <summary>
/// .NET Property for DataSource. /// .NET Property for DataSource.
/// </summary> /// </summary>
@ -127,11 +97,24 @@ public class MultiFormatDataView : Control
get { return (bool)GetValue(ItemUnloadedProperty); } get { return (bool)GetValue(ItemUnloadedProperty); }
set { SetValue(ItemUnloadedProperty, value); } set { SetValue(ItemUnloadedProperty, value); }
} }
/// <summary>
/// .NET Property for <see cref="ClearRequestedEvent"/>
/// </summary>
public event RoutedEventHandler ClearRequested
{
add { this.AddHandler(ClearRequestedEvent, value); }
remove { this.RemoveHandler(ClearRequestedEvent, value); }
}
#endregion #endregion
static MultiFormatDataView() static MultiFormatDataView()
{ {
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiFormatDataView), new FrameworkPropertyMetadata(typeof(MultiFormatDataView))); DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiFormatDataView), new FrameworkPropertyMetadata(typeof(MultiFormatDataView)));
ClearRequestedEvent = EventManager.RegisterRoutedEvent("ClearRequested",
RoutingStrategy.Bubble, typeof(RoutedEventArgs),
typeof(MultiFormatDataView));
} }
public override void OnApplyTemplate() public override void OnApplyTemplate()
@ -149,8 +132,41 @@ public class MultiFormatDataView : Control
{ {
throw new Exception($"Implementation fault, {itemsControlTemplateName} not found in template."); throw new Exception($"Implementation fault, {itemsControlTemplateName} not found in template.");
} }
// get button from template, ignore if it does not exist
if (GetTemplateChild(buttonClearTemplateName) is Button button)
{
button.Click += OnClearButtonClicked; ;
}
}
private static void OnDataSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// extract instance and guard null
if (d is not MultiFormatDataView mfdv) { return; }
// extract instance of new Value and guard null
if (e.NewValue is not IEnumerable enumerable) { return; }
// check if enumerable items are all of correct type
foreach (var item in enumerable)
{
if (item is not DataViewModel)
{ throw new ArgumentException($"{nameof(DataSourceProperty)} must be of type {nameof(DataViewModel)}"); }
} }
// add group property
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(e.NewValue);
PropertyGroupDescription groupDescription = new(nameof(DataViewModel.LineIdentifier));
view.GroupDescriptions.Add(groupDescription);
}
private void OnClearButtonClicked(object sender, RoutedEventArgs e)
{
// raise clear requested event
RoutedEventArgs args = new(ClearRequestedEvent);
RaiseEvent(args);
}
#region Selected Items handling
private void ItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e) private void ItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if(this.currentSelectedItems == null) if(this.currentSelectedItems == null)
@ -174,29 +190,9 @@ public class MultiFormatDataView : Control
{ {
// NOP // NOP
} }
#endregion
#region Realized Item Count
private static void OnDataSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// extract instance and guard null
if (d is not MultiFormatDataView mfdv) { return; }
// extract instance of new Value and guard null
if (e.NewValue is not IEnumerable enumerable) { return; }
// check if enumerable items are all of correct type
foreach (var item in enumerable)
{
if (item is not DataViewModel)
{ throw new ArgumentException($"{nameof(DataSourceProperty)} must be of type {nameof(DataViewModel)}"); }
}
// add group property
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(e.NewValue);
PropertyGroupDescription groupDescription = new(nameof(DataViewModel.LineIdentifier));
view.GroupDescriptions.Add(groupDescription);
}
private static void OnRealizedItemsCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) private static void OnRealizedItemsCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ {
// NOP // NOP
@ -238,4 +234,5 @@ public class MultiFormatDataView : Control
parentMFDV.RealizedItemsCount--; parentMFDV.RealizedItemsCount--;
} }
} }
#endregion
} }

@ -119,6 +119,7 @@
<CheckBox DockPanel.Dock="Left" Content="Character" VerticalAlignment="Center" x:Name="cbCharacter" Padding="20 0" IsChecked="True"/> <CheckBox DockPanel.Dock="Left" Content="Character" VerticalAlignment="Center" x:Name="cbCharacter" Padding="20 0" IsChecked="True"/>
<CheckBox DockPanel.Dock="Left" Content="Hexadecimal" VerticalAlignment="Center" x:Name="cbHex" Padding="20 0"/> <CheckBox DockPanel.Dock="Left" Content="Hexadecimal" VerticalAlignment="Center" x:Name="cbHex" Padding="20 0"/>
<CheckBox DockPanel.Dock="Left" Content="Binary" VerticalAlignment="Center" x:Name="cbBin" Padding="20 0"/> <CheckBox DockPanel.Dock="Left" Content="Binary" VerticalAlignment="Center" x:Name="cbBin" Padding="20 0"/>
<Button x:Name="btnClear" Content="Clear" Margin="5" />
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" VerticalAlignment="Center"> <StackPanel DockPanel.Dock="Right" Orientation="Horizontal" VerticalAlignment="Center">
<Label Content="Realized Items: " Margin="0 0 5 0"/> <Label Content="Realized Items: " Margin="0 0 5 0"/>
<Label Width="30" Content="{TemplateBinding RealizedItemsCount}"/> <Label Width="30" Content="{TemplateBinding RealizedItemsCount}"/>

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Documents; using System.Windows.Documents;
@ -14,37 +13,6 @@ using System.Windows.Media;
namespace MultiTerm.Wpf.CustomControl; namespace MultiTerm.Wpf.CustomControl;
/// <summary>
/// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
///
/// Step 1a) Using this custom control in a XAML file that exists in the current project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:MultiTerm.Wpf.CustomControl"
///
///
/// Step 1b) Using this custom control in a XAML file that exists in a different project.
/// Add this XmlNamespace attribute to the root element of the markup file where it is
/// to be used:
///
/// xmlns:MyNamespace="clr-namespace:MultiTerm.Wpf.CustomControl.MultiFormatTextBox;assembly=MultiTerm.Wpf.CustomControl.MultiFormatTextBox"
///
/// You will also need to add a project reference from the project where the XAML file lives
/// to this project and Rebuild to avoid compilation errors:
///
/// Right click on the target project in the Solution Explorer and
/// "Add Reference"->"Projects"->[Browse to and select this project]
///
///
/// Step 2)
/// Go ahead and use your control in the XAML file.
///
/// <MyNamespace:MultiFormatTextBox/>
///
/// </summary>
public class MultiFormatTextBox : Control public class MultiFormatTextBox : Control
{ {
#region static content #region static content
@ -52,13 +20,13 @@ public class MultiFormatTextBox : Control
private static readonly List<Format> formats = new() private static readonly List<Format> formats = new()
{ {
// character input, accepts all keys // character input, accepts all keys
new Format("CHAR", "MultiFormatTextBox.CHAR.Background", Core.Types.FormatType.Character, new Format("CHAR", "MultiFormatTextBox.CHAR.Background", FormatType.Character,
delegate(Key k) { return true; }), delegate(Key k) { return true; }),
// hex input, ignores all keys that are not inbetween 0 and F // hex input, ignores all keys that are not inbetween 0 and F
new Format("HEX", "MultiFormatTextBox.HEX.Background", Core.Types.FormatType.Hexadecimal, new Format("HEX", "MultiFormatTextBox.HEX.Background", FormatType.Hexadecimal,
delegate(Key k) { return (k >= Key.D0 && k <= Key.F); }), delegate(Key k) { return (k >= Key.D0 && k <= Key.F); }),
// binary input, ignores all keys except 0 and 1 // binary input, ignores all keys except 0 and 1
new Format("BIN", "MultiFormatTextBox.BIN.Background", Core.Types.FormatType.Binary, new Format("BIN", "MultiFormatTextBox.BIN.Background", FormatType.Binary,
delegate(Key k) { return (k == Key.D0 || k == Key.D1); }) delegate(Key k) { return (k == Key.D0 || k == Key.D1); })
}; };

@ -11,6 +11,7 @@
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -7,6 +7,7 @@
xmlns:protocol_serial="clr-namespace:MultiTerm.Protocols.Serial;assembly=MultiTerm.Protocols" xmlns:protocol_serial="clr-namespace:MultiTerm.Protocols.Serial;assembly=MultiTerm.Protocols"
xmlns:settings_view="clr-namespace:MultiTerm.Wpf.View.SettingsView" xmlns:settings_view="clr-namespace:MultiTerm.Wpf.View.SettingsView"
xmlns:custom_controls="clr-namespace:MultiTerm.Wpf.CustomControl;assembly=MultiTerm.Wpf.CustomControl" xmlns:custom_controls="clr-namespace:MultiTerm.Wpf.CustomControl;assembly=MultiTerm.Wpf.CustomControl"
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <Grid>
@ -31,11 +32,16 @@
</ContentControl> </ContentControl>
</GroupBox> </GroupBox>
<GroupBox Header="Receive" Grid.Row="1" Padding="5"> <GroupBox Header="Receive" Grid.Row="1" Padding="5">
<custom_controls:MultiFormatDataView DataSource="{Binding Path=CommunicationData.ReceivedData, <custom_controls:MultiFormatDataView x:Name="mfdvReceive"
Mode=OneWay}" DataSource="{Binding Path=CommunicationData.ReceivedData, Mode=OneWay}"
SelectedItems="{Binding Path=CommunicationData.SelectedReceivedData, SelectedItems="{Binding Path=CommunicationData.SelectedReceivedData, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}">
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged}"/> <behaviors:Interaction.Triggers>
<behaviors:EventTrigger EventName="ClearRequested" SourceObject="{Binding ElementName=mfdvReceive}">
<behaviors:InvokeCommandAction Command="{Binding CommunicationData.ClearReceivedDataCommand}" />
</behaviors:EventTrigger>
</behaviors:Interaction.Triggers>
</custom_controls:MultiFormatDataView>
</GroupBox> </GroupBox>
<GroupBox Header="Send" Grid.Row="2" Padding="5"> <GroupBox Header="Send" Grid.Row="2" Padding="5">

Loading…
Cancel
Save