From e9380a5b794cd4699fbc5d80d1b31709b1e4eef6 Mon Sep 17 00:00:00 2001 From: Benjamin Popp Date: Tue, 11 Sep 2018 22:20:37 -0500 Subject: [PATCH] creating HexContent and its ViewModel, ViewPort. I expect that HexContent will represent an area of the screen filled with hex data. There will probably be a wrapper panel that adds the scrollbar to the right and addresses to the left. ViewPort can act as the ViewModel for that entire panel. Added a failing test so I remember to go back and make the ViewModel notify when it's Width/Height gets changed. --- Gen3Hex/Gen3Hex.csproj | 11 ++-- Gen3Hex/MainWindow.xaml | 11 ---- Gen3Hex/{ => View}/App.xaml | 4 +- Gen3Hex/{ => View}/App.xaml.cs | 2 +- Gen3Hex/View/HexContent.cs | 82 +++++++++++++++++++++++++++ Gen3Hex/View/MainWindow.xaml | 14 +++++ Gen3Hex/{ => View}/MainWindow.xaml.cs | 2 +- Gen3Hex/ViewModel/HexElement.cs | 5 ++ Gen3Hex/ViewModel/ViewPort.cs | 13 +++++ HexTests/Tests.cs | 13 ++++- 10 files changed, 136 insertions(+), 21 deletions(-) delete mode 100644 Gen3Hex/MainWindow.xaml rename Gen3Hex/{ => View}/App.xaml (69%) rename Gen3Hex/{ => View}/App.xaml.cs (74%) create mode 100644 Gen3Hex/View/HexContent.cs create mode 100644 Gen3Hex/View/MainWindow.xaml rename Gen3Hex/{ => View}/MainWindow.xaml.cs (71%) create mode 100644 Gen3Hex/ViewModel/HexElement.cs create mode 100644 Gen3Hex/ViewModel/ViewPort.cs diff --git a/Gen3Hex/Gen3Hex.csproj b/Gen3Hex/Gen3Hex.csproj index 51bdf20b..de893915 100644 --- a/Gen3Hex/Gen3Hex.csproj +++ b/Gen3Hex/Gen3Hex.csproj @@ -47,19 +47,22 @@ - + MSBuild:Compile Designer - + + + MSBuild:Compile Designer - + App.xaml Code - + + MainWindow.xaml Code diff --git a/Gen3Hex/MainWindow.xaml b/Gen3Hex/MainWindow.xaml deleted file mode 100644 index de42a37a..00000000 --- a/Gen3Hex/MainWindow.xaml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/Gen3Hex/App.xaml b/Gen3Hex/View/App.xaml similarity index 69% rename from Gen3Hex/App.xaml rename to Gen3Hex/View/App.xaml index 855818b8..693ebd05 100644 --- a/Gen3Hex/App.xaml +++ b/Gen3Hex/View/App.xaml @@ -1,7 +1,7 @@ - + StartupUri="View/MainWindow.xaml"> diff --git a/Gen3Hex/App.xaml.cs b/Gen3Hex/View/App.xaml.cs similarity index 74% rename from Gen3Hex/App.xaml.cs rename to Gen3Hex/View/App.xaml.cs index 8d46605c..a9885591 100644 --- a/Gen3Hex/App.xaml.cs +++ b/Gen3Hex/View/App.xaml.cs @@ -2,7 +2,7 @@ [assembly: AssemblyTitle("Gen3Hex")] -namespace HavenSoft.Gen3Hex { +namespace HavenSoft.Gen3Hex.View { public partial class App { } } diff --git a/Gen3Hex/View/HexContent.cs b/Gen3Hex/View/HexContent.cs new file mode 100644 index 00000000..e3dc4ef0 --- /dev/null +++ b/Gen3Hex/View/HexContent.cs @@ -0,0 +1,82 @@ +using HavenSoft.Gen3Hex.ViewModel; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Windows; +using System.Windows.Media; + +namespace HavenSoft.Gen3Hex.View { + public class HexContent : FrameworkElement { + public const int + CellWidth = 30, + CellHeight = 20; + + public const string Hex = "0123456789ABCDEF"; + + private readonly List byteVisualCache = new List(); + + private ViewPort ViewModel => (ViewPort)DataContext; + + public HexContent() { + DataContextChanged += OnDataContextChanged; + } + + protected override void OnRender(DrawingContext drawingContext) { + base.OnRender(drawingContext); + + var viewPort = ViewModel; + + VerifyByteVisualCache(); + + for (int x = 0; x < viewPort.Width; x++) { + for (int y = 0; y < viewPort.Height; y++) { + var element = viewPort[x, y]; + drawingContext.DrawText(byteVisualCache[element.Value], new Point(x * CellWidth, y * CellHeight)); + } + } + } + + protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) { + base.OnRenderSizeChanged(sizeInfo); + + ViewModel.Width = (int)sizeInfo.NewSize.Width / CellWidth; + ViewModel.Height = (int)sizeInfo.NewSize.Height / CellHeight; + } + + private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { + if (e.OldValue is INotifyPropertyChanged oldContext) { + oldContext.PropertyChanged -= OnDataContextPropertyChanged; + } + + if(e.NewValue is INotifyPropertyChanged newContext) { + newContext.PropertyChanged += OnDataContextPropertyChanged; + } + + this.InvalidateVisual(); + } + + private void OnDataContextPropertyChanged(object sender, PropertyChangedEventArgs e) { + if (e.PropertyName == nameof(ViewModel.Width) || e.PropertyName == nameof(ViewModel.Height)) { + this.InvalidateVisual(); + } + } + + private void VerifyByteVisualCache() { + if (byteVisualCache.Count != 0) return; + + var bytesAsHex = Enumerable.Range(0, 255).Select(i => $"{Hex[i / 0x10]}{Hex[i % 0x10]}"); + + var text = bytesAsHex.Select(hex => new FormattedText( + hex, + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + new Typeface("Consolas"), + 16, + Brushes.Black, + 1.0)); + + byteVisualCache.AddRange(text); + } + } +} diff --git a/Gen3Hex/View/MainWindow.xaml b/Gen3Hex/View/MainWindow.xaml new file mode 100644 index 00000000..954a124d --- /dev/null +++ b/Gen3Hex/View/MainWindow.xaml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/Gen3Hex/MainWindow.xaml.cs b/Gen3Hex/View/MainWindow.xaml.cs similarity index 71% rename from Gen3Hex/MainWindow.xaml.cs rename to Gen3Hex/View/MainWindow.xaml.cs index 6bbf0c61..d0121874 100644 --- a/Gen3Hex/MainWindow.xaml.cs +++ b/Gen3Hex/View/MainWindow.xaml.cs @@ -1,4 +1,4 @@ -namespace HavenSoft.Gen3Hex { +namespace HavenSoft.Gen3Hex.View { public partial class MainWindow { public MainWindow() => InitializeComponent(); } diff --git a/Gen3Hex/ViewModel/HexElement.cs b/Gen3Hex/ViewModel/HexElement.cs new file mode 100644 index 00000000..4f55cb42 --- /dev/null +++ b/Gen3Hex/ViewModel/HexElement.cs @@ -0,0 +1,5 @@ +namespace HavenSoft.Gen3Hex.ViewModel { + public class HexElement { + public byte Value { get; set; } + } +} \ No newline at end of file diff --git a/Gen3Hex/ViewModel/ViewPort.cs b/Gen3Hex/ViewModel/ViewPort.cs new file mode 100644 index 00000000..6db0d440 --- /dev/null +++ b/Gen3Hex/ViewModel/ViewPort.cs @@ -0,0 +1,13 @@ +using System.ComponentModel; + +namespace HavenSoft.Gen3Hex.ViewModel { + public class ViewPort : INotifyPropertyChanged { + public int Width { get; set; } + + public int Height { get; set; } + + public HexElement this[int x, int y] => new HexElement(); + + public event PropertyChangedEventHandler PropertyChanged; + } +} diff --git a/HexTests/Tests.cs b/HexTests/Tests.cs index ee2246b3..0ea0723d 100644 --- a/HexTests/Tests.cs +++ b/HexTests/Tests.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using HavenSoft.Gen3Hex.ViewModel; +using System.Reflection; using Xunit; [assembly: AssemblyTitle("HexTests")] @@ -6,7 +7,15 @@ using Xunit; namespace HexTests { public class Tests { [Fact] - public void TestMethod1() { + public void ViewPortNotifiesOnSizeChange() { + var viewPort = new ViewPort(); + var counter = 0; + viewPort.PropertyChanged += (sender, e) => counter++; + + viewPort.Width = 12; + viewPort.Height = 50; + + Assert.Equal(2, counter); } } }