wpf sucks

This commit is contained in:
Sem van der Hoeven
2020-10-12 16:32:23 +02:00
parent 6967fb625d
commit 7879aa301d
13 changed files with 311 additions and 11 deletions

View File

@@ -6,4 +6,8 @@
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AsyncAwaitBestPractices" Version="4.3.0" />
</ItemGroup>
</Project>

View File

@@ -11,6 +11,7 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedClientServer", "..\Sh
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
..\SharedClientServer\SharedClientServer.projitems*{67a9bf1a-d317-47ca-9f07-c3480d1360ff}*SharedItemsImports = 5
..\SharedClientServer\SharedClientServer.projitems*{6d26f969-9cb1-414f-ac3e-7253d449ac5a}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution

3
Server/FodyWeavers.xml Normal file
View File

@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
</Weavers>

74
Server/FodyWeavers.xsd Normal file
View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="PropertyChanged" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="InjectOnPropertyNameChanged" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if the On_PropertyName_Changed feature is enabled.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="TriggerDependentProperties" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if the Dependent properties feature is enabled.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="EnableIsChangedProperty" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if the IsChanged property feature is enabled.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="EventInvokerNames" type="xs:string">
<xs:annotation>
<xs:documentation>Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="CheckForEquality" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="CheckForEqualityUsingBaseEquals" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if equality checks should use the Equals method resolved from the base class.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseStaticEqualsFromBase" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if equality checks should use the static Equals method resolved from the base class.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="SuppressWarnings" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to turn off build warnings from this weaver.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="SuppressOnPropertyNameChangedWarning" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to turn off build warnings about mismatched On_PropertyName_Changed methods.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,14 @@

using SharedClientServer;
using System;
using System.Collections.Generic;
using System.Text;
namespace Server.Models
{
class Information : ObservableObject
{
public bool CanStartServer { get; set; }
}
}

View File

@@ -0,0 +1,99 @@

using SharedClientServer;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
namespace Server.Models
{
class ServerClient : ObservableObject
{
public string Username { get; set; }
private TcpClient tcpClient;
private NetworkStream stream;
private byte[] buffer = new byte[1024];
private byte[] totalBuffer = new byte[1024];
private int totalBufferReceived = 0;
public ServerClient(TcpClient client)
{
tcpClient = client;
stream = tcpClient.GetStream();
stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null);
}
/// <summary>
/// callback method that gets called when the stream has finished reading a message from the stream.
/// </summary>
/// <param name="ar">the async result status</param>
private void OnRead(IAsyncResult ar)
{
int bytesReceived = this.stream.EndRead(ar);
if (totalBufferReceived + bytesReceived > 1024)
{
throw new OutOfMemoryException("buffer is too small!");
}
// copy the received bytes into the buffer
Array.Copy(buffer, 0, totalBuffer, totalBufferReceived, bytesReceived);
// add the bytes we received to the total amount
totalBufferReceived += bytesReceived;
// calculate the expected length of the message
int expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0);
while (totalBufferReceived >= expectedMessageLength)
{
// we have received the full packet
byte[] message = new byte[expectedMessageLength];
// copy the total buffer contents into the message array so we can pass it to the handleIncomingMessage method
Array.Copy(totalBuffer, 0, message, 0, expectedMessageLength);
HandleIncomingMessage(message);
// move the contents of the totalbuffer to the start of the array
Array.Copy(totalBuffer, expectedMessageLength, totalBuffer, 0, (totalBufferReceived - expectedMessageLength));
totalBufferReceived -= expectedMessageLength;
expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0);
if (expectedMessageLength == 0)
{
break;
}
}
// start reading for a new message
stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null);
}
/// <summary>
/// Method to handle incoming message data
/// </summary>
/// <param name="message">the incoming message</param>
private void HandleIncomingMessage(byte[] message)
{
//TODO implement ways to handle the message
}
/// <summary>
/// sends a message to the tcp client
/// </summary>
/// <param name="message">message to send</param>
public void sendMessage(byte[] message)
{
stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null);
}
/// <summary>
/// callback method that gets called when the stream has finished writing the message
/// </summary>
/// <param name="ar">the async result status</param>
private void OnWrite(IAsyncResult ar)
{
stream.EndWrite(ar);
}
}
}

View File

@@ -0,0 +1,41 @@

using SharedClientServer;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Sockets;
using System.Text;
namespace Server.Models
{
class ServerCommunication : ObservableObject
{
private TcpListener listener;
private List<ServerClient> serverClients;
public bool Started = false;
public ServerCommunication(TcpListener listener)
{
this.listener = listener;
serverClients = new List<ServerClient>();
}
public void Start()
{
listener.Start();
Debug.WriteLine($"================================================\nStarted Accepting clients at {DateTime.Now}\n================================================");
Started = true;
listener.BeginAcceptTcpClient(new AsyncCallback(OnClientConnected), null);
}
private void OnClientConnected(IAsyncResult ar)
{
TcpClient tcpClient = listener.EndAcceptTcpClient(ar);
Console.WriteLine($"Got connection from {tcpClient.Client.RemoteEndPoint}");
ServerClient sc = new ServerClient(tcpClient);
serverClients.Add(new ServerClient(tcpClient));
listener.BeginAcceptTcpClient(new AsyncCallback(OnClientConnected), null);
}
}
}

View File

@@ -6,4 +6,12 @@
<UseWPF>true</UseWPF>
</PropertyGroup>
<Import Project="..\SharedClientServer\SharedClientServer.projitems" Label="Shared" />
<ItemGroup>
<PackageReference Include="AsyncAwaitBestPractices" Version="4.3.0" />
<PackageReference Include="MvvmLightLibs" Version="5.4.1.1" />
<PackageReference Include="PropertyChanged.Fody" Version="3.2.9" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,45 @@
using GalaSoft.MvvmLight.Command;
using Server.Models;
using SharedClientServer;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Input;
namespace Server.ViewModels
{
class MainViewModel : ObservableObject
{
private ServerCommunication serverCommunication;
public ICommand ServerStartCommand { get; set; }
public Information InformationModel { get; set; }
public MainViewModel()
{
Debug.WriteLine("init mainviewmodel");
InformationModel = new Information();
InformationModel.CanStartServer = true;
this.ServerStartCommand = new RelayCommand(() =>
{
Debug.WriteLine("connect button clicked");
if (serverCommunication == null)
{
Debug.WriteLine("making new server communication");
serverCommunication = new ServerCommunication(new TcpListener(IPAddress.Any,5555));
}
if (!serverCommunication.Started)
{
Debug.WriteLine("can start server " + InformationModel.CanStartServer);
serverCommunication.Start();
InformationModel.CanStartServer = false;
}
});
}
}
}

View File

@@ -7,9 +7,7 @@
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBox HorizontalAlignment="center" Margin="0,0,0,0" Text="{Binding ipAddress, Mode=OneWay}" TextWrapping="Wrap" VerticalAlignment="Center" Width="120"/>
<Label Content="IP address:" HorizontalAlignment="Center" Margin="0,176,0,0" VerticalAlignment="Top" Width="120"/>
<Button Content="Connect" HorizontalAlignment="Left" Margin="465,0,0,0" VerticalAlignment="Center" Click="ConnectServer"/>
<Button Content="Start Server" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Command="{Binding ServerStartCommand}" IsEnabled="{Binding MainViewModel.InformationModel.CanStartServer}"/>
<Label Content="{Binding MainViewModel.InformationModel.CanStartServer}" HorizontalAlignment="Left" Margin="97,7,0,0" VerticalAlignment="Top"/>
</Grid>
</Window>

View File

@@ -1,5 +1,7 @@
using System;
using Server.ViewModels;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -20,15 +22,13 @@ namespace Server
/// </summary>
public partial class MainWindow : Window
{
private string ipAddress = "test";
public MainWindow()
{
InitializeComponent();
}
private void ConnectServer(object sender, RoutedEventArgs e)
{
// use mainviewmodel for the bindings of our methods
DataContext = new MainViewModel();
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace SharedClientServer
{
public abstract class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
}
}

View File

@@ -10,5 +10,6 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)ClientServerUtil.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ObservableObject.cs" />
</ItemGroup>
</Project>