diff --git a/.editorconfig b/.editorconfig
index f333e94..1dd14cd 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,6 +1,6 @@
[*]
charset=utf-8
-end_of_line=lf
+end_of_line=crlf
trim_trailing_whitespace=true
insert_final_newline=true
indent_style=space
diff --git a/BenchmarkDotNet.Artifacts/results/Benchmarks.BufferWriting-report.html b/BenchmarkDotNet.Artifacts/results/Benchmarks.BufferWriting-report.html
index 0ebb652..08da10c 100644
--- a/BenchmarkDotNet.Artifacts/results/Benchmarks.BufferWriting-report.html
+++ b/BenchmarkDotNet.Artifacts/results/Benchmarks.BufferWriting-report.html
@@ -3,12 +3,12 @@
Benchmarks.BufferWriting-20201110-192311
-
-
diff --git a/BenchmarkDotNet.Artifacts/results/Benchmarks.ImmutableDictionaryLookup-report.html b/BenchmarkDotNet.Artifacts/results/Benchmarks.ImmutableDictionaryLookup-report.html
index 521c4b5..c1f1315 100644
--- a/BenchmarkDotNet.Artifacts/results/Benchmarks.ImmutableDictionaryLookup-report.html
+++ b/BenchmarkDotNet.Artifacts/results/Benchmarks.ImmutableDictionaryLookup-report.html
@@ -3,12 +3,12 @@
Benchmarks.ImmutableDictionaryLookup-20200714-200711
-
-
diff --git a/BenchmarkDotNet.Artifacts/results/Benchmarks.LockOverhead-report.html b/BenchmarkDotNet.Artifacts/results/Benchmarks.LockOverhead-report.html
index 5993f66..99f74fa 100644
--- a/BenchmarkDotNet.Artifacts/results/Benchmarks.LockOverhead-report.html
+++ b/BenchmarkDotNet.Artifacts/results/Benchmarks.LockOverhead-report.html
@@ -3,12 +3,12 @@
Benchmarks.LockOverhead-20200825-220153
-
-
diff --git a/BenchmarkDotNet.Artifacts/results/Benchmarks.MaxValueToDepth-report.html b/BenchmarkDotNet.Artifacts/results/Benchmarks.MaxValueToDepth-report.html
index a0b205c..107ea10 100644
--- a/BenchmarkDotNet.Artifacts/results/Benchmarks.MaxValueToDepth-report.html
+++ b/BenchmarkDotNet.Artifacts/results/Benchmarks.MaxValueToDepth-report.html
@@ -3,12 +3,12 @@
Benchmarks.MaxValueToDepth-20200823-173129
-
-
diff --git a/BenchmarkDotNet.Artifacts/results/Benchmarks.MemoryCopy-report.html b/BenchmarkDotNet.Artifacts/results/Benchmarks.MemoryCopy-report.html
index 8496b82..a32e8a2 100644
--- a/BenchmarkDotNet.Artifacts/results/Benchmarks.MemoryCopy-report.html
+++ b/BenchmarkDotNet.Artifacts/results/Benchmarks.MemoryCopy-report.html
@@ -3,12 +3,12 @@
Benchmarks.MemoryCopy-20200823-155139
-
-
diff --git a/BenchmarkDotNet.Artifacts/results/Benchmarks.PlainVsCursorStruct-report.html b/BenchmarkDotNet.Artifacts/results/Benchmarks.PlainVsCursorStruct-report.html
index e2ff147..d012c14 100644
--- a/BenchmarkDotNet.Artifacts/results/Benchmarks.PlainVsCursorStruct-report.html
+++ b/BenchmarkDotNet.Artifacts/results/Benchmarks.PlainVsCursorStruct-report.html
@@ -3,12 +3,12 @@
Benchmarks.PlainVsCursorStruct-20200726-153143
-
-
diff --git a/BenchmarkDotNet.Artifacts/results/Benchmarks.PropertiesVsFields-report.html b/BenchmarkDotNet.Artifacts/results/Benchmarks.PropertiesVsFields-report.html
index eb579d9..c669b29 100644
--- a/BenchmarkDotNet.Artifacts/results/Benchmarks.PropertiesVsFields-report.html
+++ b/BenchmarkDotNet.Artifacts/results/Benchmarks.PropertiesVsFields-report.html
@@ -3,12 +3,12 @@
Benchmarks.PropertiesVsFields-20200825-210502
-
-
diff --git a/MarcusW.VncClient.sln.DotSettings b/MarcusW.VncClient.sln.DotSettings
index 567ad34..5009dcd 100644
--- a/MarcusW.VncClient.sln.DotSettings
+++ b/MarcusW.VncClient.sln.DotSettings
@@ -1,2 +1,7 @@
- True
\ No newline at end of file
+ True
+
+
+
+
+
\ No newline at end of file
diff --git a/benchmarks/Benchmarks/Benchmarks.csproj b/benchmarks/Benchmarks/Benchmarks.csproj
index e03b1a3..196412a 100644
--- a/benchmarks/Benchmarks/Benchmarks.csproj
+++ b/benchmarks/Benchmarks/Benchmarks.csproj
@@ -1,13 +1,11 @@
-
-
- netcoreapp3.1
- Exe
- true
-
-
-
-
-
-
-
+
+ net8.0
+ Exe
+ true
+ enable
+
+
+
+
+
\ No newline at end of file
diff --git a/benchmarks/Benchmarks/BufferWriting.cs b/benchmarks/Benchmarks/BufferWriting.cs
index 123ac62..78cf8d2 100644
--- a/benchmarks/Benchmarks/BufferWriting.cs
+++ b/benchmarks/Benchmarks/BufferWriting.cs
@@ -2,95 +2,94 @@
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
-namespace Benchmarks
+namespace Benchmarks;
+
+public class BufferWriting
{
- public class BufferWriting
+ private readonly byte[] _buffer = new byte[1920 * 1080 * 4];
+
+ [Benchmark]
+ public void ArrayIndexer()
{
- private readonly byte[] _buffer = new byte[1920 * 1080 * 4];
+ for (var i = 0; i < _buffer.Length; i += 4)
+ SetPixelArrayIndexer(_buffer, i, 0xffffffff);
+ }
- [Benchmark]
- public void ArrayIndexer()
+ [Benchmark]
+ public unsafe void Pointer()
+ {
+ fixed (byte* ptr = &_buffer[0])
{
- for (int i = 0; i < _buffer.Length; i += 4)
- SetPixelArrayIndexer(_buffer, i, 0xffffffff);
+ for (var i = 0; i < _buffer.Length; i += 4)
+ SetPixelPointer(ptr + i, 0xffffffff);
}
+ }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void SetPixelArrayIndexer(byte[] buffer, int i, uint color)
+ [Benchmark]
+ public unsafe void PointerMemcpy()
+ {
+ fixed (byte* ptr = &_buffer[0])
{
- buffer[i] = (byte)(color & 0xff);
- buffer[i + 1] = (byte)((color >> 8) & 0xff);
- buffer[i + 2] = (byte)((color >> 16) & 0xff);
- buffer[i + 3] = (byte)((color >> 24) & 0xff);
+ for (var i = 0; i < _buffer.Length; i += 4)
+ SetPixelPointerMemcpy(ptr + i, 0xffffffff);
}
+ }
- [Benchmark]
- public void Span()
+ [Benchmark]
+ public unsafe void PointerReinterpretCast()
+ {
+ fixed (byte* ptr = &_buffer[0])
{
- Span buffer = _buffer;
-
- for (int i = 0; i < _buffer.Length; i += 4)
- SetPixelSpan(buffer.Slice(i, 4), 0xffffffff);
+ for (var i = 0; i < _buffer.Length; i += 4)
+ SetPixelPointerReinterpretCast(ptr + i, 0xffffffff);
}
+ }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void SetPixelSpan(in Span span, uint color)
- {
- span[0] = (byte)(color & 0xff);
- span[1] = (byte)((color >> 8) & 0xff);
- span[2] = (byte)((color >> 16) & 0xff);
- span[3] = (byte)((color >> 24) & 0xff);
- }
+ [Benchmark]
+ public void Span()
+ {
+ Span buffer = _buffer;
- [Benchmark]
- public unsafe void Pointer()
- {
- fixed (byte* ptr = &_buffer[0])
- {
- for (int i = 0; i < _buffer.Length; i += 4)
- SetPixelPointer(ptr + i, 0xffffffff);
- }
- }
+ for (var i = 0; i < _buffer.Length; i += 4)
+ SetPixelSpan(buffer.Slice(i, 4), 0xffffffff);
+ }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private unsafe void SetPixelPointer(byte* ptr, uint color)
- {
- *ptr++ = (byte)(color & 0xff);
- *ptr++ = (byte)((color >> 8) & 0xff);
- *ptr++ = (byte)((color >> 16) & 0xff);
- *ptr = (byte)((color >> 24) & 0xff);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void SetPixelArrayIndexer(byte[] buffer, int i, uint color)
+ {
+ buffer[i] = (byte)(color & 0xff);
+ buffer[i + 1] = (byte)((color >> 8) & 0xff);
+ buffer[i + 2] = (byte)((color >> 16) & 0xff);
+ buffer[i + 3] = (byte)((color >> 24) & 0xff);
+ }
- [Benchmark]
- public unsafe void PointerReinterpretCast()
- {
- fixed (byte* ptr = &_buffer[0])
- {
- for (int i = 0; i < _buffer.Length; i += 4)
- SetPixelPointerReinterpretCast(ptr + i, 0xffffffff);
- }
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe void SetPixelPointer(byte* ptr, uint color)
+ {
+ *ptr++ = (byte)(color & 0xff);
+ *ptr++ = (byte)((color >> 8) & 0xff);
+ *ptr++ = (byte)((color >> 16) & 0xff);
+ *ptr = (byte)((color >> 24) & 0xff);
+ }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private unsafe void SetPixelPointerReinterpretCast(byte* ptr, uint color)
- {
- *(uint*)ptr = color;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe void SetPixelPointerMemcpy(byte* ptr, uint color)
+ {
+ Unsafe.CopyBlock(ptr, &color, sizeof(uint));
+ }
- [Benchmark]
- public unsafe void PointerMemcpy()
- {
- fixed (byte* ptr = &_buffer[0])
- {
- for (int i = 0; i < _buffer.Length; i += 4)
- SetPixelPointerMemcpy(ptr + i, 0xffffffff);
- }
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe void SetPixelPointerReinterpretCast(byte* ptr, uint color)
+ {
+ *(uint*)ptr = color;
+ }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private unsafe void SetPixelPointerMemcpy(byte* ptr, uint color)
- {
- Unsafe.CopyBlock(ptr, &color, sizeof(uint));
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void SetPixelSpan(in Span span, uint color)
+ {
+ span[0] = (byte)(color & 0xff);
+ span[1] = (byte)((color >> 8) & 0xff);
+ span[2] = (byte)((color >> 16) & 0xff);
+ span[3] = (byte)((color >> 24) & 0xff);
}
}
diff --git a/benchmarks/Benchmarks/ImmutableDictionaryLookup.cs b/benchmarks/Benchmarks/ImmutableDictionaryLookup.cs
index e36674b..97739d0 100644
--- a/benchmarks/Benchmarks/ImmutableDictionaryLookup.cs
+++ b/benchmarks/Benchmarks/ImmutableDictionaryLookup.cs
@@ -1,42 +1,33 @@
-using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using BenchmarkDotNet.Attributes;
-namespace Benchmarks
+namespace Benchmarks;
+
+public class ImmutableDictionaryLookup
{
- public class ImmutableDictionaryLookup
- {
- private const int Index = 500;
- private readonly IImmutableDictionary _dictionary= Enumerable.Range(0, 1000).ToImmutableDictionary(i => i, i => new object());
+ private const int Index = 500;
- [Benchmark]
- public object Indexer()
- {
- if (!_dictionary.ContainsKey(Index))
- return null;
- return _dictionary[Index];
- }
+ private readonly IImmutableDictionary _dictionary =
+ Enumerable.Range(0, 1000).ToImmutableDictionary(i => i, _ => new object());
- [Benchmark]
- public object TryGet()
+ [Benchmark]
+ public object? Indexer() => CollectionExtensions.GetValueOrDefault(_dictionary, Index);
+
+ [Benchmark]
+ public object? TryCatch()
+ {
+ try
{
- if (!_dictionary.TryGetValue(Index, out object value))
- return null;
- return value;
+ return _dictionary[Index];
}
-
- [Benchmark]
- public object TryCatch()
+ catch
{
- try
- {
- return _dictionary[Index];
- }
- catch
- {
- return null;
- }
+ return null;
}
}
+
+ [Benchmark]
+ public object? TryGet() => CollectionExtensions.GetValueOrDefault(_dictionary, Index);
}
diff --git a/benchmarks/Benchmarks/LockOverhead.cs b/benchmarks/Benchmarks/LockOverhead.cs
index ac21609..5dacfd1 100644
--- a/benchmarks/Benchmarks/LockOverhead.cs
+++ b/benchmarks/Benchmarks/LockOverhead.cs
@@ -1,23 +1,22 @@
using BenchmarkDotNet.Attributes;
-namespace Benchmarks
+namespace Benchmarks;
+
+public class LockOverhead
{
- public class LockOverhead
- {
- private int _value;
- private object _lock = new object();
+ private readonly object _lock = new();
+ private int _value;
- [Benchmark]
- public void IncreaseWithoutLock()
- {
+ [Benchmark]
+ public void IncreaseWithLock()
+ {
+ lock (_lock)
_value++;
- }
+ }
- [Benchmark]
- public void IncreaseWithLock()
- {
- lock (_lock)
- _value++;
- }
+ [Benchmark]
+ public void IncreaseWithoutLock()
+ {
+ _value++;
}
}
diff --git a/benchmarks/Benchmarks/MaxValueToDepth.cs b/benchmarks/Benchmarks/MaxValueToDepth.cs
index 3dc54fa..e3941fa 100644
--- a/benchmarks/Benchmarks/MaxValueToDepth.cs
+++ b/benchmarks/Benchmarks/MaxValueToDepth.cs
@@ -1,27 +1,26 @@
using System.Runtime.Intrinsics.X86;
using BenchmarkDotNet.Attributes;
-namespace Benchmarks
+namespace Benchmarks;
+
+public class MaxValueToDepth
{
- public class MaxValueToDepth
- {
- private const int MaxValue = 255;
+ private const int MaxValue = 255;
- [Benchmark]
- public uint WhileLoop()
- {
- uint val = MaxValue;
- uint depth = 0;
- while (val != 0)
- {
- depth++;
- val >>= 1;
- }
+ [Benchmark]
+ public uint PopCount() => Popcnt.PopCount(MaxValue);
- return depth;
+ [Benchmark]
+ public uint WhileLoop()
+ {
+ uint val = MaxValue;
+ uint depth = 0;
+ while (val != 0)
+ {
+ depth++;
+ val >>= 1;
}
- [Benchmark]
- public uint PopCount() => Popcnt.PopCount(MaxValue);
+ return depth;
}
}
diff --git a/benchmarks/Benchmarks/MemoryCopy.cs b/benchmarks/Benchmarks/MemoryCopy.cs
index c5acb58..893bbc2 100644
--- a/benchmarks/Benchmarks/MemoryCopy.cs
+++ b/benchmarks/Benchmarks/MemoryCopy.cs
@@ -1,48 +1,46 @@
using System;
-using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
-namespace Benchmarks
+namespace Benchmarks;
+
+public unsafe class MemoryCopy
{
- public unsafe class MemoryCopy
- {
- private readonly byte* _srcPtr;
- private readonly byte* _dstPtr;
+ private readonly byte* _dstPtr;
+ private readonly byte* _srcPtr;
- public MemoryCopy()
- {
- _srcPtr = (byte*)Marshal.AllocHGlobal(4);
- _dstPtr = (byte*)Marshal.AllocHGlobal(4);
- }
+ public MemoryCopy()
+ {
+ _srcPtr = (byte*)Marshal.AllocHGlobal(4);
+ _dstPtr = (byte*)Marshal.AllocHGlobal(4);
+ }
- ~MemoryCopy()
- {
- Marshal.FreeHGlobal((IntPtr)_srcPtr);
- Marshal.FreeHGlobal((IntPtr)_dstPtr);
- }
+ [Benchmark]
+ public void AssigningValues()
+ {
+ *_dstPtr = *_srcPtr;
+ *(_dstPtr + 1) = *(_srcPtr + 1);
+ *(_dstPtr + 2) = *(_srcPtr + 2);
+ *(_dstPtr + 3) = *(_srcPtr + 3);
+ }
- [Benchmark]
- public void MemCpy()
- {
- Unsafe.CopyBlock(_dstPtr, _srcPtr, 4);
- }
+ [Benchmark]
+ public void MemCpy()
+ {
+ Unsafe.CopyBlock(_dstPtr, _srcPtr, 4);
+ }
- [Benchmark]
- public void AssigningValues()
- {
- *_dstPtr = *_srcPtr;
- *(_dstPtr + 1) = *(_srcPtr + 1);
- *(_dstPtr + 2) = *(_srcPtr + 2);
- *(_dstPtr + 3) = *(_srcPtr + 3);
- }
+ [Benchmark]
+ public void ReinterpretCast()
+ {
+ var val = Unsafe.AsRef(_srcPtr);
+ Unsafe.Write(_dstPtr, val);
+ }
- [Benchmark]
- public void ReinterpretCast()
- {
- uint val = Unsafe.AsRef(_srcPtr);
- Unsafe.Write(_dstPtr, val);
- }
+ ~MemoryCopy()
+ {
+ Marshal.FreeHGlobal((IntPtr)_srcPtr);
+ Marshal.FreeHGlobal((IntPtr)_dstPtr);
}
}
diff --git a/benchmarks/Benchmarks/PlainVsCursorStruct.cs b/benchmarks/Benchmarks/PlainVsCursorStruct.cs
index 37a7017..2c6d67d 100644
--- a/benchmarks/Benchmarks/PlainVsCursorStruct.cs
+++ b/benchmarks/Benchmarks/PlainVsCursorStruct.cs
@@ -1,109 +1,98 @@
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
-namespace Benchmarks
+namespace Benchmarks;
+
+public class PlainVsCursorStruct
{
- public class PlainVsCursorStruct
- {
- private const int Pixels = 1920 * 1080;
- private readonly byte[] _buffer = new byte[Pixels * 4];
+ private const int Pixels = 1920 * 1080;
+ private readonly byte[] _buffer = new byte[Pixels * 4];
- [Benchmark]
- public unsafe void Plain()
+ [Benchmark]
+ public unsafe void Plain()
+ {
+ fixed (byte* ptr = &_buffer[0])
{
- fixed (byte* ptr = &_buffer[0])
- {
- for (int i = 0; i < _buffer.Length; i += 4)
- SetColor(i, ptr + i);
- }
+ for (var i = 0; i < _buffer.Length; i += 4)
+ SetColor(i, ptr + i);
}
+ }
- [Benchmark]
- public unsafe void WithCursor()
+ [Benchmark]
+ public unsafe void WithCursor()
+ {
+ fixed (byte* ptr = &_buffer[0])
{
- fixed (byte* ptr = &_buffer[0])
- {
- var cursor = new BufferCursor(ptr);
- for (int i = 0; i < Pixels; i++)
- cursor.SetNextPixel(i);
- }
+ var cursor = new BufferCursor(ptr);
+ for (var i = 0; i < Pixels; i++)
+ cursor.SetNextPixel(i);
}
+ }
- [Benchmark]
- public unsafe void WithCursorNotInlined()
+ [Benchmark]
+ public unsafe void WithCursorNotInlined()
+ {
+ fixed (byte* ptr = &_buffer[0])
{
- fixed (byte* ptr = &_buffer[0])
- {
- var cursor = new BufferCursorNotInlined(ptr);
- for (int i = 0; i < Pixels; i++)
- cursor.SetNextPixel(i);
- }
+ var cursor = new BufferCursorNotInlined(ptr);
+ for (var i = 0; i < Pixels; i++)
+ cursor.SetNextPixel(i);
}
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe void SetColor(int i, byte* position)
+ {
+ // Some random operations
+ *position++ = (byte)(i & 0xff);
+ *position++ = (byte)((i >> 8) & 0xff);
+ *position++ = (byte)((i >> 16) & 0xff);
+ *position = (byte)((i >> 24) & 0xff);
+ }
+
+ private readonly unsafe struct BufferCursor(byte* ptr)
+ {
+ private readonly byte* _ptr = ptr;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private unsafe void SetColor(int i, byte* position)
+ public readonly void SetNextPixel(int i)
{
+ MoveNext();
+
// Some random operations
- *position++ = (byte)(i & 0xff);
- *position++ = (byte)((i >> 8) & 0xff);
- *position++ = (byte)((i >> 16) & 0xff);
- *position = (byte)((i >> 24) & 0xff);
+ *_ptr = (byte)(i & 0xff);
+ *(_ptr + 1) = (byte)((i >> 8) & 0xff);
+ *(_ptr + 2) = (byte)((i >> 16) & 0xff);
+ *(_ptr + 3) = (byte)((i >> 24) & 0xff);
}
- private unsafe struct BufferCursor
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public readonly void MoveNext()
{
- private byte* _ptr;
-
- public BufferCursor(byte* ptr)
- {
- _ptr = ptr;
- }
+ *_ptr += 4;
+ }
+ }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void SetNextPixel(int i)
- {
- MoveNext();
+ private readonly unsafe struct BufferCursorNotInlined(byte* ptr)
+ {
+ private readonly byte* _ptr = ptr;
- // Some random operations
- *_ptr = (byte)(i & 0xff);
- *(_ptr + 1) = (byte)((i >> 8) & 0xff);
- *(_ptr + 2) = (byte)((i >> 16) & 0xff);
- *(_ptr + 3) = (byte)((i >> 24) & 0xff);
- }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public readonly void SetNextPixel(int i)
+ {
+ MoveNext();
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void MoveNext()
- {
- *_ptr += 4;
- }
+ // Some random operations
+ *_ptr = (byte)(i & 0xff);
+ *(_ptr + 1) = (byte)((i >> 8) & 0xff);
+ *(_ptr + 2) = (byte)((i >> 16) & 0xff);
+ *(_ptr + 3) = (byte)((i >> 24) & 0xff);
}
- private unsafe struct BufferCursorNotInlined
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public readonly void MoveNext()
{
- private byte* _ptr;
-
- public BufferCursorNotInlined(byte* ptr)
- {
- _ptr = ptr;
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- public void SetNextPixel(int i)
- {
- MoveNext();
-
- // Some random operations
- *_ptr = (byte)(i & 0xff);
- *(_ptr + 1) = (byte)((i >> 8) & 0xff);
- *(_ptr + 2) = (byte)((i >> 16) & 0xff);
- *(_ptr + 3) = (byte)((i >> 24) & 0xff);
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- public void MoveNext()
- {
- *_ptr += 4;
- }
+ *_ptr += 4;
}
}
}
diff --git a/benchmarks/Benchmarks/Program.cs b/benchmarks/Benchmarks/Program.cs
index 3fe08a3..dcc4598 100644
--- a/benchmarks/Benchmarks/Program.cs
+++ b/benchmarks/Benchmarks/Program.cs
@@ -1,12 +1,11 @@
using BenchmarkDotNet.Running;
-namespace Benchmarks
+namespace Benchmarks;
+
+public static class Program
{
- public static class Program
+ public static void Main(string[] args)
{
- public static void Main(string[] args)
- {
- BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
- }
+ BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
}
diff --git a/benchmarks/Benchmarks/PropertiesVsFields.cs b/benchmarks/Benchmarks/PropertiesVsFields.cs
index f34a6be..0a78090 100644
--- a/benchmarks/Benchmarks/PropertiesVsFields.cs
+++ b/benchmarks/Benchmarks/PropertiesVsFields.cs
@@ -1,43 +1,29 @@
using BenchmarkDotNet.Attributes;
-namespace Benchmarks
-{
- public class PropertiesVsFields
- {
- private StructWithProperties _structWithProperties = new StructWithProperties(100,200);
- private StructWithFields _structWithFields = new StructWithFields(100,200);
-
- public struct StructWithProperties
- {
- public int A { get; }
-
- public int B { get; }
+namespace Benchmarks;
- public StructWithProperties(int a, int b)
- {
- A = a;
- B = b;
- }
- }
+public class PropertiesVsFields
+{
+ private readonly StructWithFields _structWithFields = new(100, 200);
+ private readonly StructWithProperties _structWithProperties = new(100, 200);
- public struct StructWithFields
- {
- public int A;
+ [Benchmark]
+ public int MultipliedFields() => _structWithFields.A * _structWithFields.B;
- public int B;
+ [Benchmark]
+ public int MultipliedProperties() => _structWithProperties.A * _structWithProperties.B;
- public StructWithFields(int a, int b)
- {
- A = a;
- B = b;
- }
- }
+ public readonly struct StructWithProperties(int a, int b)
+ {
+ public int A { get; } = a;
+ public int B { get; } = b;
+ }
- [Benchmark]
- public int MultipliedProperties() => _structWithProperties.A * _structWithProperties.B;
+ public struct StructWithFields(int a, int b)
+ {
+ public readonly int A = a;
- [Benchmark]
- public int MultipliedFields() => _structWithFields.A * _structWithFields.B;
+ public readonly int B = b;
}
}
diff --git a/samples/AvaloniaVncClient/App.xaml b/samples/AvaloniaVncClient/App.xaml
index 78b40ff..a05231f 100644
--- a/samples/AvaloniaVncClient/App.xaml
+++ b/samples/AvaloniaVncClient/App.xaml
@@ -7,7 +7,6 @@
-
-
+
diff --git a/samples/AvaloniaVncClient/App.xaml.cs b/samples/AvaloniaVncClient/App.xaml.cs
index 431535c..1f31b23 100644
--- a/samples/AvaloniaVncClient/App.xaml.cs
+++ b/samples/AvaloniaVncClient/App.xaml.cs
@@ -6,29 +6,28 @@
using AvaloniaVncClient.Views;
using Splat;
-namespace AvaloniaVncClient
+namespace AvaloniaVncClient;
+
+public class App : Application
{
- public class App : Application
+ public override void Initialize()
{
- public override void Initialize()
- {
- AvaloniaXamlLoader.Load(this);
+ AvaloniaXamlLoader.Load(this);
- // Register dependencies
- Locator.CurrentMutable.RegisterLazySingleton(() => new ConnectionManager());
- Locator.CurrentMutable.RegisterLazySingleton(() => new InteractiveAuthenticationHandler());
- }
+ // Register dependencies
+ Locator.CurrentMutable.RegisterLazySingleton(() => new ConnectionManager());
+ Locator.CurrentMutable.RegisterLazySingleton(() => new InteractiveAuthenticationHandler());
+ }
- public override void OnFrameworkInitializationCompleted()
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
- if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
- {
- desktop.MainWindow = new MainWindow {
- DataContext = new MainWindowViewModel()
- };
- }
-
- base.OnFrameworkInitializationCompleted();
+ desktop.MainWindow = new MainWindow {
+ DataContext = new MainWindowViewModel(),
+ };
}
+
+ base.OnFrameworkInitializationCompleted();
}
}
diff --git a/samples/AvaloniaVncClient/AvaloniaVncClient.csproj b/samples/AvaloniaVncClient/AvaloniaVncClient.csproj
index 36a77e2..aad540e 100644
--- a/samples/AvaloniaVncClient/AvaloniaVncClient.csproj
+++ b/samples/AvaloniaVncClient/AvaloniaVncClient.csproj
@@ -1,27 +1,27 @@
-
- WinExe
- netcoreapp3.1
- enable
-
-
-
-
- %(Filename)
-
-
- Designer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ WinExe
+ net8.0-windows
+ enable
+
+
+
+
+ %(Filename)
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/AvaloniaVncClient/Program.cs b/samples/AvaloniaVncClient/Program.cs
index 1159de7..00c035d 100644
--- a/samples/AvaloniaVncClient/Program.cs
+++ b/samples/AvaloniaVncClient/Program.cs
@@ -3,26 +3,25 @@
using Avalonia.Logging;
using Avalonia.ReactiveUI;
-namespace AvaloniaVncClient
+namespace AvaloniaVncClient;
+
+public static class Program
{
- public static class Program
+ // Avalonia configuration, don't remove; also used by visual designer.
+ public static AppBuilder BuildAvaloniaApp()
{
- // Initialization code. Don't use any Avalonia, third-party APIs or any
- // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
- // yet and stuff might break.
- public static void Main(string[] args)
- => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args, ShutdownMode.OnMainWindowClose);
-
- // Avalonia configuration, don't remove; also used by visual designer.
- public static AppBuilder BuildAvaloniaApp()
- {
#if DEBUG
- LogEventLevel logLevel = LogEventLevel.Debug;
+ var logLevel = LogEventLevel.Debug;
#else
- LogEventLevel logLevel = LogEventLevel.Warning;
+ var logLevel = LogEventLevel.Warning;
#endif
- return AppBuilder.Configure().UsePlatformDetect().LogToTrace(logLevel).UseReactiveUI();
- }
+ return AppBuilder.Configure().UsePlatformDetect().LogToTrace(logLevel).UseReactiveUI();
}
+
+ // Initialization code. Don't use any Avalonia, third-party APIs or any
+ // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
+ // yet and stuff might break.
+ public static void Main(string[] args)
+ => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args, ShutdownMode.OnMainWindowClose);
}
diff --git a/samples/AvaloniaVncClient/Services/ConnectionManager.cs b/samples/AvaloniaVncClient/Services/ConnectionManager.cs
index ad5f4e3..44cb133 100644
--- a/samples/AvaloniaVncClient/Services/ConnectionManager.cs
+++ b/samples/AvaloniaVncClient/Services/ConnectionManager.cs
@@ -3,38 +3,37 @@
using System.Threading.Tasks;
using MarcusW.VncClient;
using MarcusW.VncClient.Avalonia.Adapters.Logging;
-using MarcusW.VncClient.Rendering;
using Microsoft.Extensions.Logging;
using Splat;
-namespace AvaloniaVncClient.Services
+namespace AvaloniaVncClient.Services;
+
+public class ConnectionManager
{
- public class ConnectionManager
- {
- private readonly InteractiveAuthenticationHandler _interactiveAuthenticationHandler;
+ private readonly InteractiveAuthenticationHandler _interactiveAuthenticationHandler;
- private readonly VncClient _vncClient;
+ private readonly VncClient _vncClient;
- public ConnectionManager(InteractiveAuthenticationHandler? interactiveAuthenticationHandler = null)
- {
- _interactiveAuthenticationHandler = interactiveAuthenticationHandler ?? Locator.Current.GetService()
- ?? throw new ArgumentNullException(nameof(interactiveAuthenticationHandler));
+ public ConnectionManager(InteractiveAuthenticationHandler? interactiveAuthenticationHandler = null)
+ {
+ _interactiveAuthenticationHandler = interactiveAuthenticationHandler
+ ?? Locator.Current.GetService()
+ ?? throw new ArgumentNullException(nameof(interactiveAuthenticationHandler));
- // Create and populate default logger factory for logging to Avalonia logging sinks
- var loggerFactory = new LoggerFactory();
- loggerFactory.AddProvider(new AvaloniaLoggerProvider());
+ // Create and populate default logger factory for logging to Avalonia logging sinks
+ var loggerFactory = new LoggerFactory();
+ loggerFactory.AddProvider(new AvaloniaLoggerProvider());
- _vncClient = new VncClient(loggerFactory);
- }
+ _vncClient = new(loggerFactory);
+ }
- public Task ConnectAsync(ConnectParameters parameters, CancellationToken cancellationToken = default)
- {
- parameters.AuthenticationHandler = _interactiveAuthenticationHandler;
+ public Task ConnectAsync(ConnectParameters parameters, CancellationToken cancellationToken = default)
+ {
+ parameters.AuthenticationHandler = _interactiveAuthenticationHandler;
- // Uncomment for debugging/visualization purposes
- //parameters.RenderFlags |= RenderFlags.VisualizeRectangles;
+ // Uncomment for debugging/visualization purposes
+ //parameters.RenderFlags |= RenderFlags.VisualizeRectangles;
- return _vncClient.ConnectAsync(parameters, cancellationToken);
- }
+ return _vncClient.ConnectAsync(parameters, cancellationToken);
}
}
diff --git a/samples/AvaloniaVncClient/Services/InteractiveAuthenticationHandler.cs b/samples/AvaloniaVncClient/Services/InteractiveAuthenticationHandler.cs
index eb938b8..e10dc73 100644
--- a/samples/AvaloniaVncClient/Services/InteractiveAuthenticationHandler.cs
+++ b/samples/AvaloniaVncClient/Services/InteractiveAuthenticationHandler.cs
@@ -8,28 +8,29 @@
using MarcusW.VncClient.Security;
using ReactiveUI;
-namespace AvaloniaVncClient.Services
+namespace AvaloniaVncClient.Services;
+
+public class InteractiveAuthenticationHandler : IAuthenticationHandler
{
- public class InteractiveAuthenticationHandler : IAuthenticationHandler
- {
- public Interaction EnterPasswordInteraction { get; } = new Interaction();
+ public Interaction EnterPasswordInteraction { get; } = new();
- ///
- public async Task ProvideAuthenticationInputAsync(RfbConnection connection, ISecurityType securityType, IAuthenticationInputRequest request)
- where TInput : class, IAuthenticationInput
+ ///
+ public async Task ProvideAuthenticationInputAsync(RfbConnection connection,
+ ISecurityType securityType, IAuthenticationInputRequest request)
+ where TInput : class, IAuthenticationInput
+ {
+ if (typeof(TInput) != typeof(PasswordAuthenticationInput))
{
- if (typeof(TInput) == typeof(PasswordAuthenticationInput))
- {
- string? password = await Dispatcher.UIThread.InvokeAsync(async () => await EnterPasswordInteraction.Handle(Unit.Default)).ConfigureAwait(false);
+ throw new InvalidOperationException(
+ "The authentication input request is not supported by the interactive authentication handler.");
+ }
- // TODO: Implement canceling of authentication input requests instead of passing an empty password!
- if (password == null)
- password = string.Empty;
+ string password = await Dispatcher.UIThread
+ .InvokeAsync(async () => await EnterPasswordInteraction.Handle(Unit.Default)).ConfigureAwait(false)
- return (TInput)Convert.ChangeType(new PasswordAuthenticationInput(password), typeof(TInput));
- }
+ // TODO: Implement canceling of authentication input requests instead of passing an empty password!
+ ?? string.Empty;
- throw new InvalidOperationException("The authentication input request is not supported by the interactive authentication handler.");
- }
+ return (TInput)Convert.ChangeType(new PasswordAuthenticationInput(password), typeof(TInput));
}
}
diff --git a/samples/AvaloniaVncClient/ViewLocator.cs b/samples/AvaloniaVncClient/ViewLocator.cs
index 7fa8017..3909e1e 100644
--- a/samples/AvaloniaVncClient/ViewLocator.cs
+++ b/samples/AvaloniaVncClient/ViewLocator.cs
@@ -3,25 +3,28 @@
using Avalonia.Controls.Templates;
using AvaloniaVncClient.ViewModels;
-namespace AvaloniaVncClient
+namespace AvaloniaVncClient;
+
+public class ViewLocator : IDataTemplate
{
- public class ViewLocator : IDataTemplate
- {
- public bool SupportsRecycling => false;
+ public bool SupportsRecycling => false;
- public IControl Build(object data)
+ public Control Build(object? data)
+ {
+ string? viewName = data?.GetType().FullName?.Replace("ViewModel", "View");
+ if (viewName == null)
{
- var viewName = data.GetType().FullName?.Replace("ViewModel", "View");
- if (viewName == null)
- return new TextBlock { Text = "Not Found" };
-
- var viewType = Type.GetType(viewName);
- if (viewType == null)
- return new TextBlock { Text = "Not Found: " + viewName };
+ return new TextBlock { Text = "Not Found" };
+ }
- return (Control)Activator.CreateInstance(viewType)!;
+ var viewType = Type.GetType(viewName);
+ if (viewType == null)
+ {
+ return new TextBlock { Text = "Not Found: " + viewName };
}
- public bool Match(object data) => data is ViewModelBase;
+ return (Control)Activator.CreateInstance(viewType)!;
}
+
+ public bool Match(object? data) => data is ViewModelBase;
}
diff --git a/samples/AvaloniaVncClient/ViewModels/MainWindowViewModel.cs b/samples/AvaloniaVncClient/ViewModels/MainWindowViewModel.cs
index b7bbd1e..a378241 100644
--- a/samples/AvaloniaVncClient/ViewModels/MainWindowViewModel.cs
+++ b/samples/AvaloniaVncClient/ViewModels/MainWindowViewModel.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Linq;
-using System.Net;
+using System;
using System.Reactive;
using System.Threading;
using System.Threading.Tasks;
@@ -8,96 +6,103 @@
using MarcusW.VncClient;
using MarcusW.VncClient.Protocol.Implementation;
using MarcusW.VncClient.Protocol.Implementation.Services.Transports;
-using MarcusW.VncClient.Rendering;
using ReactiveUI;
using Splat;
-namespace AvaloniaVncClient.ViewModels
+namespace AvaloniaVncClient.ViewModels;
+
+public class MainWindowViewModel : ViewModelBase
{
- public class MainWindowViewModel : ViewModelBase
- {
- private readonly ConnectionManager _connectionManager;
+ private readonly ConnectionManager _connectionManager;
- private string _host = "fedora-vm";
- private int _port = 5901;
- private RfbConnection? _rfbConnection;
- private string? _errorMessage;
+ private readonly ObservableAsPropertyHelper _parametersValidProperty;
+ private string? _errorMessage;
- private readonly ObservableAsPropertyHelper _parametersValidProperty;
+ private string _host = "fedora-vm";
+ private int _port = 5901;
+ private RfbConnection? _rfbConnection;
- public InteractiveAuthenticationHandler InteractiveAuthenticationHandler { get; }
+ public MainWindowViewModel(ConnectionManager? connectionManager = null,
+ InteractiveAuthenticationHandler? interactiveAuthenticationHandler = null)
+ {
+ _connectionManager = connectionManager ?? Locator.Current.GetService()
+ ?? throw new ArgumentNullException(nameof(connectionManager));
+ InteractiveAuthenticationHandler = interactiveAuthenticationHandler
+ ?? Locator.Current.GetService()
+ ?? throw new ArgumentNullException(nameof(interactiveAuthenticationHandler));
+
+ IObservable parametersValid = this.WhenAnyValue(vm => vm.Host, vm => vm.Port, (host, port) => {
+ // Is it an IP Address or a valid DNS/hostname?
+ if (Uri.CheckHostName(host) == UriHostNameType.Unknown)
+ {
+ return false;
+ }
- public bool IsTightAvailable => DefaultImplementation.IsTightAvailable;
+ // Is the port valid?
+ return port is >= 0 and <= 65535;
+ });
+ _parametersValidProperty = parametersValid.ToProperty(this, nameof(ParametersValid));
- public string Host
- {
- get => _host;
- set => this.RaiseAndSetIfChanged(ref _host, value);
- }
+ ConnectCommand = ReactiveCommand.CreateFromTask(ConnectAsync, parametersValid);
+ }
- public int Port
- {
- get => _port;
- set => this.RaiseAndSetIfChanged(ref _port, value);
- }
+ public InteractiveAuthenticationHandler InteractiveAuthenticationHandler { get; }
- // TODO: Add a way to close existing connections. Maybe a list of multiple connections (shown as tabs)?
- public RfbConnection? RfbConnection
- {
- get => _rfbConnection;
- private set => this.RaiseAndSetIfChanged(ref _rfbConnection, value);
- }
+#pragma warning disable CA1822
- public string? ErrorMessage
- {
- get => _errorMessage;
- set => this.RaiseAndSetIfChanged(ref _errorMessage, value);
- }
+ // ReSharper disable once MemberCanBeMadeStatic.Global
+ public bool IsTightAvailable => DefaultImplementation.IsTightAvailable;
+#pragma warning restore CA1822
- public ReactiveCommand ConnectCommand { get; }
+ public string Host
+ {
+ get => _host;
+ set => this.RaiseAndSetIfChanged(ref _host, value);
+ }
- public bool ParametersValid => _parametersValidProperty.Value;
+ public int Port
+ {
+ get => _port;
+ set => this.RaiseAndSetIfChanged(ref _port, value);
+ }
- public MainWindowViewModel(ConnectionManager? connectionManager = null, InteractiveAuthenticationHandler? interactiveAuthenticationHandler = null)
- {
- _connectionManager = connectionManager ?? Locator.Current.GetService() ?? throw new ArgumentNullException(nameof(connectionManager));
- InteractiveAuthenticationHandler = interactiveAuthenticationHandler ?? Locator.Current.GetService()
- ?? throw new ArgumentNullException(nameof(interactiveAuthenticationHandler));
+ // TODO: Add a way to close existing connections. Maybe a list of multiple connections (shown as tabs)?
+ public RfbConnection? RfbConnection
+ {
+ get => _rfbConnection;
+ private set => this.RaiseAndSetIfChanged(ref _rfbConnection, value);
+ }
- IObservable parametersValid = this.WhenAnyValue(vm => vm.Host, vm => vm.Port, (host, port) => {
- // Is it an IP Address or a valid DNS/hostname?
- if (Uri.CheckHostName(host) == UriHostNameType.Unknown)
- return false;
+ public string? ErrorMessage
+ {
+ get => _errorMessage;
+ set => this.RaiseAndSetIfChanged(ref _errorMessage, value);
+ }
- // Is the port valid?
- return port >= 0 && port <= 65535;
- });
- _parametersValidProperty = parametersValid.ToProperty(this, nameof(ParametersValid));
+ public ReactiveCommand ConnectCommand { get; }
- ConnectCommand = ReactiveCommand.CreateFromTask(ConnectAsync, parametersValid);
- }
+ public bool ParametersValid => _parametersValidProperty.Value;
- private async Task ConnectAsync(CancellationToken cancellationToken = default)
+ private async Task ConnectAsync(CancellationToken cancellationToken = default)
+ {
+ try
{
- try
- {
- // TODO: Configure connect parameters
- var parameters = new ConnectParameters {
- TransportParameters = new TcpTransportParameters {
- Host = Host,
- Port = Port
- }
- };
-
- // Try to connect and set the connection
- RfbConnection = await _connectionManager.ConnectAsync(parameters, cancellationToken).ConfigureAwait(true);
-
- ErrorMessage = null;
- }
- catch (Exception exception)
- {
- ErrorMessage = exception.Message;
- }
+ // TODO: Configure connect parameters
+ var parameters = new ConnectParameters {
+ TransportParameters = new TcpTransportParameters {
+ Host = Host,
+ Port = Port,
+ },
+ };
+
+ // Try to connect and set the connection
+ RfbConnection = await _connectionManager.ConnectAsync(parameters, cancellationToken).ConfigureAwait(true);
+
+ ErrorMessage = null;
+ }
+ catch (Exception exception)
+ {
+ ErrorMessage = exception.Message;
}
}
}
diff --git a/samples/AvaloniaVncClient/ViewModels/ViewModelBase.cs b/samples/AvaloniaVncClient/ViewModels/ViewModelBase.cs
index f801d1f..4111dbd 100644
--- a/samples/AvaloniaVncClient/ViewModels/ViewModelBase.cs
+++ b/samples/AvaloniaVncClient/ViewModels/ViewModelBase.cs
@@ -1,6 +1,5 @@
using ReactiveUI;
-namespace AvaloniaVncClient.ViewModels
-{
- public class ViewModelBase : ReactiveObject { }
-}
+namespace AvaloniaVncClient.ViewModels;
+
+public class ViewModelBase : ReactiveObject { }
diff --git a/samples/AvaloniaVncClient/Views/Dialogs/EnterPasswordDialog.xaml.cs b/samples/AvaloniaVncClient/Views/Dialogs/EnterPasswordDialog.xaml.cs
index 7974948..1491a30 100644
--- a/samples/AvaloniaVncClient/Views/Dialogs/EnterPasswordDialog.xaml.cs
+++ b/samples/AvaloniaVncClient/Views/Dialogs/EnterPasswordDialog.xaml.cs
@@ -1,32 +1,30 @@
-using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
-namespace AvaloniaVncClient.Views.Dialogs
+namespace AvaloniaVncClient.Views.Dialogs;
+
+public class EnterPasswordDialog : Window
{
- public class EnterPasswordDialog : Window
+ public EnterPasswordDialog()
{
- private TextBox PasswordTextBox => this.FindControl("PasswordTextBox");
+ InitializeComponent();
+ }
- public EnterPasswordDialog()
- {
- InitializeComponent();
- }
+ private TextBox PasswordTextBox => this.FindControl("PasswordTextBox")!;
- private void InitializeComponent()
- {
- AvaloniaXamlLoader.Load(this);
- }
+ public void OnCancelClick(object? sender, RoutedEventArgs e)
+ {
+ Close(null);
+ }
- public void OnCancelClick(object sender, RoutedEventArgs e)
- {
- Close(null);
- }
+ public void OnOkClick(object? sender, RoutedEventArgs e)
+ {
+ Close(PasswordTextBox.Text);
+ }
- public void OnOkClick(object sender, RoutedEventArgs e)
- {
- Close(PasswordTextBox.Text);
- }
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
}
}
diff --git a/samples/AvaloniaVncClient/Views/MainWindow.xaml b/samples/AvaloniaVncClient/Views/MainWindow.xaml
index 55a7727..c8602b0 100644
--- a/samples/AvaloniaVncClient/Views/MainWindow.xaml
+++ b/samples/AvaloniaVncClient/Views/MainWindow.xaml
@@ -1,3 +1,4 @@
+
-
-
-
+
+
@@ -32,7 +36,8 @@
-
+
-
+
@@ -58,7 +64,7 @@
-
+
@@ -71,11 +77,16 @@
-
-
-
-
+
+
+
+
diff --git a/samples/AvaloniaVncClient/Views/MainWindow.xaml.cs b/samples/AvaloniaVncClient/Views/MainWindow.xaml.cs
index 24c9051..ac10b2a 100644
--- a/samples/AvaloniaVncClient/Views/MainWindow.xaml.cs
+++ b/samples/AvaloniaVncClient/Views/MainWindow.xaml.cs
@@ -1,6 +1,5 @@
using System.Reactive.Disposables;
using System.Reactive.Linq;
-using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
@@ -10,57 +9,61 @@
using AvaloniaVncClient.Views.Dialogs;
using ReactiveUI;
-namespace AvaloniaVncClient.Views
-{
- public class MainWindow : ReactiveWindow
- {
- private Button ConnectButton => this.FindControl