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);
}
}
}