source code checkin

This commit is contained in:
Brett Hewitson 2021-01-07 16:23:23 +10:00
parent 5f8fb2c825
commit 7e57b72e35
675 changed files with 168433 additions and 0 deletions

View file

@ -0,0 +1,47 @@
using System;
namespace ServerManagerTool.Common.Attibutes
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class AggregateIniValueEntryAttribute : Attribute
{
/// <summary>
/// Attribute for the IniFile value
/// </summary>
/// <param name="key">The key of the value. Defaults to the same name as the attributed field.</param>
public AggregateIniValueEntryAttribute(string key = "")
{
this.Key = key;
}
/// <summary>
/// The key of the value.
/// </summary>
public string Key;
/// <summary>
/// If true, the value will always be surrounded with brackets
/// </summary>
public bool ValueWithinBrackets;
/// <summary>
/// If true, the every list value will always be surrounded with brackets
/// </summary>
public bool ListValueWithinBrackets;
/// <summary>
/// Determines the number od brackets around the Value delimiter. Default 1, but will be higher for hierarchial values.
/// </summary>
public int BracketsAroundValueDelimiter = 1;
/// <summary>
/// If true, then the property with not be written if empty. This does not work for collections, only value types.
/// </summary>
public bool ExcludeIfEmpty;
/// <summary>
/// If true, then the property with not be written if false. This does not work for collections, only BOOLEAN types.
/// </summary>
public bool ExcludeIfFalse = false;
}
}

View file

@ -0,0 +1,98 @@
using ServerManagerTool.Common.Enums;
using System;
namespace ServerManagerTool.Common.Attibutes
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public abstract class BaseIniFileEntryAttribute : Attribute
{
/// <summary>
/// Attribute for the IniFile serializer
/// </summary>
/// <param name="file">The file into which the setting should be serialized.</param>
/// <param name="section">The section in the ini file.</param>
/// <param name="category">The category of the setting.</param>
/// <param name="key">The key within the section. Defaults to the same name as the attributed field.</param>
protected BaseIniFileEntryAttribute(Enum file, Enum section, Enum category, string key = "")
{
this.File = file;
this.Section = section;
this.Category = category;
this.Key = key;
this.QuotedString = QuotedStringType.False;
this.Multiline = false;
this.MultilineSeparator = @"\n";
}
public Enum File { get; set; }
/// <summary>
/// The section of the ini file.
/// </summary>
public Enum Section { get; set; }
/// <summary>
/// The category of the setting.
/// </summary>
public Enum Category { get; set; }
/// <summary>
/// The key within the section.
/// </summary>
public string Key;
/// <summary>
/// Only write the attributed value if the value is different to the specified value.
/// </summary>
public object WriteIfNotValue;
/// <summary>
/// If true, the value of booleans will be inverted when read or written.
/// </summary>
public bool InvertBoolean;
/// <summary>
/// If true, will also write a true boolean value when the underlying field is non-default (or empty for strings), otherwise a false value will be written.
/// </summary>
public bool WriteBoolValueIfNonEmpty;
/// <summary>
/// If true, the value of booleans will be written as an integer (0 = false, 1 = true).
/// </summary>
public bool WriteBooleanAsInteger;
/// <summary>
/// Clear the section before writing this value.
/// </summary>
public bool ClearSection;
/// <summary>
/// If true, the value will always be written with quotes, if remove, the value will always be written without quotes even if added.
/// </summary>
public QuotedStringType QuotedString;
/// <summary>
/// Only write the attributed value if the named field is true.
/// </summary>
public string ConditionedOn;
/// <summary>
/// If true, the value will be treated as a multiline value.
/// </summary>
public bool Multiline;
/// <summary>
/// The new line separator to use when Multiline = True.
/// </summary>
public string MultilineSeparator;
/// <summary>
/// Clears the value when the named field is off, otherwise if on will skip the update.
/// NOTE: Use this for config fields that are updated by the server, while it is ruuning.
/// </summary>
public string ClearWhenOff;
public bool IsCustom;
}
}

View file

@ -0,0 +1,164 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ServerManagerTool.Common {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
public sealed partial class CommonConfig : global::System.Configuration.ApplicationSettingsBase {
private static CommonConfig defaultInstance = ((CommonConfig)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new CommonConfig())));
public static CommonConfig Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("http://whatismyip.akamai.com/")]
public string PublicIPCheckUrl {
get {
return ((string)(this["PublicIPCheckUrl"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("SteamCMD")]
public string SteamCmdRelativePath {
get {
return ((string)(this["SteamCmdRelativePath"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("SteamCMD.exe")]
public string SteamCmdExeFile {
get {
return ((string)(this["SteamCmdExeFile"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("SteamCMD.zip")]
public string SteamCmdZipFile {
get {
return ((string)(this["SteamCmdZipFile"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip")]
public string SteamCmdUrl {
get {
return ((string)(this["SteamCmdUrl"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("+login anonymous +quit")]
public string SteamCmdInstallArgs {
get {
return ((string)(this["SteamCmdInstallArgs"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string DefaultSteamAPIKey {
get {
return ((string)(this["DefaultSteamAPIKey"]));
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string SteamAPIKey {
get {
return ((string)(this["SteamAPIKey"]));
}
set {
this["SteamAPIKey"] = value;
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("https://steamcommunity.com/dev/apikey")]
public string SteamAPIKeyUrl {
get {
return ((string)(this["SteamAPIKeyUrl"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("+login {0} {1} +quit")]
public string SteamCmdAuthenticateArgs {
get {
return ((string)(this["SteamCmdAuthenticateArgs"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Steam")]
public string SteamProcessName {
get {
return ((string)(this["SteamProcessName"]));
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string SteamClientFile {
get {
return ((string)(this["SteamClientFile"]));
}
set {
this["SteamClientFile"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool UpgradeConfig {
get {
return ((bool)(this["UpgradeConfig"]));
}
set {
this["UpgradeConfig"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool SteamCmdRemoveQuit {
get {
return ((bool)(this["SteamCmdRemoveQuit"]));
}
set {
this["SteamCmdRemoveQuit"] = value;
}
}
}
}

View file

@ -0,0 +1,48 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="ServerManagerTool.Common" GeneratedClassName="CommonConfig">
<Profiles />
<Settings>
<Setting Name="PublicIPCheckUrl" Type="System.String" Scope="Application">
<Value Profile="(Default)">http://whatismyip.akamai.com/</Value>
</Setting>
<Setting Name="SteamCmdRelativePath" Type="System.String" Scope="Application">
<Value Profile="(Default)">SteamCMD</Value>
</Setting>
<Setting Name="SteamCmdExeFile" Type="System.String" Scope="Application">
<Value Profile="(Default)">SteamCMD.exe</Value>
</Setting>
<Setting Name="SteamCmdZipFile" Type="System.String" Scope="Application">
<Value Profile="(Default)">SteamCMD.zip</Value>
</Setting>
<Setting Name="SteamCmdUrl" Type="System.String" Scope="Application">
<Value Profile="(Default)">https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip</Value>
</Setting>
<Setting Name="SteamCmdInstallArgs" Type="System.String" Scope="Application">
<Value Profile="(Default)">+login anonymous +quit</Value>
</Setting>
<Setting Name="DefaultSteamAPIKey" Type="System.String" Scope="Application">
<Value Profile="(Default)" />
</Setting>
<Setting Name="SteamAPIKey" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="SteamAPIKeyUrl" Type="System.String" Scope="Application">
<Value Profile="(Default)">https://steamcommunity.com/dev/apikey</Value>
</Setting>
<Setting Name="SteamCmdAuthenticateArgs" Type="System.String" Scope="Application">
<Value Profile="(Default)">+login {0} {1} +quit</Value>
</Setting>
<Setting Name="SteamProcessName" Type="System.String" Scope="Application">
<Value Profile="(Default)">Steam</Value>
</Setting>
<Setting Name="SteamClientFile" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="UpgradeConfig" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="SteamCmdRemoveQuit" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>

View file

@ -0,0 +1,16 @@
namespace ServerManagerTool.Common
{
public static class Constants
{
public const string ARG_AUTOBACKUP = "-ab";
public const string ARG_AUTOSHUTDOWN1 = "-as1";
public const string ARG_AUTOSHUTDOWN2 = "-as2";
public const string ARG_AUTORESTART = "-ar";
public const string ARG_AUTOUPDATE = "-au";
public const string ARG_BETA = "-beta";
public const string ARG_RCON = "-rcon";
public const string ARG_SERVERMONITOR = "-sm";
public const string ARG_TEST = "-test";
public const string ARG_TITLE = "-title";
}
}

View file

@ -0,0 +1,298 @@
<UserControl x:Class="ServerManagerTool.Common.Controls.AnnotatedCheckBoxAndFloatSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters"
mc:Ignorable="d"
d:DesignWidth="300"
d:DesignHeight="25"
x:Name="Control">
<UserControl.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="SliderThumb.Static.Foreground" Color="#FFE5E5E5"/>
<SolidColorBrush x:Key="SliderThumb.MouseOver.Background" Color="#FFDCECFC"/>
<SolidColorBrush x:Key="SliderThumb.MouseOver.Border" Color="#FF7Eb4EA"/>
<SolidColorBrush x:Key="SliderThumb.Pressed.Background" Color="#FFDAECFC"/>
<SolidColorBrush x:Key="SliderThumb.Pressed.Border" Color="#FF569DE5"/>
<SolidColorBrush x:Key="SliderThumb.Disabled.Background" Color="#FFF0F0F0"/>
<SolidColorBrush x:Key="SliderThumb.Disabled.Border" Color="#FFD9D9D9"/>
<SolidColorBrush x:Key="SliderThumb.Static.Background" Color="#FFF0F0F0"/>
<SolidColorBrush x:Key="SliderThumb.Static.Border" Color="#FFACACAC"/>
<SolidColorBrush x:Key="SliderThumb.Track.Border" Color="#FFD6D6D6"/>
<SolidColorBrush x:Key="SliderThumb.Track.BorderBackground" Color="#FFE7EAEA"/>
<SolidColorBrush x:Key="SliderThumb.Grip.Fill" Color="#FFE6DFD8"/>
<SolidColorBrush x:Key="SliderThumb.Tick.Bottom" Color="#FFD8CCBC"/>
<SolidColorBrush x:Key="SliderThumb.Track.Background" Color="#FFBFA786"/>
<ControlTemplate x:Key="SliderThumbHorizontalTop" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 0,6 C0,6 5.5,0 5.5,0 5.5,0 11,6 11,6 11,6 11,18 11,18 11,18 0,18 0,18 0,18 0,6 0,6 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbHorizontalBottom" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 0,12 C0,12 5.5,18 5.5,18 5.5,18 11,12 11,12 11,12 11,0 11,0 11,0 0,0 0,0 0,0 0,12 0,12 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="RepeatButtonTransparent" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Rectangle Fill="{TemplateBinding Background}" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="SliderThumbHorizontalDefault" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 0,0 C0,0 11,0 11,0 11,0 11,18 11,18 11,18 0,18 0,18 0,18 0,0 0,0 z" Fill="{DynamicResource SliderThumb.Grip.Fill}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderHorizontal" TargetType="{x:Type Slider}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TickBar x:Name="TopTick" Fill="{TemplateBinding Foreground}" Height="4" Margin="0,0,0,2" Placement="Top" Grid.Row="0" Visibility="Collapsed"/>
<TickBar x:Name="BottomTick" Fill="{DynamicResource SliderThumb.Tick.Bottom}" Height="4" Margin="0,2,0,0" Placement="Bottom" Grid.Row="2" Visibility="Collapsed"/>
<Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="1" Background="{StaticResource SliderThumb.Track.BorderBackground}" Height="4.0" Margin="5,0" Grid.Row="1" VerticalAlignment="center">
<Canvas Margin="-6,-1" Background="{DynamicResource SliderThumb.Track.Background}">
<Rectangle x:Name="PART_SelectionRange" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="4.0" Visibility="Hidden"/>
</Canvas>
</Border>
<Track x:Name="PART_Track" Grid.Row="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb x:Name="Thumb" Focusable="False" Height="18" OverridesDefaultStyle="True" Template="{StaticResource SliderThumbHorizontalDefault}" VerticalAlignment="Center" Width="11" Foreground="#FFBFA786"/>
</Track.Thumb>
</Track>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="TickPlacement" Value="TopLeft">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbHorizontalTop}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="5,2,5,0"/>
</Trigger>
<Trigger Property="TickPlacement" Value="BottomRight">
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbHorizontalBottom}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="5,0,5,2"/>
</Trigger>
<Trigger Property="TickPlacement" Value="Both">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
</Trigger>
<Trigger Property="IsSelectionRangeEnabled" Value="true">
<Setter Property="Visibility" TargetName="PART_SelectionRange" Value="Visible"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="Foreground" TargetName="Thumb" Value="Blue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbVerticalLeft" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 6,11 C6,11 0,5.5 0,5.5 0,5.5 6,0 6,0 6,0 18,0 18,0 18,0 18,11 18,11 18,11 6,11 6,11 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbVerticalRight" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 12,11 C12,11 18,5.5 18,5.5 18,5.5 12,0 12,0 12,0 0,0 0,0 0,0 0,11 0,11 0,11 12,11 12,11 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbVerticalDefault" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M0.5,0.5 L18.5,0.5 18.5,11.5 0.5,11.5z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderVertical" TargetType="{x:Type Slider}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition MinWidth="{TemplateBinding MinWidth}" Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TickBar x:Name="TopTick" Grid.Column="0" Fill="{TemplateBinding Foreground}" Margin="0,0,2,0" Placement="Left" Visibility="Collapsed" Width="4"/>
<TickBar x:Name="BottomTick" Grid.Column="2" Fill="{TemplateBinding Foreground}" Margin="2,0,0,0" Placement="Right" Visibility="Collapsed" Width="4"/>
<Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="1" Background="{StaticResource SliderThumb.Track.BorderBackground}" Grid.Column="1" HorizontalAlignment="center" Margin="0,5" Width="4.0">
<Canvas Margin="-1,-6">
<Rectangle x:Name="PART_SelectionRange" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Visibility="Hidden" Width="4.0"/>
</Canvas>
</Border>
<Track x:Name="PART_Track" Grid.Column="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb x:Name="Thumb" Focusable="False" Height="11" OverridesDefaultStyle="True" Template="{StaticResource SliderThumbVerticalDefault}" VerticalAlignment="Top" Width="18"/>
</Track.Thumb>
</Track>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="TickPlacement" Value="TopLeft">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbVerticalLeft}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="2,5,0,5"/>
</Trigger>
<Trigger Property="TickPlacement" Value="BottomRight">
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbVerticalRight}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="0,5,2,5"/>
</Trigger>
<Trigger Property="TickPlacement" Value="Both">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
</Trigger>
<Trigger Property="IsSelectionRangeEnabled" Value="true">
<Setter Property="Visibility" TargetName="PART_SelectionRange" Value="Visible"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="Foreground" TargetName="Thumb" Value="Blue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="AnnotatedSliderStyle" TargetType="{x:Type Slider}">
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource SliderThumb.Static.Foreground}"/>
<Setter Property="Template" Value="{StaticResource SliderHorizontal}"/>
<Style.Triggers>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="Template" Value="{StaticResource SliderVertical}"/>
</Trigger>
</Style.Triggers>
</Style>
<cc:NullableHasValueConverter x:Key="NullableHasValueConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding LabelRelativeWidth}" MinWidth="{Binding LabelRelativeMinWidth}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="{Binding SliderRelativeWidth}" MinWidth="{Binding SliderRelativeMinWidth}"/>
<ColumnDefinition Width="{Binding ValueRelativeWidth}" MinWidth="{Binding ValueRelativeMinWidth}"/>
<ColumnDefinition Width="{Binding SuffixRelativeWidth}" MinWidth="{Binding SuffixRelativeMinWidth}"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding Label}" VerticalContentAlignment="Center"/>
<CheckBox x:Name="CheckBox" Grid.Column="1" Margin="2,0,2,0" IsChecked="{Binding Value.HasValue}" VerticalAlignment="Center" VerticalContentAlignment="Center"/>
<Slider x:Name="Slider" Grid.Column="2" Margin="0,0,5,0" IsEnabled="{Binding ElementName=CheckBox, Path=IsChecked, FallbackValue=False}"
Value="{Binding Value.Value, Mode=OneWay}"
Minimum="{Binding Minimum}"
Maximum="{Binding Maximum}"
LargeChange="{Binding LargeChange}"
SmallChange="{Binding SmallChange}"
TickFrequency="{Binding TickFrequency}" Style="{DynamicResource AnnotatedSliderStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
HorizontalContentAlignment="Stretch"
ValueChanged="Slider_ValueChanged"/>
<TextBox x:Name="Text" Grid.Column="3" Text="{Binding Value.Value, Mode=TwoWay, StringFormat={}{0:#######,##0.##########}}" IsEnabled="{Binding ElementName=CheckBox, Path=IsChecked, FallbackValue=False}" VerticalContentAlignment="Center" MinHeight="{Binding ValueRelativeMinHeight}"/>
<Label Grid.Column="4" Content="{Binding Suffix}" VerticalContentAlignment="Center" />
</Grid>
</UserControl>

View file

@ -0,0 +1,152 @@
using ServerManagerTool.Common.Model;
using System.Windows;
using System.Windows.Controls;
namespace ServerManagerTool.Common.Controls
{
/// <summary>
/// Interaction logic for AnnotatedSlider.xaml
/// </summary>
public partial class AnnotatedCheckBoxAndFloatSlider : UserControl
{
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(nameof(Label), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(NullableValue<float>), typeof(AnnotatedCheckBoxAndFloatSlider), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty SuffixProperty = DependencyProperty.Register(nameof(Suffix), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider));
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(nameof(Minimum), typeof(float), typeof(AnnotatedCheckBoxAndFloatSlider));
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(nameof(Maximum), typeof(float), typeof(AnnotatedCheckBoxAndFloatSlider));
public static readonly DependencyProperty LargeChangeProperty = DependencyProperty.Register(nameof(LargeChange), typeof(float), typeof(AnnotatedCheckBoxAndFloatSlider));
public static readonly DependencyProperty SmallChangeProperty = DependencyProperty.Register(nameof(SmallChange), typeof(float), typeof(AnnotatedCheckBoxAndFloatSlider));
public static readonly DependencyProperty TickFrequencyProperty = DependencyProperty.Register(nameof(TickFrequency), typeof(float), typeof(AnnotatedCheckBoxAndFloatSlider));
public static readonly DependencyProperty LabelRelativeWidthProperty = DependencyProperty.Register(nameof(LabelRelativeWidth), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider), new PropertyMetadata("4*"));
public static readonly DependencyProperty LabelRelativeMinWidthProperty = DependencyProperty.Register(nameof(LabelRelativeMinWidth), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider), new PropertyMetadata("0"));
public static readonly DependencyProperty SliderRelativeWidthProperty = DependencyProperty.Register(nameof(SliderRelativeWidth), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider), new PropertyMetadata("8*"));
public static readonly DependencyProperty SliderRelativeMinWidthProperty = DependencyProperty.Register(nameof(SliderRelativeMinWidth), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider), new PropertyMetadata("0"));
public static readonly DependencyProperty ValueRelativeWidthProperty = DependencyProperty.Register(nameof(ValueRelativeWidth), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider), new PropertyMetadata("2*"));
public static readonly DependencyProperty ValueRelativeMinWidthProperty = DependencyProperty.Register(nameof(ValueRelativeMinWidth), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider), new PropertyMetadata("50"));
public static readonly DependencyProperty ValueRelativeMinHeightProperty = DependencyProperty.Register(nameof(ValueRelativeMinHeight), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider), new PropertyMetadata("25"));
public static readonly DependencyProperty SuffixRelativeWidthProperty = DependencyProperty.Register(nameof(SuffixRelativeWidth), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider), new PropertyMetadata("1*"));
public static readonly DependencyProperty SuffixRelativeMinWidthProperty = DependencyProperty.Register(nameof(SuffixRelativeMinWidth), typeof(string), typeof(AnnotatedCheckBoxAndFloatSlider), new PropertyMetadata("0"));
public AnnotatedCheckBoxAndFloatSlider()
{
InitializeComponent();
Value = new NullableValue<float>();
(this.Content as FrameworkElement).DataContext = this;
}
public string Label
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public NullableValue<float> Value
{
get { return (NullableValue<float>)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public string Suffix
{
get { return (string)GetValue(SuffixProperty); }
set { SetValue(SuffixProperty, value); }
}
public float Minimum
{
get { return (float)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public float Maximum
{
get { return (float)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public float LargeChange
{
get { return (float)GetValue(LargeChangeProperty); }
set { SetValue(LargeChangeProperty, value); }
}
public float SmallChange
{
get { return (float)GetValue(SmallChangeProperty); }
set { SetValue(SmallChangeProperty, value); }
}
public float TickFrequency
{
get { return (float)GetValue(TickFrequencyProperty); }
set { SetValue(TickFrequencyProperty, value); }
}
public string LabelRelativeWidth
{
get { return (string)GetValue(LabelRelativeWidthProperty); }
set { SetValue(LabelRelativeWidthProperty, value); }
}
public string LabelRelativeMinWidth
{
get { return (string)GetValue(LabelRelativeMinWidthProperty); }
set { SetValue(LabelRelativeMinWidthProperty, value); }
}
public string SliderRelativeWidth
{
get { return (string)GetValue(SliderRelativeWidthProperty); }
set { SetValue(SliderRelativeWidthProperty, value); }
}
public string SliderRelativeMinWidth
{
get { return (string)GetValue(SliderRelativeMinWidthProperty); }
set { SetValue(SliderRelativeMinWidthProperty, value); }
}
public string ValueRelativeWidth
{
get { return (string)GetValue(ValueRelativeWidthProperty); }
set { SetValue(ValueRelativeWidthProperty, value); }
}
public string ValueRelativeMinWidth
{
get { return (string)GetValue(ValueRelativeMinWidthProperty); }
set { SetValue(ValueRelativeMinWidthProperty, value); }
}
public string ValueRelativeMinHeight
{
get { return (string)GetValue(ValueRelativeMinHeightProperty); }
set { SetValue(ValueRelativeMinHeightProperty, value); }
}
public string SuffixRelativeWidth
{
get { return (string)GetValue(SuffixRelativeWidthProperty); }
set { SetValue(SuffixRelativeWidthProperty, value); }
}
public string SuffixRelativeMinWidth
{
get { return (string)GetValue(SuffixRelativeMinWidthProperty); }
set { SetValue(SuffixRelativeMinWidthProperty, value); }
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (Slider.IsFocused)
{
unchecked
{
Value.Value = (float)e.NewValue;
}
}
}
}
}

View file

@ -0,0 +1,298 @@
<UserControl x:Class="ServerManagerTool.Common.Controls.AnnotatedCheckBoxAndIntegerSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cc="clr-namespace:ServerManagerTool.Common.Converters"
mc:Ignorable="d"
d:DesignWidth="300"
d:DesignHeight="25"
x:Name="Control">
<UserControl.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="SliderThumb.Static.Foreground" Color="#FFE5E5E5"/>
<SolidColorBrush x:Key="SliderThumb.MouseOver.Background" Color="#FFDCECFC"/>
<SolidColorBrush x:Key="SliderThumb.MouseOver.Border" Color="#FF7Eb4EA"/>
<SolidColorBrush x:Key="SliderThumb.Pressed.Background" Color="#FFDAECFC"/>
<SolidColorBrush x:Key="SliderThumb.Pressed.Border" Color="#FF569DE5"/>
<SolidColorBrush x:Key="SliderThumb.Disabled.Background" Color="#FFF0F0F0"/>
<SolidColorBrush x:Key="SliderThumb.Disabled.Border" Color="#FFD9D9D9"/>
<SolidColorBrush x:Key="SliderThumb.Static.Background" Color="#FFF0F0F0"/>
<SolidColorBrush x:Key="SliderThumb.Static.Border" Color="#FFACACAC"/>
<SolidColorBrush x:Key="SliderThumb.Track.Border" Color="#FFD6D6D6"/>
<SolidColorBrush x:Key="SliderThumb.Track.BorderBackground" Color="#FFE7EAEA"/>
<SolidColorBrush x:Key="SliderThumb.Grip.Fill" Color="#FFE6DFD8"/>
<SolidColorBrush x:Key="SliderThumb.Tick.Bottom" Color="#FFD8CCBC"/>
<SolidColorBrush x:Key="SliderThumb.Track.Background" Color="#FFBFA786"/>
<ControlTemplate x:Key="SliderThumbHorizontalTop" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 0,6 C0,6 5.5,0 5.5,0 5.5,0 11,6 11,6 11,6 11,18 11,18 11,18 0,18 0,18 0,18 0,6 0,6 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbHorizontalBottom" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 0,12 C0,12 5.5,18 5.5,18 5.5,18 11,12 11,12 11,12 11,0 11,0 11,0 0,0 0,0 0,0 0,12 0,12 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="RepeatButtonTransparent" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Rectangle Fill="{TemplateBinding Background}" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="SliderThumbHorizontalDefault" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 0,0 C0,0 11,0 11,0 11,0 11,18 11,18 11,18 0,18 0,18 0,18 0,0 0,0 z" Fill="{DynamicResource SliderThumb.Grip.Fill}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderHorizontal" TargetType="{x:Type Slider}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TickBar x:Name="TopTick" Fill="{TemplateBinding Foreground}" Height="4" Margin="0,0,0,2" Placement="Top" Grid.Row="0" Visibility="Collapsed"/>
<TickBar x:Name="BottomTick" Fill="{DynamicResource SliderThumb.Tick.Bottom}" Height="4" Margin="0,2,0,0" Placement="Bottom" Grid.Row="2" Visibility="Collapsed"/>
<Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="1" Background="{StaticResource SliderThumb.Track.BorderBackground}" Height="4.0" Margin="5,0" Grid.Row="1" VerticalAlignment="center">
<Canvas Margin="-6,-1" Background="{DynamicResource SliderThumb.Track.Background}">
<Rectangle x:Name="PART_SelectionRange" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="4.0" Visibility="Hidden"/>
</Canvas>
</Border>
<Track x:Name="PART_Track" Grid.Row="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb x:Name="Thumb" Focusable="False" Height="18" OverridesDefaultStyle="True" Template="{StaticResource SliderThumbHorizontalDefault}" VerticalAlignment="Center" Width="11" Foreground="#FFBFA786"/>
</Track.Thumb>
</Track>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="TickPlacement" Value="TopLeft">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbHorizontalTop}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="5,2,5,0"/>
</Trigger>
<Trigger Property="TickPlacement" Value="BottomRight">
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbHorizontalBottom}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="5,0,5,2"/>
</Trigger>
<Trigger Property="TickPlacement" Value="Both">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
</Trigger>
<Trigger Property="IsSelectionRangeEnabled" Value="true">
<Setter Property="Visibility" TargetName="PART_SelectionRange" Value="Visible"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="Foreground" TargetName="Thumb" Value="Blue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbVerticalLeft" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 6,11 C6,11 0,5.5 0,5.5 0,5.5 6,0 6,0 6,0 18,0 18,0 18,0 18,11 18,11 18,11 6,11 6,11 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbVerticalRight" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 12,11 C12,11 18,5.5 18,5.5 18,5.5 12,0 12,0 12,0 0,0 0,0 0,0 0,11 0,11 0,11 12,11 12,11 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbVerticalDefault" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M0.5,0.5 L18.5,0.5 18.5,11.5 0.5,11.5z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderVertical" TargetType="{x:Type Slider}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition MinWidth="{TemplateBinding MinWidth}" Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TickBar x:Name="TopTick" Grid.Column="0" Fill="{TemplateBinding Foreground}" Margin="0,0,2,0" Placement="Left" Visibility="Collapsed" Width="4"/>
<TickBar x:Name="BottomTick" Grid.Column="2" Fill="{TemplateBinding Foreground}" Margin="2,0,0,0" Placement="Right" Visibility="Collapsed" Width="4"/>
<Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="1" Background="{StaticResource SliderThumb.Track.BorderBackground}" Grid.Column="1" HorizontalAlignment="center" Margin="0,5" Width="4.0">
<Canvas Margin="-1,-6">
<Rectangle x:Name="PART_SelectionRange" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Visibility="Hidden" Width="4.0"/>
</Canvas>
</Border>
<Track x:Name="PART_Track" Grid.Column="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb x:Name="Thumb" Focusable="False" Height="11" OverridesDefaultStyle="True" Template="{StaticResource SliderThumbVerticalDefault}" VerticalAlignment="Top" Width="18"/>
</Track.Thumb>
</Track>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="TickPlacement" Value="TopLeft">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbVerticalLeft}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="2,5,0,5"/>
</Trigger>
<Trigger Property="TickPlacement" Value="BottomRight">
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbVerticalRight}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="0,5,2,5"/>
</Trigger>
<Trigger Property="TickPlacement" Value="Both">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
</Trigger>
<Trigger Property="IsSelectionRangeEnabled" Value="true">
<Setter Property="Visibility" TargetName="PART_SelectionRange" Value="Visible"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="Foreground" TargetName="Thumb" Value="Blue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="AnnotatedSliderStyle" TargetType="{x:Type Slider}">
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource SliderThumb.Static.Foreground}"/>
<Setter Property="Template" Value="{StaticResource SliderHorizontal}"/>
<Style.Triggers>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="Template" Value="{StaticResource SliderVertical}"/>
</Trigger>
</Style.Triggers>
</Style>
<cc:NullableHasValueConverter x:Key="NullableHasValueConverter"/>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding LabelRelativeWidth}" MinWidth="{Binding LabelRelativeMinWidth}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="{Binding SliderRelativeWidth}" MinWidth="{Binding SliderRelativeMinWidth}"/>
<ColumnDefinition Width="{Binding ValueRelativeWidth}" MinWidth="{Binding ValueRelativeMinWidth}"/>
<ColumnDefinition Width="{Binding SuffixRelativeWidth}" MinWidth="{Binding SuffixRelativeMinWidth}"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding Label}" VerticalContentAlignment="Center"/>
<CheckBox x:Name="CheckBox" Grid.Column="1" Margin="2,0,2,0" IsChecked="{Binding Value.HasValue}" VerticalAlignment="Center" VerticalContentAlignment="Center"/>
<Slider x:Name="Slider" Grid.Column="2" Margin="0,0,5,0" IsEnabled="{Binding ElementName=CheckBox, Path=IsChecked, FallbackValue=False}"
Value="{Binding Value.Value, Mode=OneWay}"
Minimum="{Binding Minimum}"
Maximum="{Binding Maximum}"
LargeChange="{Binding LargeChange}"
SmallChange="{Binding SmallChange}"
TickFrequency="{Binding TickFrequency}" Style="{DynamicResource AnnotatedSliderStyle}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
HorizontalContentAlignment="Stretch"
ValueChanged="Slider_ValueChanged"/>
<TextBox x:Name="Text" Grid.Column="3" Text="{Binding Value.Value, Mode=TwoWay, StringFormat={}{0:#######,##0}}" IsEnabled="{Binding ElementName=CheckBox, Path=IsChecked, FallbackValue=False}" VerticalContentAlignment="Center" MinHeight="{Binding ValueRelativeMinHeight}"/>
<Label Grid.Column="4" Content="{Binding Suffix}" VerticalContentAlignment="Center" />
</Grid>
</UserControl>

View file

@ -0,0 +1,152 @@
using ServerManagerTool.Common.Model;
using System.Windows;
using System.Windows.Controls;
namespace ServerManagerTool.Common.Controls
{
/// <summary>
/// Interaction logic for AnnotatedSlider.xaml
/// </summary>
public partial class AnnotatedCheckBoxAndIntegerSlider : UserControl
{
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(nameof(Label), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(NullableValue<int>), typeof(AnnotatedCheckBoxAndIntegerSlider), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty SuffixProperty = DependencyProperty.Register(nameof(Suffix), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider));
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(nameof(Minimum), typeof(float), typeof(AnnotatedCheckBoxAndIntegerSlider));
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(nameof(Maximum), typeof(float), typeof(AnnotatedCheckBoxAndIntegerSlider));
public static readonly DependencyProperty LargeChangeProperty = DependencyProperty.Register(nameof(LargeChange), typeof(float), typeof(AnnotatedCheckBoxAndIntegerSlider));
public static readonly DependencyProperty SmallChangeProperty = DependencyProperty.Register(nameof(SmallChange), typeof(float), typeof(AnnotatedCheckBoxAndIntegerSlider));
public static readonly DependencyProperty TickFrequencyProperty = DependencyProperty.Register(nameof(TickFrequency), typeof(float), typeof(AnnotatedCheckBoxAndIntegerSlider));
public static readonly DependencyProperty LabelRelativeWidthProperty = DependencyProperty.Register(nameof(LabelRelativeWidth), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider), new PropertyMetadata("4*"));
public static readonly DependencyProperty LabelRelativeMinWidthProperty = DependencyProperty.Register(nameof(LabelRelativeMinWidth), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider), new PropertyMetadata("0"));
public static readonly DependencyProperty SliderRelativeWidthProperty = DependencyProperty.Register(nameof(SliderRelativeWidth), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider), new PropertyMetadata("8*"));
public static readonly DependencyProperty SliderRelativeMinWidthProperty = DependencyProperty.Register(nameof(SliderRelativeMinWidth), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider), new PropertyMetadata("0"));
public static readonly DependencyProperty ValueRelativeWidthProperty = DependencyProperty.Register(nameof(ValueRelativeWidth), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider), new PropertyMetadata("2*"));
public static readonly DependencyProperty ValueRelativeMinWidthProperty = DependencyProperty.Register(nameof(ValueRelativeMinWidth), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider), new PropertyMetadata("50"));
public static readonly DependencyProperty ValueRelativeMinHeightProperty = DependencyProperty.Register(nameof(ValueRelativeMinHeight), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider), new PropertyMetadata("25"));
public static readonly DependencyProperty SuffixRelativeWidthProperty = DependencyProperty.Register(nameof(SuffixRelativeWidth), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider), new PropertyMetadata("1*"));
public static readonly DependencyProperty SuffixRelativeMinWidthProperty = DependencyProperty.Register(nameof(SuffixRelativeMinWidth), typeof(string), typeof(AnnotatedCheckBoxAndIntegerSlider), new PropertyMetadata("0"));
public AnnotatedCheckBoxAndIntegerSlider()
{
InitializeComponent();
Value = new NullableValue<int>();
(this.Content as FrameworkElement).DataContext = this;
}
public string Label
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public NullableValue<int> Value
{
get { return (NullableValue<int>)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public string Suffix
{
get { return (string)GetValue(SuffixProperty); }
set { SetValue(SuffixProperty, value); }
}
public float Minimum
{
get { return (float)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public float Maximum
{
get { return (float)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public float LargeChange
{
get { return (float)GetValue(LargeChangeProperty); }
set { SetValue(LargeChangeProperty, value); }
}
public float SmallChange
{
get { return (float)GetValue(SmallChangeProperty); }
set { SetValue(SmallChangeProperty, value); }
}
public float TickFrequency
{
get { return (float)GetValue(TickFrequencyProperty); }
set { SetValue(TickFrequencyProperty, value); }
}
public string LabelRelativeWidth
{
get { return (string)GetValue(LabelRelativeWidthProperty); }
set { SetValue(LabelRelativeWidthProperty, value); }
}
public string LabelRelativeMinWidth
{
get { return (string)GetValue(LabelRelativeMinWidthProperty); }
set { SetValue(LabelRelativeMinWidthProperty, value); }
}
public string SliderRelativeWidth
{
get { return (string)GetValue(SliderRelativeWidthProperty); }
set { SetValue(SliderRelativeWidthProperty, value); }
}
public string SliderRelativeMinWidth
{
get { return (string)GetValue(SliderRelativeMinWidthProperty); }
set { SetValue(SliderRelativeMinWidthProperty, value); }
}
public string ValueRelativeWidth
{
get { return (string)GetValue(ValueRelativeWidthProperty); }
set { SetValue(ValueRelativeWidthProperty, value); }
}
public string ValueRelativeMinWidth
{
get { return (string)GetValue(ValueRelativeMinWidthProperty); }
set { SetValue(ValueRelativeMinWidthProperty, value); }
}
public string ValueRelativeMinHeight
{
get { return (string)GetValue(ValueRelativeMinHeightProperty); }
set { SetValue(ValueRelativeMinHeightProperty, value); }
}
public string SuffixRelativeWidth
{
get { return (string)GetValue(SuffixRelativeWidthProperty); }
set { SetValue(SuffixRelativeWidthProperty, value); }
}
public string SuffixRelativeMinWidth
{
get { return (string)GetValue(SuffixRelativeMinWidthProperty); }
set { SetValue(SuffixRelativeMinWidthProperty, value); }
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (Slider.IsFocused)
{
unchecked
{
Value.Value = (int)e.NewValue;
}
}
}
}
}

View file

@ -0,0 +1,292 @@
<UserControl x:Class="ServerManagerTool.Common.Controls.AnnotatedSlider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignWidth="300"
d:DesignHeight="25"
x:Name="Control">
<UserControl.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="SliderThumb.Static.Foreground" Color="#FFE5E5E5"/>
<SolidColorBrush x:Key="SliderThumb.MouseOver.Background" Color="#FFDCECFC"/>
<SolidColorBrush x:Key="SliderThumb.MouseOver.Border" Color="#FF7Eb4EA"/>
<SolidColorBrush x:Key="SliderThumb.Pressed.Background" Color="#FFDAECFC"/>
<SolidColorBrush x:Key="SliderThumb.Pressed.Border" Color="#FF569DE5"/>
<SolidColorBrush x:Key="SliderThumb.Disabled.Background" Color="#FFF0F0F0"/>
<SolidColorBrush x:Key="SliderThumb.Disabled.Border" Color="#FFD9D9D9"/>
<SolidColorBrush x:Key="SliderThumb.Static.Background" Color="#FFF0F0F0"/>
<SolidColorBrush x:Key="SliderThumb.Static.Border" Color="#FFACACAC"/>
<SolidColorBrush x:Key="SliderThumb.Track.Border" Color="#FFD6D6D6"/>
<SolidColorBrush x:Key="SliderThumb.Track.BorderBackground" Color="#FFE7EAEA"/>
<SolidColorBrush x:Key="SliderThumb.Grip.Fill" Color="#FFE6DFD8"/>
<SolidColorBrush x:Key="SliderThumb.Tick.Bottom" Color="#FFD8CCBC"/>
<SolidColorBrush x:Key="SliderThumb.Track.Background" Color="#FFBFA786"/>
<ControlTemplate x:Key="SliderThumbHorizontalTop" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 0,6 C0,6 5.5,0 5.5,0 5.5,0 11,6 11,6 11,6 11,18 11,18 11,18 0,18 0,18 0,18 0,6 0,6 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbHorizontalBottom" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 0,12 C0,12 5.5,18 5.5,18 5.5,18 11,12 11,12 11,12 11,0 11,0 11,0 0,0 0,0 0,0 0,12 0,12 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="RepeatButtonTransparent" TargetType="{x:Type RepeatButton}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Rectangle Fill="{TemplateBinding Background}" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="SliderThumbHorizontalDefault" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 0,0 C0,0 11,0 11,0 11,0 11,18 11,18 11,18 0,18 0,18 0,18 0,0 0,0 z" Fill="{DynamicResource SliderThumb.Grip.Fill}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderHorizontal" TargetType="{x:Type Slider}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TickBar x:Name="TopTick" Fill="{TemplateBinding Foreground}" Height="4" Margin="0,0,0,2" Placement="Top" Grid.Row="0" Visibility="Collapsed"/>
<TickBar x:Name="BottomTick" Fill="{DynamicResource SliderThumb.Tick.Bottom}" Height="4" Margin="0,2,0,0" Placement="Bottom" Grid.Row="2" Visibility="Collapsed"/>
<Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="1" Background="{StaticResource SliderThumb.Track.BorderBackground}" Height="4.0" Margin="5,0" Grid.Row="1" VerticalAlignment="center">
<Canvas Margin="-6,-1" Background="{DynamicResource SliderThumb.Track.Background}">
<Rectangle x:Name="PART_SelectionRange" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="4.0" Visibility="Hidden"/>
</Canvas>
</Border>
<Track x:Name="PART_Track" Grid.Row="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb x:Name="Thumb" Focusable="False" Height="18" OverridesDefaultStyle="True" Template="{StaticResource SliderThumbHorizontalDefault}" VerticalAlignment="Center" Width="11" Foreground="#FFBFA786"/>
</Track.Thumb>
</Track>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="TickPlacement" Value="TopLeft">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbHorizontalTop}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="5,2,5,0"/>
</Trigger>
<Trigger Property="TickPlacement" Value="BottomRight">
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbHorizontalBottom}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="5,0,5,2"/>
</Trigger>
<Trigger Property="TickPlacement" Value="Both">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
</Trigger>
<Trigger Property="IsSelectionRangeEnabled" Value="true">
<Setter Property="Visibility" TargetName="PART_SelectionRange" Value="Visible"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="Foreground" TargetName="Thumb" Value="Blue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbVerticalLeft" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 6,11 C6,11 0,5.5 0,5.5 0,5.5 6,0 6,0 6,0 18,0 18,0 18,0 18,11 18,11 18,11 6,11 6,11 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbVerticalRight" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M 12,11 C12,11 18,5.5 18,5.5 18,5.5 12,0 12,0 12,0 0,0 0,0 0,0 0,11 0,11 0,11 12,11 12,11 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderThumbVerticalDefault" TargetType="{x:Type Thumb}">
<Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
<Path x:Name="grip" Data="M0.5,0.5 L18.5,0.5 18.5,11.5 0.5,11.5z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsDragging" Value="true">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
<Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="SliderVertical" TargetType="{x:Type Slider}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition MinWidth="{TemplateBinding MinWidth}" Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TickBar x:Name="TopTick" Grid.Column="0" Fill="{TemplateBinding Foreground}" Margin="0,0,2,0" Placement="Left" Visibility="Collapsed" Width="4"/>
<TickBar x:Name="BottomTick" Grid.Column="2" Fill="{TemplateBinding Foreground}" Margin="2,0,0,0" Placement="Right" Visibility="Collapsed" Width="4"/>
<Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="1" Background="{StaticResource SliderThumb.Track.BorderBackground}" Grid.Column="1" HorizontalAlignment="center" Margin="0,5" Width="4.0">
<Canvas Margin="-1,-6">
<Rectangle x:Name="PART_SelectionRange" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Visibility="Hidden" Width="4.0"/>
</Canvas>
</Border>
<Track x:Name="PART_Track" Grid.Column="1">
<Track.DecreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource RepeatButtonTransparent}"/>
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb x:Name="Thumb" Focusable="False" Height="11" OverridesDefaultStyle="True" Template="{StaticResource SliderThumbVerticalDefault}" VerticalAlignment="Top" Width="18"/>
</Track.Thumb>
</Track>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="TickPlacement" Value="TopLeft">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbVerticalLeft}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="2,5,0,5"/>
</Trigger>
<Trigger Property="TickPlacement" Value="BottomRight">
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
<Setter Property="Template" TargetName="Thumb" Value="{StaticResource SliderThumbVerticalRight}"/>
<Setter Property="Margin" TargetName="TrackBackground" Value="0,5,2,5"/>
</Trigger>
<Trigger Property="TickPlacement" Value="Both">
<Setter Property="Visibility" TargetName="TopTick" Value="Visible"/>
<Setter Property="Visibility" TargetName="BottomTick" Value="Visible"/>
</Trigger>
<Trigger Property="IsSelectionRangeEnabled" Value="true">
<Setter Property="Visibility" TargetName="PART_SelectionRange" Value="Visible"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="Foreground" TargetName="Thumb" Value="Blue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="AnnotatedSliderStyle" TargetType="{x:Type Slider}">
<Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource SliderThumb.Static.Foreground}"/>
<Setter Property="Template" Value="{StaticResource SliderHorizontal}"/>
<Style.Triggers>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="Template" Value="{StaticResource SliderVertical}"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding LabelRelativeWidth}" MinWidth="{Binding LabelRelativeMinWidth}"/>
<ColumnDefinition Width="{Binding SliderRelativeWidth}" MinWidth="{Binding SliderRelativeMinWidth}"/>
<ColumnDefinition Width="{Binding ValueRelativeWidth}" MinWidth="{Binding ValueRelativeMinWidth}"/>
<ColumnDefinition Width="{Binding SuffixRelativeWidth}" MinWidth="{Binding SuffixRelativeMinWidth}"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding Label}" VerticalContentAlignment="Center"/>
<Slider x:Name="Slider" Grid.Column="1" Value="{Binding Value, Mode=OneWay}" Margin="0,0,5,0"
Minimum="{Binding Minimum}"
Maximum="{Binding Maximum}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
HorizontalContentAlignment="Stretch"
LargeChange="{Binding LargeChange}"
SmallChange="{Binding SmallChange}"
TickFrequency="{Binding TickFrequency}" Style="{DynamicResource AnnotatedSliderStyle}"
ValueChanged="Slider_ValueChanged"/>
<TextBox x:Name="Text" Grid.Column="2" Text="{Binding Value, Mode=TwoWay, StringFormat={}{0:#######,##0.##########}}" VerticalContentAlignment="Center" MinHeight="{Binding ValueRelativeMinHeight}"/>
<Label Grid.Column="3" Content="{Binding Suffix}" VerticalContentAlignment="Center" />
</Grid>
</UserControl>

View file

@ -0,0 +1,148 @@
using System.Windows;
using System.Windows.Controls;
namespace ServerManagerTool.Common.Controls
{
/// <summary>
/// Interaction logic for AnnotatedSlider.xaml
/// </summary>
public partial class AnnotatedSlider : UserControl
{
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(nameof(Label), typeof(string), typeof(AnnotatedSlider));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(float), typeof(AnnotatedSlider), new FrameworkPropertyMetadata(default(float), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty SuffixProperty = DependencyProperty.Register(nameof(Suffix), typeof(string), typeof(AnnotatedSlider));
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(nameof(Minimum), typeof(float), typeof(AnnotatedSlider));
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(nameof(Maximum), typeof(float), typeof(AnnotatedSlider));
public static readonly DependencyProperty LargeChangeProperty = DependencyProperty.Register(nameof(LargeChange), typeof(float), typeof(AnnotatedSlider));
public static readonly DependencyProperty SmallChangeProperty = DependencyProperty.Register(nameof(SmallChange), typeof(float), typeof(AnnotatedSlider));
public static readonly DependencyProperty TickFrequencyProperty = DependencyProperty.Register(nameof(TickFrequency), typeof(float), typeof(AnnotatedSlider));
public static readonly DependencyProperty LabelRelativeWidthProperty = DependencyProperty.Register(nameof(LabelRelativeWidth), typeof(string), typeof(AnnotatedSlider), new PropertyMetadata("4*"));
public static readonly DependencyProperty LabelRelativeMinWidthProperty = DependencyProperty.Register(nameof(LabelRelativeMinWidth), typeof(string), typeof(AnnotatedSlider), new PropertyMetadata("0"));
public static readonly DependencyProperty SliderRelativeWidthProperty = DependencyProperty.Register(nameof(SliderRelativeWidth), typeof(string), typeof(AnnotatedSlider), new PropertyMetadata("8*"));
public static readonly DependencyProperty SliderRelativeMinWidthProperty = DependencyProperty.Register(nameof(SliderRelativeMinWidth), typeof(string), typeof(AnnotatedSlider), new PropertyMetadata("0"));
public static readonly DependencyProperty ValueRelativeWidthProperty = DependencyProperty.Register(nameof(ValueRelativeWidth), typeof(string), typeof(AnnotatedSlider), new PropertyMetadata("2*"));
public static readonly DependencyProperty ValueRelativeMinWidthProperty = DependencyProperty.Register(nameof(ValueRelativeMinWidth), typeof(string), typeof(AnnotatedSlider), new PropertyMetadata("50"));
public static readonly DependencyProperty ValueRelativeMinHeightProperty = DependencyProperty.Register(nameof(ValueRelativeMinHeight), typeof(string), typeof(AnnotatedSlider), new PropertyMetadata("25"));
public static readonly DependencyProperty SuffixRelativeWidthProperty = DependencyProperty.Register(nameof(SuffixRelativeWidth), typeof(string), typeof(AnnotatedSlider), new PropertyMetadata("1*"));
public static readonly DependencyProperty SuffixRelativeMinWidthProperty = DependencyProperty.Register(nameof(SuffixRelativeMinWidth), typeof(string), typeof(AnnotatedSlider), new PropertyMetadata("0"));
public string Label
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public float Value
{
get { return (float)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public string Suffix
{
get { return (string)GetValue(SuffixProperty); }
set { SetValue(SuffixProperty, value); }
}
public float Minimum
{
get { return (float)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public float Maximum
{
get { return (float)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public float LargeChange
{
get { return (float)GetValue(LargeChangeProperty); }
set { SetValue(LargeChangeProperty, value); }
}
public float SmallChange
{
get { return (float)GetValue(SmallChangeProperty); }
set { SetValue(SmallChangeProperty, value); }
}
public float TickFrequency
{
get { return (float)GetValue(TickFrequencyProperty); }
set { SetValue(TickFrequencyProperty, value); }
}
public string LabelRelativeWidth
{
get { return (string)GetValue(LabelRelativeWidthProperty); }
set { SetValue(LabelRelativeWidthProperty, value); }
}
public string LabelRelativeMinWidth
{
get { return (string)GetValue(LabelRelativeMinWidthProperty); }
set { SetValue(LabelRelativeMinWidthProperty, value); }
}
public string SliderRelativeWidth
{
get { return (string)GetValue(SliderRelativeWidthProperty); }
set { SetValue(SliderRelativeWidthProperty, value); }
}
public string SliderRelativeMinWidth
{
get { return (string)GetValue(SliderRelativeMinWidthProperty); }
set { SetValue(SliderRelativeMinWidthProperty, value); }
}
public string ValueRelativeWidth
{
get { return (string)GetValue(ValueRelativeWidthProperty); }
set { SetValue(ValueRelativeWidthProperty, value); }
}
public string ValueRelativeMinWidth
{
get { return (string)GetValue(ValueRelativeMinWidthProperty); }
set { SetValue(ValueRelativeMinWidthProperty, value); }
}
public string ValueRelativeMinHeight
{
get { return (string)GetValue(ValueRelativeMinHeightProperty); }
set { SetValue(ValueRelativeMinHeightProperty, value); }
}
public string SuffixRelativeWidth
{
get { return (string)GetValue(SuffixRelativeWidthProperty); }
set { SetValue(SuffixRelativeWidthProperty, value); }
}
public string SuffixRelativeMinWidth
{
get { return (string)GetValue(SuffixRelativeMinWidthProperty); }
set { SetValue(SuffixRelativeMinWidthProperty, value); }
}
public AnnotatedSlider()
{
InitializeComponent();
(this.Content as FrameworkElement).DataContext = this;
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if(Slider.IsFocused)
{
unchecked
{
Value = (float)e.NewValue;
}
}
}
}
}

View file

@ -0,0 +1,53 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
namespace ServerManagerTool.Common.Controls
{
public class DropDownButton : ToggleButton
{
public DropDownButton()
{
// Bind the ToogleButton.IsChecked property to the drop-down's IsOpen property
Binding binding = new Binding("Menu.IsOpen")
{
Source = this
};
this.SetBinding(IsCheckedProperty, binding);
DataContextChanged += (sender, args) =>
{
if (Menu != null)
{
Menu.DataContext = DataContext;
}
};
}
public static readonly DependencyProperty MenuProperty = DependencyProperty.Register("Menu", typeof(ContextMenu), typeof(DropDownButton), new UIPropertyMetadata(null, OnMenuChanged));
public ContextMenu Menu
{
get { return (ContextMenu)GetValue(MenuProperty); }
set { SetValue(MenuProperty, value); }
}
private static void OnMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var dropDownButton = (DropDownButton)d;
var contextMenu = (ContextMenu)e.NewValue;
contextMenu.DataContext = dropDownButton.DataContext;
}
protected override void OnClick()
{
if (Menu != null)
{
// If there is a drop-down assigned to this button, then position and display it
Menu.PlacementTarget = this;
Menu.Placement = PlacementMode.Bottom;
Menu.IsOpen = true;
}
}
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Windows.Data;
using System.Globalization;
using System.Linq;
namespace ServerManagerTool.Common.Converters
{
public class AllTrueMultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return !values.Any(v => !(v is bool) || !(bool)v);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException("AllTrueConverter is a OneWay converter.");
}
}
}

View file

@ -0,0 +1,30 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class CommaDelimitedStringCountConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value == null)
{
return "0";
}
var strValue = value as string;
if(string.IsNullOrWhiteSpace(strValue))
{
return "0";
}
return strValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Length.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException("CommaDelimitedStringCountConverter can only be used OneWay.");
}
}
}

View file

@ -0,0 +1,56 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
namespace ServerManagerTool.Common.Converters
{
public class DoubleRangeValueConverter : MarkupExtension, IValueConverter
{
protected double MinValue { get; set; }
protected double MaxValue { get; set; }
public DoubleRangeValueConverter()
{
MinValue = int.MinValue;
MaxValue = int.MaxValue;
}
public DoubleRangeValueConverter(double minValue)
{
MinValue = minValue;
MaxValue = int.MaxValue;
}
public DoubleRangeValueConverter(double minValue, double maxValue)
{
MinValue = minValue;
MaxValue = maxValue;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double scaledValue = System.Convert.ToDouble(value);
var sliderValue = scaledValue;
sliderValue = Math.Max(MinValue, sliderValue);
sliderValue = Math.Min(MaxValue, sliderValue);
return sliderValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var sliderValue = System.Convert.ToDouble(value);
sliderValue = Math.Max(MinValue, sliderValue);
sliderValue = Math.Min(MaxValue, sliderValue);
var scaledValue = sliderValue;
return scaledValue;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class EnumConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || parameter == null)
return false;
string checkValue = value.ToString();
string targetValue = parameter.ToString();
return checkValue.Equals(targetValue, StringComparison.InvariantCultureIgnoreCase);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || parameter == null)
return null;
bool useValue = (bool)value;
string targetValue = parameter.ToString();
if (useValue)
return Enum.Parse(targetType, targetValue);
return null;
}
}
}

View file

@ -0,0 +1,27 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class EnumFlagsConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (value == null || parameter == null)
return false;
var flagsValue = (int)value;
var targetFlagValue = (int)Enum.Parse(value.GetType(), parameter.ToString());
return (flagsValue & targetFlagValue) == targetFlagValue;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotSupportedException("Cannot convert flags value back");
}
}
}

View file

@ -0,0 +1,25 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class FlagsEnumToBooleanConverter : IValueConverter
{
private int targetValue;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var mask = System.Convert.ToInt32(parameter);
this.targetValue = System.Convert.ToInt32(value);
return ((mask & this.targetValue) != 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
this.targetValue ^= System.Convert.ToInt32(parameter);
return Enum.Parse(targetType, this.targetValue.ToString());
}
}
}

View file

@ -0,0 +1,42 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class FloatToPercentageConverter : IValueConverter
{
public const int MIN_VALUE = 0;
public const int MAX_VALUE = 100;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var scaledValue = System.Convert.ToSingle(value);
var sliderValue = scaledValue * 100;
sliderValue = Math.Max(MIN_VALUE, sliderValue);
//sliderValue = Math.Min(MAX_VALUE, sliderValue);
return $"{sliderValue}%";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType() == typeof(string))
{
var stringValue = (string)value;
if (stringValue.EndsWith("%"))
{
stringValue = stringValue.Replace("%", "");
value = stringValue;
}
}
var sliderValue = System.Convert.ToSingle(value);
sliderValue = Math.Max(MIN_VALUE, sliderValue);
//sliderValue = Math.Min(MAX_VALUE, sliderValue);
var scaledValue = sliderValue / 100;
return scaledValue;
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
namespace ServerManagerTool.Common.Converters
{
public class GreaterThanIntValueConverter : MarkupExtension, IValueConverter
{
protected int Operand { get; set; }
public GreaterThanIntValueConverter(int operand)
{
Operand = operand;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return System.Convert.ToInt32(value) > Operand;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
}

View file

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class HasStringValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value == null)
{
return false;
}
var strValue = value as string;
if(String.IsNullOrWhiteSpace(strValue))
{
return false;
}
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
}
}
}

View file

@ -0,0 +1,26 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class InstalledVersionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var version = value as string;
if (string.IsNullOrWhiteSpace(version))
return "0.0";
if (version.Equals("0.0"))
return "0.0";
return version;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,56 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
namespace ServerManagerTool.Common.Converters
{
public class IntRangeValueConverter : MarkupExtension, IValueConverter
{
protected int MinValue { get; set; }
protected int MaxValue { get; set; }
public IntRangeValueConverter()
{
MinValue = int.MinValue;
MaxValue = int.MaxValue;
}
public IntRangeValueConverter(int minValue)
{
MinValue = minValue;
MaxValue = int.MaxValue;
}
public IntRangeValueConverter(int minValue, int maxValue)
{
MinValue = minValue;
MaxValue = maxValue;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double scaledValue = System.Convert.ToInt32(value);
var sliderValue = scaledValue;
sliderValue = Math.Max(MinValue, sliderValue);
sliderValue = Math.Min(MaxValue, sliderValue);
return sliderValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var sliderValue = System.Convert.ToInt32(value);
sliderValue = Math.Max(MinValue, sliderValue);
sliderValue = Math.Min(MaxValue, sliderValue);
var scaledValue = sliderValue;
return scaledValue;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class InvertBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class InvertBooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool flag = false;
if (value is bool)
{
flag = (bool)value;
}
else if (value is bool?)
{
bool? nullable = (bool?)value;
flag = nullable.HasValue && nullable.Value;
}
return flag ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Visibility)
return (Visibility)value == Visibility.Collapsed;
return false;
}
}
}

View file

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class IsNullOrWhiteSpaceValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value == null)
{
return true;
}
var strValue = value as string;
if(String.IsNullOrWhiteSpace(strValue))
{
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
}
}
}

View file

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class IsNullValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
}
}
}

View file

@ -0,0 +1,39 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class MinutesToTimeValueConverter : IValueConverter
{
public const int MAX_VALUE_HOURS = 24 * 365;
public const int MAX_VALUE_MINUTES = 59;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Value is seconds since midnight.
var totalMinutes = (int)value;
var hours = Math.Min(Math.Max(totalMinutes / 60, 0), MAX_VALUE_HOURS);
var minutes = Math.Min(Math.Max(totalMinutes % 60, 0), MAX_VALUE_MINUTES);
return String.Format("{0:00}:{1:00}", hours, minutes);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var strTime = (string)value;
var split = strTime.Split(':');
if(split.Length != 2)
{
return 0;
}
int hours;
Int32.TryParse(split[0], out hours);
int minutes;
Int32.TryParse(split[1], out minutes);
return hours * 60 + minutes;
}
}
}

View file

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class NullValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value ?? parameter;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
}
}
}

View file

@ -0,0 +1,34 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class NullableHasValueConverter : IValueConverter
{
public object convertValue = null;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
convertValue = value;
return value != null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool && (bool)value)
{
if (targetType == typeof(bool) || targetType == typeof(bool?))
return default(bool);
else if (targetType == typeof(int) || targetType == typeof(int?))
return default(int);
else if (targetType == typeof(float) || targetType == typeof(float?))
return default(float);
return string.Empty;
}
return null;
}
}
}

View file

@ -0,0 +1,49 @@
using ServerManagerTool.Common.Utils;
using System;
using System.Globalization;
using System.Numerics;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class ProcessorAffinityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!BigInteger.TryParse(value.ToString(), out BigInteger affinity))
return "Invalid";
if (!ProcessUtils.IsProcessorAffinityValid(affinity))
return "Invalid";
if (affinity == BigInteger.Zero)
return "All";
var result = string.Empty;
var delimiter = string.Empty;
var index = 0;
while (true)
{
var cpuValue = (BigInteger)Math.Pow(2, index);
if (cpuValue > affinity)
break;
if ((affinity & cpuValue) == cpuValue)
{
result = $"{result}{delimiter}{index}";
delimiter = ", ";
}
index++;
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException("ProcessorAffinityConverter can only be used OneWay.");
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class SecondsToHoursConverter : IValueConverter
{
public const int MIN_VALUE = 0;
public const int MAX_VALUE = int.MaxValue;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double scaledValue = System.Convert.ToInt32(value);
var sliderValue = (int)TimeSpan.FromSeconds(scaledValue).TotalHours;
sliderValue = Math.Max(MIN_VALUE, sliderValue);
sliderValue = Math.Min(MAX_VALUE, sliderValue);
return sliderValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var sliderValue = System.Convert.ToInt32(value);
sliderValue = Math.Max(MIN_VALUE, sliderValue);
sliderValue = Math.Min(MAX_VALUE, sliderValue);
var scaledValue = (int)TimeSpan.FromHours(sliderValue).TotalSeconds;
return scaledValue;
}
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class SecondsToMinutesConverter : IValueConverter
{
public const int MIN_VALUE = 0;
public const int MAX_VALUE = int.MaxValue;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double scaledValue = System.Convert.ToInt32(value);
var sliderValue = (int)TimeSpan.FromSeconds(scaledValue).TotalMinutes;
sliderValue = Math.Max(MIN_VALUE, sliderValue);
sliderValue = Math.Min(MAX_VALUE, sliderValue);
return sliderValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var sliderValue = System.Convert.ToInt32(value);
sliderValue = Math.Max(MIN_VALUE, sliderValue);
sliderValue = Math.Min(MAX_VALUE, sliderValue);
var scaledValue = (int)TimeSpan.FromMinutes(sliderValue).TotalSeconds;
return scaledValue;
}
}
}

View file

@ -0,0 +1,35 @@
using System;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class SecondsToTimeValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Value is seconds since midnight.
var seconds = (int)value;
var hours = Math.Min(Math.Max(seconds / 3600, 0), 23);
var minutes = Math.Min(Math.Max((seconds % 3600) / 60, 0), 59);
return String.Format("{0:00}:{1:00}", hours, minutes);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var strTime = (string)value;
var split = strTime.Split(':');
if(split.Length != 2)
{
return 0;
}
int hours;
Int32.TryParse(split[0], out hours);
int minutes;
Int32.TryParse(split[1], out minutes);
return hours * 3600 + minutes * 60;
}
}
}

View file

@ -0,0 +1,21 @@
using ServerManagerTool.Common.Utils;
using System;
using System.Globalization;
using System.Windows.Data;
namespace ServerManagerTool.Common.Converters
{
public class UnixTimeToDateTimeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int unixTimestamp = (int)value;
return DateTimeUtils.UnixTimeStampToDateTime(unixTimestamp).ToString(culture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return 0;
}
}
}

View file

@ -0,0 +1,8 @@
namespace ServerManagerTool.Common.Enums
{
public enum ConsoleStatus
{
Disconnected,
Connected,
};
}

View file

@ -0,0 +1,12 @@
using System.ComponentModel;
namespace ServerManagerTool.Common.Enums
{
[DefaultValue(False)]
public enum QuotedStringType
{
False,
True,
Remove,
}
}

View file

@ -0,0 +1,45 @@
using System.ComponentModel;
namespace ServerManagerTool.Common.Extensions
{
public static class CollectionViewExtensions
{
public static void ToggleSorting(this ICollectionView view, string property, ListSortDirection defaultDirection = ListSortDirection.Ascending)
{
for (int i = 0; i < view.SortDescriptions.Count; i++)
{
var sortDescription = view.SortDescriptions[i];
if (sortDescription.PropertyName == property)
{
view.SortDescriptions.RemoveAt(i);
return;
}
}
view.SortDescriptions.Add(new SortDescription() { PropertyName = property, Direction = defaultDirection });
}
public static void ToggleSortDirection(this ICollectionView view, string property, ListSortDirection defaultDirection = ListSortDirection.Ascending)
{
for (int i = 0; i < view.SortDescriptions.Count; i++)
{
var sortDescription = view.SortDescriptions[i];
if (sortDescription.PropertyName == property)
{
if (sortDescription.Direction == ListSortDirection.Ascending)
{
view.SortDescriptions[i] = new SortDescription() { PropertyName = property, Direction = ListSortDirection.Descending };
}
else
{
view.SortDescriptions[i] = new SortDescription() { PropertyName = property, Direction = ListSortDirection.Ascending };
}
return;
}
}
view.SortDescriptions.Add(new SortDescription() { PropertyName = property, Direction = defaultDirection });
}
}
}

View file

@ -0,0 +1,47 @@
using System;
using System.Linq;
using System.Windows.Markup;
using System.Windows.Media.Imaging;
namespace ServerManagerTool.Common
{
/// <summary>
/// Simple extension for icon, to let you choose icon with specific size.
/// Usage sample:
/// Image Stretch="None" Source="{common:Icon /Controls;component/icons/custom.ico, 16}"
/// Or:
/// Image Source="{common:Icon Source={Binding IconResource}, Size=16}"
/// </summary>
public class IconExtension : MarkupExtension
{
private string _path;
public string Path
{
get
{
return _path;
}
set
{
// Have to make full pack URI from short form, so System.Uri recognizes it.
_path = $"pack://application:,,,{value}";
}
}
public int Size { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var decoder = BitmapDecoder.Create(new Uri(Path), BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand);
var result = decoder.Frames.SingleOrDefault(f => f.Width == Size);
if (result == default(BitmapFrame))
{
result = decoder.Frames.OrderBy(f => f.Width).First();
}
return result;
}
}
}

View file

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace ServerManagerTool.Common.Interfaces
{
public interface IAsyncDisposable
{
Task DisposeAsync();
}
}

View file

@ -0,0 +1,11 @@
namespace ServerManagerTool.Common.Interfaces
{
public interface IIniSectionCollection
{
IIniValuesCollection[] Sections { get; }
void Add(string sectionName, string[] values);
void Update();
}
}

View file

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace ServerManagerTool.Common.Interfaces
{
public interface IIniValuesCollection
{
string IniCollectionKey { get; }
bool IsArray { get; }
bool IsEnabled { get; set; }
void FromIniValues(IEnumerable<string> values);
IEnumerable<string> ToIniValues();
}
}

View file

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace ServerManagerTool.Common.Interfaces
{
public interface IIniValuesList
{
IEnumerable<string> ToIniValues(object excludeIfValue);
}
}

View file

@ -0,0 +1,11 @@
namespace ServerManagerTool.Common.Interfaces
{
public interface INullableValue
{
bool HasValue { get; }
INullableValue Clone();
void SetValue(object value);
}
}

View file

@ -0,0 +1,107 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Model;
using System;
namespace ServerManagerTool.Common.JsonConverters
{
public class NullableValueConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
if (objectType == typeof(NullableValue<int>))
{
return true;
}
else if (objectType == typeof(NullableValue<float>))
{
return true;
}
return false;
}
public override bool CanRead => true;
public override bool CanWrite => true;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
// Create target object based on objectType
var target = Activator.CreateInstance(objectType) as INullableValue;
target?.SetValue(existingValue);
return target;
}
if (reader.TokenType == JsonToken.StartObject)
{
// Load JObject from stream
var jObject = JObject.Load(reader);
// Create target object based on objectType
var target = Activator.CreateInstance(objectType);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
if (reader.TokenType == JsonToken.Integer)
{
var jValue = JToken.Load(reader) as JValue;
// Create target object based on objectType
var target = Activator.CreateInstance(objectType) as NullableValue<int>;
target?.SetValue(existingValue);
if (target != null && jValue != null && jValue.Value != null && int.TryParse(jValue.Value.ToString(), out int result))
{
// Populate the object properties
target.SetValue(result);
return target;
}
}
if (reader.TokenType == JsonToken.Float)
{
var jValue = JToken.Load(reader) as JValue;
// Create target object based on objectType
var target = Activator.CreateInstance(objectType) as NullableValue<int>;
target?.SetValue(existingValue);
if (target != null && jValue != null && jValue.Value != null && float.TryParse(jValue.Value.ToString(), out float result))
{
// Populate the object properties
target.SetValue(result);
return target;
}
}
return Activator.CreateInstance(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value != null && value is NullableValue<int> && ((NullableValue<int>)value).HasValue)
{
serializer.Serialize(writer, ((NullableValue<int>)value).Value);
}
else if (value != null && value is NullableValue<float> && ((NullableValue<float>)value).HasValue)
{
serializer.Serialize(writer, ((NullableValue<float>)value).Value);
}
else
{
serializer.Serialize(writer, null);
}
}
}
}

View file

@ -0,0 +1,53 @@
using ServerManagerTool.Common.Interfaces;
using System;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
namespace ServerManagerTool.Common.Lib
{
/// <summary>
/// This class ensures the following:
/// 1. All work items run in the order posted.
/// 2. Work items run on a background thread.
/// 3. Work items do not overlap
/// 4. If requested, the completion status of a work item is returned via a task.
/// </summary>
public class ActionQueue : IAsyncDisposable
{
public ActionBlock<Action> workQueue;
public ActionQueue(TaskScheduler scheduler = null)
{
this.workQueue = new ActionBlock<Action>(a => a.Invoke(), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1, TaskScheduler = scheduler ?? TaskScheduler.Default });
}
public Task<T> PostAction<T>(Func<T> action)
{
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
this.workQueue.Post(() =>
{
try
{
var result = action.Invoke();
Task.Run(() => tcs.TrySetResult(result));
}
catch(Exception ex)
{
Task.Run(() => tcs.TrySetException(ex));
}
});
return tcs.Task;
}
public Task PostAction(Action action)
{
return PostAction(() => { action.Invoke(); return true; });
}
public async Task DisposeAsync()
{
await PostAction(() => this.workQueue.Complete());
}
}
}

View file

@ -0,0 +1,21 @@
using System.Windows;
namespace ServerManagerTool.Common.Lib
{
public class BindingProxy : Freezable
{
public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
}
}

View file

@ -0,0 +1,32 @@
using System.Windows;
using System.Windows.Controls;
namespace ServerManagerTool.Common.Lib
{
public static class BrowserBehavior
{
public static readonly DependencyProperty HtmlProperty = DependencyProperty.RegisterAttached("Html", typeof(string), typeof(BrowserBehavior), new FrameworkPropertyMetadata(OnHtmlChanged));
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static string GetHtml(WebBrowser d)
{
return (string)d.GetValue(HtmlProperty);
}
public static void SetHtml(WebBrowser d, string value)
{
d.SetValue(HtmlProperty, value);
}
static void OnHtmlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null)
return;
if (d is WebBrowser wb)
{
wb.NavigateToString(e.NewValue as string);
}
}
}
}

View file

@ -0,0 +1,15 @@
using System;
namespace ServerManagerTool.Common.Lib
{
public class CommandListener : IDisposable
{
public Action<ConsoleCommand> Callback { get; set; }
public Action<CommandListener> DisposeAction { get; set; }
public void Dispose()
{
DisposeAction(this);
}
}
}

View file

@ -0,0 +1,18 @@
using ServerManagerTool.Common.Enums;
using System.Collections.Generic;
namespace ServerManagerTool.Common.Lib
{
public class ConsoleCommand
{
public ConsoleStatus status;
public string rawCommand;
public string command;
public string args;
public bool suppressCommand;
public bool suppressOutput;
public IEnumerable<string> lines = new string[0];
}
}

View file

@ -0,0 +1,179 @@
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace ServerManagerTool.Common.Lib
{
public static class SortBehavior
{
public static readonly DependencyProperty CanUserSortColumnsProperty = DependencyProperty.RegisterAttached("CanUserSortColumns", typeof(bool), typeof(SortBehavior), new FrameworkPropertyMetadata(OnCanUserSortColumnsChanged));
public static readonly DependencyProperty CanUseSortProperty = DependencyProperty.RegisterAttached("CanUseSort", typeof(bool), typeof(SortBehavior), new FrameworkPropertyMetadata(true));
public static readonly DependencyProperty SortDirectionProperty = DependencyProperty.RegisterAttached("SortDirection", typeof(ListSortDirection?), typeof(SortBehavior));
public static readonly DependencyProperty SortExpressionProperty = DependencyProperty.RegisterAttached("SortExpression", typeof(string), typeof(SortBehavior));
public static readonly DependencyProperty IsDefaultSortProperty = DependencyProperty.RegisterAttached("IsDefaultSort", typeof(bool), typeof(SortBehavior), new FrameworkPropertyMetadata(false));
[AttachedPropertyBrowsableForType(typeof(ListView))]
public static bool GetCanUserSortColumns(ListView element)
{
return (bool)(element?.GetValue(CanUserSortColumnsProperty) ?? false);
}
[AttachedPropertyBrowsableForType(typeof(ListView))]
public static void SetCanUserSortColumns(ListView element, bool value)
{
element?.SetValue(CanUserSortColumnsProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static bool GetCanUseSort(GridViewColumn element)
{
return (bool)(element?.GetValue(CanUseSortProperty) ?? false);
}
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static void SetCanUseSort(GridViewColumn element, bool value)
{
element?.SetValue(CanUseSortProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static ListSortDirection? GetSortDirection(GridViewColumn element)
{
return (ListSortDirection?)element.GetValue(SortDirectionProperty);
}
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static void SetSortDirection(GridViewColumn element, ListSortDirection? value)
{
element?.SetValue(SortDirectionProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static string GetSortExpression(GridViewColumn element)
{
return (string)element?.GetValue(SortExpressionProperty);
}
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static void SetSortExpression(GridViewColumn element, string value)
{
element?.SetValue(SortExpressionProperty, value);
}
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static bool GetIsDefaultSort(GridViewColumn element)
{
return (bool)(element?.GetValue(IsDefaultSortProperty) ?? false);
}
[AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
public static void SetIsDefaultSort(GridViewColumn element, bool value)
{
element?.SetValue(IsDefaultSortProperty, value);
}
private static void OnCanUserSortColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var listView = (ListView)d;
if ((bool)e.NewValue)
{
listView.AddHandler(GridViewColumnHeader.ClickEvent, (RoutedEventHandler)OnColumnHeaderClick);
if (listView.IsLoaded)
{
DoInitialSort(listView);
}
else
{
listView.Loaded += OnLoaded;
}
}
else
{
listView.RemoveHandler(GridViewColumnHeader.ClickEvent, (RoutedEventHandler)OnColumnHeaderClick);
}
}
private static void OnLoaded(object sender, RoutedEventArgs e)
{
var listView = (ListView)e.Source;
listView.Loaded -= OnLoaded;
DoInitialSort(listView);
}
private static void DoInitialSort(ListView listView)
{
var gridView = (GridView)listView.View;
var column = gridView.Columns.FirstOrDefault(c => GetIsDefaultSort(c));
if (column != null)
{
DoSort(listView, column);
}
}
private static void OnColumnHeaderClick(object sender, RoutedEventArgs e)
{
var columnHeader = e.OriginalSource as GridViewColumnHeader;
if (columnHeader != null && GetCanUseSort(columnHeader.Column))
{
DoSort((ListView)e.Source, columnHeader.Column);
}
}
private static void DoSort(ListView listView, GridViewColumn newColumn)
{
var gridView = (GridView)listView.View;
var sortDescriptions = listView.Items.SortDescriptions;
var newDirection = ListSortDirection.Ascending;
var propertyPath = ResolveSortExpression(newColumn);
if (propertyPath != null)
{
if (sortDescriptions.Count > 0)
{
if (sortDescriptions[0].PropertyName == propertyPath)
{
newDirection = GetSortDirection(newColumn) == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
}
else
{
foreach (var column in gridView.Columns.Where(c => GetSortDirection(c) != null))
{
SetSortDirection(column, null);
}
}
sortDescriptions.Clear();
}
sortDescriptions.Add(new SortDescription(propertyPath, newDirection));
SetSortDirection(newColumn, newDirection);
// check if there is a default sort column
var defaultColumn = gridView.Columns.FirstOrDefault(c => GetIsDefaultSort(c));
if (defaultColumn != null)
{
var defaultPropertyPath = ResolveSortExpression(defaultColumn);
if (defaultPropertyPath != null && !defaultPropertyPath.Equals(propertyPath))
{
sortDescriptions.Add(new SortDescription(defaultPropertyPath, ListSortDirection.Ascending));
}
}
}
}
private static string ResolveSortExpression(GridViewColumn column)
{
var propertyPath = GetSortExpression(column);
if (propertyPath == null)
{
var binding = column.DisplayMemberBinding as Binding;
return binding != null ? binding.Path.Path : null;
}
return propertyPath;
}
}
}

View file

@ -0,0 +1,31 @@
using System.Net;
namespace ServerManagerTool.Common.Lib
{
public class NetworkAdapterEntry
{
public NetworkAdapterEntry(IPAddress address, string description)
{
this.IPAddress = address.ToString();
this.Description = description;
}
public NetworkAdapterEntry(string address, string description)
{
this.IPAddress = address;
this.Description = description;
}
public string IPAddress
{
get;
set;
}
public string Description
{
get;
set;
}
}
}

View file

@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
namespace ServerManagerTool.Common.Lib
{
public sealed class PropertyChangeNotifier : DependencyObject, IDisposable
{
#region Member Variables
private WeakReference _propertySource;
#endregion // Member Variables
#region Constructor
public PropertyChangeNotifier(DependencyObject propertySource, string path)
: this(propertySource, new PropertyPath(path))
{
}
public PropertyChangeNotifier(DependencyObject propertySource, DependencyProperty property)
: this(propertySource, new PropertyPath(property))
{
}
public PropertyChangeNotifier(DependencyObject propertySource, DependencyProperty property, DependencyPropertyChangedEventHandler handler)
: this(propertySource, property)
{
this.ValueChanged += handler;
}
public PropertyChangeNotifier(DependencyObject propertySource, PropertyPath property)
{
if (null == propertySource)
throw new ArgumentNullException("propertySource");
if (null == property)
throw new ArgumentNullException("property");
this._propertySource = new WeakReference(propertySource);
Binding binding = new Binding();
binding.Path = property;
binding.Mode = BindingMode.OneWay;
binding.Source = propertySource;
BindingOperations.SetBinding(this, ValueProperty, binding);
}
public static IEnumerable<PropertyChangeNotifier> GetNotifiers(DependencyObject propertySource, IEnumerable<DependencyProperty> properties, DependencyPropertyChangedEventHandler handler)
{
foreach(var property in properties)
{
var notifier = new PropertyChangeNotifier(propertySource, property, handler);
yield return notifier;
}
}
#endregion // Constructor
#region PropertySource
public DependencyObject PropertySource
{
get
{
try
{
// note, it is possible that accessing the target property
// will result in an exception so ive wrapped this check
// in a try catch
return this._propertySource.IsAlive
? this._propertySource.Target as DependencyObject
: null;
}
catch
{
return null;
}
}
}
#endregion // PropertySource
#region Value
/// <summary>
/// Identifies the <see cref=”Value”/> dependency property
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value),
typeof(object), typeof(PropertyChangeNotifier), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnPropertyChanged)));
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PropertyChangeNotifier notifier = (PropertyChangeNotifier)d;
if (null != notifier.ValueChanged)
{
notifier.ValueChanged(notifier.PropertySource, e);
}
}
/// <summary>
/// Returns/sets the value of the property
/// </summary>
/// <seealso cref=”ValueProperty”/>
[Description("Returns/sets the value of the property")]
[Category("Behavior")]
[Bindable(true)]
public object Value
{
get
{
return (object)this.GetValue(PropertyChangeNotifier.ValueProperty);
}
set
{
this.SetValue(PropertyChangeNotifier.ValueProperty, value);
}
}
#endregion //Value
#region Events
public event DependencyPropertyChangedEventHandler ValueChanged;
#endregion // Events
#region IDisposable Members
public void Dispose()
{
BindingOperations.ClearBinding(this, ValueProperty);
}
#endregion
}
}

View file

@ -0,0 +1,84 @@
using System;
using System.Windows.Input;
namespace ServerManagerTool.Common.Lib
{
public class RelayCommand<T> : ICommand
{
#region Fields
readonly Action<T> _execute = null;
readonly Predicate<T> _canExecute = null;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
/// </summary>
/// <param name="execute">Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.</param>
/// <remarks><seealso cref="CanExecute"/> will always return true.</remarks>
public RelayCommand(Action<T> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
///<summary>
///Defines the method that determines whether the command can execute in its current state.
///</summary>
///<param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
///<returns>
///true if this command can be executed; otherwise, false.
///</returns>
public bool CanExecute(object parameter)
{
try
{
return _canExecute == null ? true : _canExecute((T)parameter);
}
catch (Exception)
{
return false;
}
}
///<summary>
///Occurs when changes occur that affect whether or not the command should execute.
///</summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
///<summary>
///Defines the method to be called when the command is invoked.
///</summary>
///<param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <see langword="null" />.</param>
public void Execute(object parameter)
{
_execute((T)parameter);
}
#endregion
}
}

View file

@ -0,0 +1,24 @@
using ServerManagerTool.Common.Utils;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Threading;
using System.Threading.Tasks;
namespace ServerManagerTool.Common.Lib
{
public static class ServerUpdater
{
public static Task<bool> UpgradeServerAsync(string steamCmdFile, string steamCmdArgs, string workingDirectory, string username, SecureString password, string serverInstallDirectory, DataReceivedEventHandler outputHandler, CancellationToken cancellationToken, ProcessWindowStyle windowStyle = ProcessWindowStyle.Normal)
{
Directory.CreateDirectory(serverInstallDirectory);
return ProcessUtils.RunProcessAsync(steamCmdFile, steamCmdArgs, string.Empty, workingDirectory, username, password, outputHandler, cancellationToken, windowStyle);
}
public static Task<bool> UpgradeModsAsync(string steamCmdFile, string steamCmdArgs, string workingDirectory, string username, SecureString password, DataReceivedEventHandler outputHandler, CancellationToken cancellationToken, ProcessWindowStyle windowStyle = ProcessWindowStyle.Normal)
{
return ProcessUtils.RunProcessAsync(steamCmdFile, steamCmdArgs, string.Empty, workingDirectory, username, password, outputHandler, cancellationToken, windowStyle);
}
}
}

View file

@ -0,0 +1,196 @@
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace ServerManagerTool.Common.Lib
{
public delegate void ProgressDelegate(int progress, string message, bool newLine = true);
public class SteamCmdUpdater
{
public const string OUTPUT_PREFIX = "[UPDATER]";
public struct Update
{
public Update(string statusKey, float completionPercent)
{
this.StatusKey = statusKey;
this.CompletionPercent = completionPercent;
this.Cancelled = false;
this.FailureText = null;
}
public Update SetFailed(string failureText)
{
this.FailureText = failureText;
return this;
}
public static Update AsCompleted(string statusKey)
{
return new Update { StatusKey = statusKey, CompletionPercent = 100, Cancelled = false };
}
public static Update AsCancelled(string statusKey)
{
return new Update { StatusKey = statusKey, CompletionPercent = 100, Cancelled = true };
}
public string StatusKey;
public float CompletionPercent;
public bool Cancelled;
public string FailureText;
}
enum Status
{
CleaningSteamCmd,
DownloadingSteamCmd,
UnzippingSteamCmd,
RunningSteamCmd,
InstallSteamCmdComplete,
Complete,
Cancelled
}
Dictionary<Status, Update> statuses = new Dictionary<Status, Update>()
{
{ Status.CleaningSteamCmd, new Update("AutoUpdater_Status_CleaningSteamCmd", 0) },
{ Status.DownloadingSteamCmd, new Update("AutoUpdater_Status_DownloadingSteamCmd", 10) },
{ Status.UnzippingSteamCmd, new Update("AutoUpdater_Status_UnzippingSteamCmd", 30) },
{ Status.RunningSteamCmd, new Update("AutoUpdater_Status_RunningSteamCmd", 50) },
{ Status.InstallSteamCmdComplete, new Update("AutoUpdater_Status_InstallSteamCmdComplete", 80) },
{ Status.Complete, Update.AsCompleted("AutoUpdater_Status_Complete") },
{ Status.Cancelled, Update.AsCancelled("AutoUpdater_Status_Cancelled") }
};
public static string GetSteamCmdFile(string dataPath) => IOUtils.NormalizePath(Path.Combine(dataPath, CommonConfig.Default.SteamCmdRelativePath, CommonConfig.Default.SteamCmdExeFile));
public async Task ReinstallSteamCmdAsync(string dataPath, IProgress<Update> reporter, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(dataPath))
return;
try
{
reporter?.Report(statuses[Status.CleaningSteamCmd]);
string steamCmdDirectory = Path.Combine(dataPath, CommonConfig.Default.SteamCmdRelativePath);
if (Directory.Exists(steamCmdDirectory))
{
Directory.Delete(steamCmdDirectory, true);
}
await Task.Delay(5000);
await InstallSteamCmdAsync(dataPath, reporter, cancellationToken);
reporter?.Report(statuses[Status.InstallSteamCmdComplete]);
reporter?.Report(statuses[Status.Complete]);
}
catch (TaskCanceledException)
{
reporter?.Report(statuses[Status.Cancelled]);
}
catch (Exception ex)
{
reporter?.Report(statuses[Status.Complete].SetFailed(ex.ToString()));
}
}
private async Task InstallSteamCmdAsync(string dataPath, IProgress<Update> reporter, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(dataPath))
return;
string steamCmdDirectory = Path.Combine(dataPath, CommonConfig.Default.SteamCmdRelativePath);
if (!Directory.Exists(steamCmdDirectory))
{
Directory.CreateDirectory(steamCmdDirectory);
}
reporter?.Report(statuses[Status.DownloadingSteamCmd]);
// Get SteamCmd.exe if necessary
string steamCmdPath = Path.Combine(steamCmdDirectory, CommonConfig.Default.SteamCmdExeFile);
if (!File.Exists(steamCmdPath))
{
// download the SteamCMD zip file
var steamZipPath = Path.Combine(steamCmdDirectory, CommonConfig.Default.SteamCmdZipFile);
using (var webClient = new WebClient())
{
using (var cancelRegistration = cancellationToken.Register(webClient.CancelAsync))
{
await webClient.DownloadFileTaskAsync(CommonConfig.Default.SteamCmdUrl, steamZipPath);
}
}
// Unzip the downloaded file
reporter?.Report(statuses[Status.UnzippingSteamCmd]);
ZipFile.ExtractToDirectory(steamZipPath, steamCmdDirectory);
File.Delete(steamZipPath);
// Run the SteamCmd updater
reporter?.Report(statuses[Status.RunningSteamCmd]);
var arguments = SteamUtils.BuildSteamCmdArguments(false, CommonConfig.Default.SteamCmdInstallArgs);
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = steamCmdPath,
Arguments = arguments,
UseShellExecute = false,
};
var process = Process.Start(startInfo);
process.EnableRaisingEvents = true;
var ts = new TaskCompletionSource<bool>();
using (var cancelRegistration = cancellationToken.Register(() =>
{
try
{
process.Kill();
}
finally
{
ts.TrySetCanceled();
}
}))
{
process.Exited += (s, e) =>
{
ts.TrySetResult(process.ExitCode == 0);
};
await ts.Task;
}
}
return;
}
public async void UpdateSteamCmdAsync(string dataPath, IProgress<Update> reporter, CancellationToken cancellationToken)
{
try
{
await InstallSteamCmdAsync(dataPath, reporter, cancellationToken);
reporter?.Report(statuses[Status.InstallSteamCmdComplete]);
reporter?.Report(statuses[Status.Complete]);
}
catch (TaskCanceledException)
{
reporter?.Report(statuses[Status.Cancelled]);
}
catch(Exception ex)
{
reporter?.Report(statuses[Status.Complete].SetFailed(ex.ToString()));
}
}
}
}

View file

@ -0,0 +1,29 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Linq;
using System.Reflection;
namespace ServerManagerTool.Common.Lib
{
public class UserScopedSettingContractResolver : DefaultContractResolver
{
public static readonly UserScopedSettingContractResolver Instance = new UserScopedSettingContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
var customAttributes = member.CustomAttributes?.ToArray() ?? new CustomAttributeData[0];
if (customAttributes.Any(a => a.AttributeType == typeof(System.Configuration.UserScopedSettingAttribute)))
{
property.ShouldSerialize = instance => { return property.PropertyType.IsValueType || property.PropertyType == typeof(string); };
}
else
{
property.ShouldSerialize = instance => { return false; };
}
return property;
}
}
}

View file

@ -0,0 +1,331 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
namespace ServerManagerTool.Common.Model
{
/// <summary>
/// An INI style value of the form AggregateName=(Key1=val1, Key2=val2...)
/// </summary>
public abstract class AggregateIniValue : DependencyObject
{
protected const char DELIMITER = ',';
protected readonly List<PropertyInfo> Properties = new List<PropertyInfo>();
public T Duplicate<T>() where T : AggregateIniValue, new()
{
GetPropertyInfos(true);
var result = new T();
foreach (var prop in this.Properties.Where(prop => prop.CanWrite))
{
prop.SetValue(result, prop.GetValue(this));
}
return result;
}
public static T FromINIValue<T>(string value) where T : AggregateIniValue, new()
{
var result = new T();
result.InitializeFromINIValue(value);
return result;
}
protected void GetPropertyInfos(bool allProperties = false)
{
if (this.Properties.Count != 0)
return;
if (allProperties)
this.Properties.AddRange(this.GetType().GetProperties());
else
this.Properties.AddRange(this.GetType().GetProperties().Where(p => p.GetCustomAttribute(typeof(AggregateIniValueEntryAttribute)) != null));
}
public abstract string GetSortKey();
public virtual void InitializeFromINIValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return;
GetPropertyInfos();
if (this.Properties.Count == 0)
return;
var kvPair = value.Split(new[] { '=' }, 2);
value = kvPair[1].Trim('(', ')', ' ');
var pairs = value.Split(DELIMITER);
foreach (var pair in pairs)
{
kvPair = pair.Split('=');
if (kvPair.Length != 2)
continue;
var key = kvPair[0].Trim();
var val = kvPair[1].Trim();
var propInfo = this.Properties.FirstOrDefault(p => string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase));
if (propInfo != null)
StringUtils.SetPropertyValue(val, this, propInfo);
else
{
propInfo = this.Properties.FirstOrDefault(f => f.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().Any(a => string.Equals(a.Key, key, StringComparison.OrdinalIgnoreCase)));
if (propInfo != null)
StringUtils.SetPropertyValue(val, this, propInfo);
}
}
}
public abstract bool IsEquivalent(AggregateIniValue other);
public virtual bool ShouldSave() { return true; }
public static object SortKeySelector(AggregateIniValue arg)
{
return arg.GetSortKey();
}
public virtual string ToINIValue()
{
GetPropertyInfos();
if (this.Properties.Count == 0)
return string.Empty;
var result = new StringBuilder();
result.Append("(");
var delimiter = "";
foreach (var prop in this.Properties)
{
result.Append(delimiter);
var attr = prop.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().FirstOrDefault();
var propName = string.IsNullOrWhiteSpace(attr?.Key) ? prop.Name : attr.Key;
var val = prop.GetValue(this);
var propValue = StringUtils.GetPropertyValue(val, prop);
if ((attr?.ExcludeIfEmpty ?? false) && string.IsNullOrWhiteSpace(propValue))
{
Debug.WriteLine($"{propName} skipped, ExcludeIfEmpty = true and value is empty");
}
else
{
result.Append($"{propName}={propValue}");
delimiter = DELIMITER.ToString();
}
}
result.Append(")");
return result.ToString();
}
public override string ToString()
{
return ToINIValue();
}
protected virtual void FromComplexINIValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
return;
GetPropertyInfos();
if (this.Properties.Count == 0)
return;
var kvValue = value.Trim(' ');
var propertyValues = SplitCollectionValues(kvValue, DELIMITER);
foreach (var property in this.Properties)
{
var attr = property.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().FirstOrDefault();
var propertyName = string.IsNullOrWhiteSpace(attr?.Key) ? property.Name : attr.Key;
var propertyValue = propertyValues.FirstOrDefault(p => p.StartsWith($"{propertyName}="));
if (propertyValue == null)
continue;
var kvPropertyPair = propertyValue.Split(new[] { '=' }, 2);
var kvPropertyValue = kvPropertyPair[1].Trim(DELIMITER, ' ');
if (attr?.ValueWithinBrackets ?? false)
{
if (kvPropertyValue.StartsWith("("))
kvPropertyValue = kvPropertyValue.Substring(1);
if (kvPropertyValue.EndsWith(")"))
kvPropertyValue = kvPropertyValue.Substring(0, kvPropertyValue.Length - 1);
}
var collection = property.GetValue(this) as IIniValuesCollection;
if (collection != null)
{
var values = SplitCollectionValues(kvPropertyValue, DELIMITER);
values = values.Where(v => !string.IsNullOrWhiteSpace(v)).ToArray();
if (attr?.ListValueWithinBrackets ?? false)
{
values = values.Select(v => v.Substring(1)).ToArray();
values = values.Select(v => v.Substring(0, v.Length - 1)).ToArray();
}
collection.FromIniValues(values);
}
else
StringUtils.SetPropertyValue(kvPropertyValue, this, property);
}
}
protected virtual string ToComplexINIValue(bool resultWithinBrackets)
{
GetPropertyInfos();
if (this.Properties.Count == 0)
return string.Empty;
var result = new StringBuilder();
if (resultWithinBrackets)
result.Append("(");
var delimiter = "";
foreach (var prop in this.Properties)
{
var attr = prop.GetCustomAttributes(typeof(AggregateIniValueEntryAttribute), false).OfType<AggregateIniValueEntryAttribute>().FirstOrDefault();
var propName = string.IsNullOrWhiteSpace(attr?.Key) ? prop.Name : attr.Key;
var val = prop.GetValue(this);
var collection = val as IIniValuesCollection;
if (collection != null)
{
result.Append(delimiter);
result.Append($"{propName}=");
if (attr?.ValueWithinBrackets ?? false)
result.Append("(");
var iniVals = collection.ToIniValues();
var delimiter2 = "";
foreach (var iniVal in iniVals)
{
result.Append(delimiter2);
if (attr?.ListValueWithinBrackets ?? false)
result.Append($"({iniVal})");
else
result.Append(iniVal);
delimiter2 = DELIMITER.ToString();
}
if (attr?.ValueWithinBrackets ?? false)
result.Append(")");
delimiter = DELIMITER.ToString();
}
else
{
if ((attr?.ExcludeIfEmpty ?? false) && val is string && string.IsNullOrWhiteSpace(val.ToString()))
{
Debug.WriteLine($"{propName} skipped, ExcludeIfEmpty = true and value is null or empty");
}
else if ((attr?.ExcludeIfFalse ?? false) && val is bool && !((bool)val))
{
Debug.WriteLine($"{propName} skipped, ExcludeIfFalse = true and value is false");
}
else
{
var propValue = StringUtils.GetPropertyValue(val, prop);
result.Append(delimiter);
result.Append($"{propName}=");
if (attr?.ValueWithinBrackets ?? false)
result.Append("(");
result.Append(propValue);
if (attr?.ValueWithinBrackets ?? false)
result.Append(")");
delimiter = DELIMITER.ToString();
}
}
}
if (resultWithinBrackets)
result.Append(")");
return result.ToString();
}
protected string[] SplitCollectionValues(string valueString, char delimiter)
{
if (string.IsNullOrWhiteSpace(valueString))
return new string[0];
// string any leading or trailing spaces
var tempString = valueString.Trim();
// check if any delimiters
var total1 = tempString.Count(c => c.Equals(delimiter));
if (total1 == 0)
return new[] {tempString};
var result = new List<string>();
var bracketCount = 0;
var startIndex = 0;
for (var index = 0; index < tempString.Length; index++)
{
var charValue = tempString[index];
if (charValue == '(')
{
bracketCount++;
continue;
}
if (charValue == ')')
{
bracketCount--;
continue;
}
if (charValue != delimiter || bracketCount != 0)
continue;
result.Add(tempString.Substring(startIndex, index - startIndex));
startIndex = index + 1;
}
result.Add(tempString.Substring(startIndex));
return result.ToArray();
}
public void Update(AggregateIniValue other)
{
if (other == null)
return;
GetPropertyInfos();
other.GetPropertyInfos();
foreach (var propInfo in this.Properties)
{
var otherPropInfo = other.Properties.FirstOrDefault(p => p.Name.Equals(propInfo.Name, StringComparison.OrdinalIgnoreCase));
if (otherPropInfo == null)
continue;
var val = otherPropInfo.GetValue(other);
var propValue = StringUtils.GetPropertyValue(val, propInfo);
StringUtils.SetPropertyValue(propValue, this, propInfo);
}
}
}
}

View file

@ -0,0 +1,86 @@
using ServerManagerTool.Common.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
public class AggregateIniValueList<T> : SortableObservableCollection<T>, IIniValuesCollection
where T : AggregateIniValue, new()
{
protected readonly Func<IEnumerable<T>> _resetFunc;
private bool _isEnabled;
public AggregateIniValueList(string aggregateValueName, Func<IEnumerable<T>> resetFunc)
{
this.IniCollectionKey = aggregateValueName;
this._resetFunc = resetFunc;
}
public string IniCollectionKey { get; }
public bool IsEnabled
{
get { return this._isEnabled; }
set
{
this._isEnabled = value;
OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs(nameof(IsEnabled)));
}
}
public bool IsArray => false;
public void AddRange(IEnumerable<T> values)
{
if (values == null)
return;
foreach (var value in values)
{
var item = this.FirstOrDefault(i => i.IsEquivalent(value));
if (item == null)
base.Add(value);
else
item.Update(value);
}
this.Sort(AggregateIniValue.SortKeySelector);
}
public void Reset()
{
this.Clear();
if (this._resetFunc != null)
this.AddRange(this._resetFunc());
this.Sort(AggregateIniValue.SortKeySelector);
}
public virtual void FromIniValues(IEnumerable<string> iniValues)
{
var items = iniValues?.Select(AggregateIniValue.FromINIValue<T>).ToArray();
Clear();
AddRange(items);
IsEnabled = (Count != 0);
// Add any default values which were missing
if (_resetFunc != null)
{
var defaultItemsToAdd = _resetFunc().Where(r => !this.Any(v => v.IsEquivalent(r))).ToArray();
AddRange(defaultItemsToAdd);
}
Sort(AggregateIniValue.SortKeySelector);
}
public virtual IEnumerable<string> ToIniValues()
{
if (string.IsNullOrWhiteSpace(IniCollectionKey))
return this.Where(d => d.ShouldSave()).Select(d => d.ToINIValue());
return this.Where(d => d.ShouldSave()).Select(d => $"{this.IniCollectionKey}={d.ToINIValue()}");
}
}
}

View file

@ -0,0 +1,56 @@
using System.Windows;
namespace ServerManagerTool.Common.Model
{
public class ComboBoxItem : DependencyObject
{
public static readonly DependencyProperty ValueMemberProperty = DependencyProperty.Register(nameof(ValueMember), typeof(string), typeof(ComboBoxItem), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty DisplayMemberProperty = DependencyProperty.Register(nameof(DisplayMember), typeof(string), typeof(ComboBoxItem), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty GroupMemberProperty = DependencyProperty.Register(nameof(GroupMember), typeof(string), typeof(ComboBoxItem), new PropertyMetadata(string.Empty));
public ComboBoxItem()
{
}
public ComboBoxItem(string valueMember, string displayMember)
{
ValueMember = valueMember;
DisplayMember = displayMember;
}
public ComboBoxItem(string valueMember, string displayMember, string groupMember)
{
ValueMember = valueMember;
DisplayMember = displayMember;
GroupMember = groupMember;
}
public string ValueMember
{
get { return (string)GetValue(ValueMemberProperty); }
set { SetValue(ValueMemberProperty, value); }
}
public string DisplayMember
{
get { return (string)GetValue(DisplayMemberProperty); }
set { SetValue(DisplayMemberProperty, value); }
}
public string GroupMember
{
get { return (string)GetValue(GroupMemberProperty); }
set { SetValue(GroupMemberProperty, value); }
}
public ComboBoxItem Duplicate()
{
return new ComboBoxItem
{
DisplayMember = this.DisplayMember,
ValueMember = this.ValueMember,
GroupMember = this.GroupMember,
};
}
}
}

View file

@ -0,0 +1,11 @@
using System.Collections.Specialized;
namespace ServerManagerTool.Common.Model
{
public class ComboBoxItemList : SortableObservableCollection<ComboBoxItem>
{
public ComboBoxItemList()
{
}
}
}

View file

@ -0,0 +1,55 @@
using System.Windows;
namespace ServerManagerTool.Common.Model
{
public class CustomItem : DependencyObject
{
public static readonly DependencyProperty ItemKeyProperty = DependencyProperty.Register(nameof(ItemKey), typeof(string), typeof(CustomItem), new PropertyMetadata(string.Empty));
public string ItemKey
{
get { return (string)GetValue(ItemKeyProperty); }
set { SetValue(ItemKeyProperty, value); }
}
public static readonly DependencyProperty ItemValueProperty = DependencyProperty.Register(nameof(ItemValue), typeof(string), typeof(CustomItem), new PropertyMetadata(string.Empty));
public string ItemValue
{
get { return (string)GetValue(ItemValueProperty); }
set { SetValue(ItemValueProperty, value); }
}
public static CustomItem FromINIValue(string value)
{
var result = new CustomItem();
result.InitializeFromINIValue(value);
return result;
}
protected virtual void InitializeFromINIValue(string value)
{
var kvPair = value.Split(new[] { '=' }, 2);
if (kvPair.Length > 1)
{
ItemKey = kvPair[0];
ItemValue = kvPair[1];
}
else if (kvPair.Length > 0)
{
ItemKey = kvPair[0];
ItemValue = string.Empty;
}
}
public virtual string ToINIValue()
{
return this.ToString();
}
public override string ToString()
{
if (string.IsNullOrWhiteSpace(ItemKey))
return null;
return $"{ItemKey}={ItemValue}";
}
}
}

View file

@ -0,0 +1,112 @@
using ServerManagerTool.Common.Interfaces;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
namespace ServerManagerTool.Common.Model
{
public class CustomSection : DependencyObject, IIniValuesCollection, IEnumerable<CustomItem>
{
public CustomSection()
{
SectionItems = new ObservableCollection<CustomItem>();
Update();
}
public static readonly DependencyProperty IsDeletedProperty = DependencyProperty.Register(nameof(IsDeleted), typeof(bool), typeof(CustomSection), new PropertyMetadata(false));
public bool IsDeleted
{
get { return (bool)GetValue(IsDeletedProperty); }
set { SetValue(IsDeletedProperty, value); }
}
public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register(nameof(IsEnabled), typeof(bool), typeof(CustomSection), new PropertyMetadata(false));
public bool IsEnabled
{
get { return (bool)GetValue(IsEnabledProperty); }
set { SetValue(IsEnabledProperty, value); }
}
public static readonly DependencyProperty SectionItemsProperty = DependencyProperty.Register(nameof(SectionItems), typeof(ObservableCollection<CustomItem>), typeof(CustomSection), new PropertyMetadata(null));
public ObservableCollection<CustomItem> SectionItems
{
get { return (ObservableCollection<CustomItem>)GetValue(SectionItemsProperty); }
set { SetValue(SectionItemsProperty, value); }
}
public static readonly DependencyProperty SectionNameProperty = DependencyProperty.Register(nameof(SectionName), typeof(string), typeof(CustomSection), new PropertyMetadata(string.Empty));
public string SectionName
{
get { return (string)GetValue(SectionNameProperty); }
set { SetValue(SectionNameProperty, value); }
}
public bool IsArray => false;
public string IniCollectionKey => SectionName;
public void Add(string itemKey, string itemValue)
{
var item = new CustomItem();
item.ItemKey = itemKey;
item.ItemValue = itemValue;
SectionItems.Add(item);
Update();
}
public void AddRange(IEnumerable<CustomItem> values)
{
foreach (var value in values)
{
SectionItems.Add(value);
}
Update();
}
public void Clear()
{
SectionItems.Clear();
}
public void FromIniValues(IEnumerable<string> values)
{
AddRange(values.Select(v => CustomItem.FromINIValue(v)));
}
public IEnumerator<CustomItem> GetEnumerator()
{
return SectionItems.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return SectionItems.GetEnumerator();
}
public bool Remove(CustomItem item)
{
return SectionItems.Remove(item);
}
public IEnumerable<string> ToIniValues()
{
var values = new List<string>();
values.AddRange(SectionItems.Select(i => i.ToINIValue()).Where(i => i != null));
return values;
}
public override string ToString()
{
return $"{SectionName}; Count={SectionItems.Count}";
}
public void Update()
{
this.IsEnabled = (!IsDeleted && SectionItems.Count != 0);
}
}
}

View file

@ -0,0 +1,69 @@
using ServerManagerTool.Common.Interfaces;
using System;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
public class CustomList : SortableObservableCollection<CustomSection>, IIniSectionCollection
{
public IIniValuesCollection[] Sections
{
get
{
return this.ToArray();
}
}
public void Add(string sectionName, string[] values)
{
Add(sectionName, values, true);
}
public void Add(string sectionName, string[] values, bool clearExisting)
{
var section = this.Items.FirstOrDefault(s => s.SectionName.Equals(sectionName, StringComparison.OrdinalIgnoreCase) && !s.IsDeleted);
if (section == null)
{
section = new CustomSection();
section.SectionName = sectionName;
this.Add(section);
}
if (clearExisting)
section.Clear();
section.FromIniValues(values);
}
public new void Clear()
{
foreach (var section in this)
{
section.IsDeleted = true;
}
Update();
}
public new void Remove(CustomSection item)
{
if (item != null)
item.IsDeleted = true;
Update();
}
public override string ToString()
{
return $"Count={Count}";
}
public void Update()
{
foreach (var section in this)
{
section.Update();
}
this.Sort(s => s.SectionName);
}
}
}

View file

@ -0,0 +1,47 @@
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.Globalization;
namespace ServerManagerTool.Common.Model
{
public class FloatIniValueArray : IniValueList<float>, IIniValuesList
{
public FloatIniValueArray(string iniKeyName, Func<IEnumerable<float>> resetFunc) :
base(iniKeyName, resetFunc, (a, b) => a == b, m => m, ToIniValueInternal, FromIniValueInternal)
{
}
public override bool IsArray => true;
private static string ToIniValueInternal(float val)
{
return val.ToString("0.0#########", CultureInfo.GetCultureInfo(StringUtils.DEFAULT_CULTURE_CODE));
}
private static float FromIniValueInternal(string iniVal)
{
var tempValue = iniVal.Replace("f", "");
return float.Parse(tempValue, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, CultureInfo.GetCultureInfo(StringUtils.DEFAULT_CULTURE_CODE));
}
public IEnumerable<string> ToIniValues(object excludeIfValue)
{
var excludeIfFloatValue = excludeIfValue is float ? (float)excludeIfValue : float.NaN;
var values = new List<string>();
for (var i = 0; i < this.Count; i++)
{
if (!EquivalencyFunc(this[i], excludeIfFloatValue))
{
if (string.IsNullOrWhiteSpace(IniCollectionKey))
values.Add(this.ToIniValue(this[i]));
else
values.Add($"{this.IniCollectionKey}[{i}]={this.ToIniValue(this[i])}");
}
}
return values;
}
}
}

View file

@ -0,0 +1,41 @@
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
public class FloatIniValueList : IniValueList<float>, IIniValuesList
{
public FloatIniValueList(string iniKeyName, Func<IEnumerable<float>> resetFunc) :
base(iniKeyName, resetFunc, (a, b) => a == b, m => m, ToIniValueInternal, FromIniValueInternal)
{
}
public override bool IsArray => false;
private static string ToIniValueInternal(float val)
{
return val.ToString("0.0#########", CultureInfo.GetCultureInfo(StringUtils.DEFAULT_CULTURE_CODE));
}
private static float FromIniValueInternal(string iniVal)
{
return float.Parse(iniVal, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, CultureInfo.GetCultureInfo(StringUtils.DEFAULT_CULTURE_CODE));
}
public IEnumerable<string> ToIniValues(object excludeIfValue)
{
var excludeIfFloatValue = excludeIfValue is float ? (float)excludeIfValue : float.NaN;
var values = new List<string>();
if (string.IsNullOrWhiteSpace(IniCollectionKey))
values.AddRange(this.Where(v => !EquivalencyFunc(v, excludeIfFloatValue)).Select(d => ToIniValueInternal(d)));
else
values.AddRange(this.Where(v => !EquivalencyFunc(v, excludeIfFloatValue)).Select(d => $"{this.IniCollectionKey}={ToIniValueInternal(d)}"));
return values;
}
}
}

View file

@ -0,0 +1,6 @@
namespace ServerManagerTool.Common.Model
{
public class IniValueArray
{
}
}

View file

@ -0,0 +1,138 @@
using ServerManagerTool.Common.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
public abstract class IniValueList<T> : SortableObservableCollection<T>, IIniValuesCollection
{
private bool _isEnabled;
protected IniValueList(string aggregateValueName, Func<IEnumerable<T>> resetFunc, Func<T, T, bool> equivalencyFunc, Func<T, object> sortKeySelectorFunc, Func<T, string> toIniValue, Func<string, T> fromIniValue)
{
this.ToIniValue = toIniValue;
this.FromIniValue = fromIniValue;
this.ResetFunc = resetFunc;
this.EquivalencyFunc = equivalencyFunc;
this.SortKeySelectorFunc = sortKeySelectorFunc;
this.IniCollectionKey = aggregateValueName;
this.Reset();
this.IsEnabled = false;
}
public Func<T, string> ToIniValue { get; }
public Func<string, T> FromIniValue { get; }
protected Func<IEnumerable<T>> ResetFunc { get; }
public Func<T, T, bool> EquivalencyFunc { get; private set; }
protected Func<T, object> SortKeySelectorFunc { get; }
public bool IsEnabled
{
get { return this._isEnabled; }
set
{
this._isEnabled = value;
OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs(nameof(IsEnabled)));
}
}
public abstract bool IsArray { get; }
public string IniCollectionKey { get; }
public void AddRange(IEnumerable<T> values)
{
foreach (var value in values)
{
base.Add(value);
}
}
public virtual void FromIniValues(IEnumerable<string> values)
{
this.Clear();
if (this.IsArray)
{
var list = new List<T>();
if (this.ResetFunc != null)
list.AddRange(this.ResetFunc());
foreach(var v in values)
{
var indexStart = v.IndexOf('[');
var indexEnd = v.IndexOf(']');
if(indexStart >= indexEnd)
{
// Invalid format
continue;
}
int index;
if(!int.TryParse(v.Substring(indexStart + 1, indexEnd - indexStart - 1), out index))
{
// Invalid index
continue;
}
if(index >= list.Count)
{
// Unexpected size
continue;
}
list[index] = this.FromIniValue(v.Substring(v.IndexOf('=') + 1).Trim());
this.IsEnabled = true;
}
this.AddRange(list);
}
else
{
this.AddRange(values.Select(v => v.Substring(v.IndexOf('=') + 1)).Select(this.FromIniValue));
this.IsEnabled = (this.Count != 0);
// Add any default values which were missing
if (this.ResetFunc != null)
{
var defaultItemsToAdd = this.ResetFunc().Where(r => !this.Any(v => this.EquivalencyFunc(v, r))).ToArray();
this.AddRange(defaultItemsToAdd);
this.Sort(this.SortKeySelectorFunc);
}
}
}
public virtual IEnumerable<string> ToIniValues()
{
var values = new List<string>();
if (this.IsArray)
{
for(var i = 0; i < this.Count; i++)
{
if (string.IsNullOrWhiteSpace(IniCollectionKey))
values.Add(this.ToIniValue(this[i]));
else
values.Add($"{this.IniCollectionKey}[{i}]={this.ToIniValue(this[i])}");
}
}
else
{
if (string.IsNullOrWhiteSpace(IniCollectionKey))
values.AddRange(this.Select(d => this.ToIniValue(d)));
else
values.AddRange(this.Select(d => $"{this.IniCollectionKey}={this.ToIniValue(d)}"));
}
return values;
}
public void Reset()
{
this.Clear();
if (this.ResetFunc != null)
this.AddRange(this.ResetFunc());
}
}
}

View file

@ -0,0 +1,41 @@
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
public class IntegerIniValueList : IniValueList<int>, IIniValuesList
{
public IntegerIniValueList(string iniKeyName, Func<IEnumerable<int>> resetFunc) :
base(iniKeyName, resetFunc, (a, b) => a == b, m => m, ToIniValueInternal, FromIniValueInternal)
{
}
public override bool IsArray => false;
private static string ToIniValueInternal(int val)
{
return val.ToString(CultureInfo.GetCultureInfo(StringUtils.DEFAULT_CULTURE_CODE));
}
private static int FromIniValueInternal(string iniVal)
{
return int.Parse(iniVal, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, CultureInfo.GetCultureInfo(StringUtils.DEFAULT_CULTURE_CODE));
}
public IEnumerable<string> ToIniValues(object excludeIfValue)
{
var excludeIfIntegerValue = excludeIfValue is int ? (int)excludeIfValue : int.MinValue;
var values = new List<string>();
if (string.IsNullOrWhiteSpace(IniCollectionKey))
values.AddRange(this.Where(v => !EquivalencyFunc(v, excludeIfIntegerValue)).Select(d => ToIniValueInternal(d)));
else
values.AddRange(this.Where(v => !EquivalencyFunc(v, excludeIfIntegerValue)).Select(d => $"{this.IniCollectionKey}={ToIniValueInternal(d)}"));
return values;
}
}
}

View file

@ -0,0 +1,45 @@
using System.Runtime.Serialization;
using System.Windows;
namespace ServerManagerTool.Common.Model
{
[DataContract]
public class PlayerUserItem : DependencyObject
{
public static readonly DependencyProperty PlayerIdProperty = DependencyProperty.Register(nameof(PlayerId), typeof(string), typeof(PlayerUserItem), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty PlayerNameProperty = DependencyProperty.Register(nameof(PlayerName), typeof(string), typeof(PlayerUserItem), new PropertyMetadata(string.Empty));
[DataMember]
public string PlayerId
{
get { return (string)GetValue(PlayerIdProperty); }
set { SetValue(PlayerIdProperty, value); }
}
[DataMember]
public string PlayerName
{
get { return (string)GetValue(PlayerNameProperty); }
set { SetValue(PlayerNameProperty, value); }
}
public static PlayerUserItem GetItem(SteamUserDetail detail)
{
if (string.IsNullOrWhiteSpace(detail.steamid))
return null;
var result = new PlayerUserItem
{
PlayerId = detail.steamid,
PlayerName = detail.personaname ?? string.Empty,
};
return result;
}
public override string ToString()
{
return $"{PlayerId} - {PlayerName}";
}
}
}

View file

@ -0,0 +1,93 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
namespace ServerManagerTool.Common.Model
{
[DataContract]
public class PlayerUserList : ObservableCollection<PlayerUserItem>
{
public void AddRange(PlayerUserList list)
{
if (list == null)
return;
foreach (var item in list)
{
if (string.IsNullOrWhiteSpace(item?.PlayerId))
continue;
if (!this.Any(i => i.PlayerId.Equals(item.PlayerId)))
this.Add(item);
}
}
public static PlayerUserList GetList(SteamUserDetailResponse response, string[] ids)
{
var result = new PlayerUserList();
if (ids != null)
{
foreach (var id in ids)
{
result.Add(new PlayerUserItem()
{
PlayerId = id,
PlayerName = "<not available>",
});
}
}
if (response?.players != null)
{
foreach (var detail in response.players)
{
var item = result.FirstOrDefault(i => i.PlayerId == detail.steamid);
if (item == null)
{
var newItem = PlayerUserItem.GetItem(detail);
if (!string.IsNullOrWhiteSpace(newItem?.PlayerId))
result.Add(newItem);
}
else
{
item.PlayerId = detail.steamid;
item.PlayerName = detail.personaname ?? string.Empty;
}
}
}
// remove all NULL records.
for(int index = result.Count - 1; index >= 0; index--)
{
if (result[index] == null)
result.RemoveAt(index);
}
return result;
}
public void Remove(string steamId)
{
var items = this.Where(i => i.PlayerId.Equals(steamId, System.StringComparison.OrdinalIgnoreCase)).ToArray();
foreach (var item in items)
{
this.Remove(item);
}
}
public string[] ToArray()
{
return this.Select(i => i.PlayerId).ToArray();
}
public string ToDelimitedString(string delimiter)
{
return string.Join(delimiter, this.Select(i => i.PlayerId));
}
public override string ToString()
{
return $"{nameof(PlayerUserList)} - {Count}";
}
}
}

View file

@ -0,0 +1,29 @@
using System.Numerics;
using System.Windows;
namespace ServerManagerTool.Common.Model
{
public class ProcessorAffinityItem : DependencyObject
{
public static readonly DependencyProperty SelectedProperty = DependencyProperty.Register(nameof(Selected), typeof(bool), typeof(ProcessorAffinityItem), new PropertyMetadata(false));
public bool Selected
{
get { return (bool)GetValue(SelectedProperty); }
set { SetValue(SelectedProperty, value); }
}
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(nameof(Description), typeof(string), typeof(ProcessorAffinityItem), new PropertyMetadata(string.Empty));
public string Description
{
get { return (string)GetValue(DescriptionProperty); }
set { SetValue(DescriptionProperty, value); }
}
public static readonly DependencyProperty AffinityValueProperty = DependencyProperty.Register(nameof(AffinityValue), typeof(BigInteger), typeof(ProcessorAffinityItem), new PropertyMetadata(BigInteger.Zero));
public BigInteger AffinityValue
{
get { return (BigInteger)GetValue(AffinityValueProperty); }
set { SetValue(AffinityValueProperty, value); }
}
}
}

View file

@ -0,0 +1,67 @@
using ServerManagerTool.Common.Utils;
using System.Linq;
using System.Numerics;
namespace ServerManagerTool.Common.Model
{
public class ProcessorAffinityList : SortableObservableCollection<ProcessorAffinityItem>
{
private bool _allProcessors;
public ProcessorAffinityList(BigInteger affinityValue)
{
AllProcessors = true;
PopulateAffinities(affinityValue);
}
public bool AllProcessors
{
get { return this._allProcessors; }
set
{
this._allProcessors = value;
OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs(nameof(AllProcessors)));
}
}
public BigInteger AffinityValue
{
get
{
if (AllProcessors || this.Count(i => i.Selected) == this.Count)
return BigInteger.Zero;
var affinity = BigInteger.Zero;
foreach (var value in this.Where(i => i.Selected).Select(i => i.AffinityValue))
affinity += value;
return affinity;
}
}
private void PopulateAffinities(BigInteger affinityValue)
{
var list = ProcessUtils.GetProcessorAffinityList();
var index = 0;
if (!ProcessUtils.IsProcessorAffinityValid(affinityValue))
affinityValue = BigInteger.Zero;
foreach (var item in list)
{
if (item == 0)
continue;
this.Add(new ProcessorAffinityItem() { Selected = affinityValue == BigInteger.Zero || ((affinityValue & item) == item), AffinityValue = item, Description = $"{index}" });
index++;
}
var affinity = BigInteger.Zero;
if (this.Count(i => i.Selected) != this.Count)
{
foreach (var value in this.Where(i => i.Selected).Select(i => i.AffinityValue))
affinity += value;
}
AllProcessors = affinity == BigInteger.Zero;
}
}
}

View file

@ -0,0 +1,55 @@
using System.Collections.Generic;
namespace ServerManagerTool.Common.Model
{
public class PublishedFileDetail
{
public string publishedfileid { get; set; }
public int result { get; set; }
public string creator { get; set; }
public string creator_app_id { get; set; }
public string consumer_app_id { get; set; }
public string filename { get; set; }
public string file_size { get; set; }
public string file_url { get; set; }
public string hcontent_file { get; set; }
public string preview_url { get; set; }
public string hcontent_preview { get; set; }
public string title { get; set; }
public string description { get; set; }
public int time_created { get; set; }
public int time_updated { get; set; }
public int visibility { get; set; }
public int banned { get; set; }
public string ban_reason { get; set; }
public int subscriptions { get; set; }
public int favorited { get; set; }
public int lifetime_subscriptions { get; set; }
public int lifetime_favorited { get; set; }
public int views { get; set; }
public List<object> tags { get; set; }
}
}

View file

@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace ServerManagerTool.Common.Model
{
public class PublishedFileDetailsResponse
{
public int result { get; set; }
public int resultcount { get; set; }
public List<PublishedFileDetail> publishedfiledetails { get; set; }
}
}

View file

@ -0,0 +1,7 @@
namespace ServerManagerTool.Common.Model
{
public class PublishedFileDetailsResult
{
public PublishedFileDetailsResponse response { get; set; }
}
}

View file

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
/// <summary>
/// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed and allows sorting.
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
public class SortableObservableCollection<T> : ObservableCollection<T>
{
public SortableObservableCollection()
{
}
public SortableObservableCollection(List<T> list)
: base(list)
{
}
public SortableObservableCollection(IEnumerable<T> collection)
: base(collection)
{
}
/// <summary>
/// Sorts the items of the collection in ascending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
public void Sort<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderBy(keySelector));
}
/// <summary>
/// Sorts the items of the collection in ascending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
/// <param name="comparer">An <see cref="IComparer{T}"/> to compare keys.</param>
public void Sort<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
InternalSort(Items.OrderBy(keySelector, comparer));
}
/// <summary>
/// Sorts the items of the collection in descending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
public void SortDescending<TKey>(Func<T, TKey> keySelector)
{
InternalSort(Items.OrderByDescending(keySelector));
}
/// <summary>
/// Sorts the items of the collection in descending order according to a key.
/// </summary>
/// <typeparam name="TKey">The type of the key returned by <paramref name="keySelector"/>.</typeparam>
/// <param name="keySelector">A function to extract a key from an item.</param>
/// <param name="comparer">An <see cref="IComparer{T}"/> to compare keys.</param>
public void SortDescending<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
{
InternalSort(Items.OrderByDescending(keySelector, comparer));
}
/// <summary>
/// Moves the items of the collection so that their orders are the same as those of the items provided.
/// </summary>
/// <param name="sortedItems">An <see cref="IEnumerable{T}"/> to provide item orders.</param>
private void InternalSort(IEnumerable<T> sortedItems)
{
var sortedItemsList = sortedItems.ToList();
foreach (var item in sortedItemsList)
{
Move(IndexOf(item), sortedItemsList.IndexOf(item));
}
}
}
}

View file

@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace ServerManagerTool.Common.Model
{
public class SteamCmdAppManifest
{
public string appid { get; set; }
public List<SteamCmdManifestUserConfig> UserConfig { get; set; }
}
}

View file

@ -0,0 +1,23 @@
using System.Collections.Generic;
namespace ServerManagerTool.Common.Model
{
public class SteamCmdAppWorkshop
{
public string appid { get; set; }
public string SizeOnDisk { get; set; }
public string NeedsUpdate { get; set; }
public string NeedsDownload { get; set; }
public string TimeLastUpdated { get; set; }
public string TimeLastAppRan { get; set; }
public List<SteamCmdWorkshopItemsInstalled> WorkshopItemsInstalled { get; set; }
public List<SteamCmdWorkshopItemDetails> WorkshopItemDetails { get; set; }
}
}

View file

@ -0,0 +1,83 @@
using NeXt.Vdf;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
public class SteamCmdManifestDetailsResult
{
public static bool ClearUserConfigBetaKeys(VdfValue data)
{
var updated = false;
var vdfTable = data as VdfTable;
if (vdfTable != null)
{
var value = vdfTable.FirstOrDefault(v => v.Name.Equals("UserConfig", StringComparison.OrdinalIgnoreCase));
var tableValue = value as VdfTable;
if (tableValue != null && tableValue.Count > 0)
{
var betaKeyItems = tableValue.Where(v => v.Name.Equals("betakey", StringComparison.OrdinalIgnoreCase)).ToArray();
foreach (var item in betaKeyItems)
{
tableValue.Remove(item);
updated = true;
}
}
}
return updated;
}
public static SteamCmdAppManifest Deserialize(VdfValue data)
{
var result = new SteamCmdAppManifest();
var vdfTable = data as VdfTable;
if (vdfTable != null)
{
var value = vdfTable.FirstOrDefault(v => v.Name.Equals("appid", StringComparison.OrdinalIgnoreCase));
if (value != null) result.appid = GetValue(value);
value = vdfTable.FirstOrDefault(v => v.Name.Equals("UserConfig", StringComparison.OrdinalIgnoreCase));
var tableValue = value as VdfTable;
if (tableValue != null && tableValue.Count > 0)
{
result.UserConfig = new List<SteamCmdManifestUserConfig>();
foreach (var item in tableValue)
{
if (item is VdfTable)
{
var temp = new SteamCmdManifestUserConfig();
temp.betakey = item.Name;
result.UserConfig.Add(temp);
}
}
}
}
return result;
}
public static string GetValue(VdfValue data)
{
if (data == null)
return null;
switch (data.Type)
{
case VdfValueType.Decimal:
return ((VdfDecimal)data).Content.ToString("G0");
case VdfValueType.Long:
return ((VdfLong)data).Content.ToString("G0");
case VdfValueType.String:
return ((VdfString)data).Content;
default:
return null;
}
}
}
}

View file

@ -0,0 +1,7 @@
namespace ServerManagerTool.Common.Model
{
public class SteamCmdManifestUserConfig
{
public string betakey { get; set; }
}
}

View file

@ -0,0 +1,111 @@
using NeXt.Vdf;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
public class SteamCmdWorkshopDetailsResult
{
public static SteamCmdAppWorkshop Deserialize(VdfValue data)
{
var result = new SteamCmdAppWorkshop();
var vdfTable = data as VdfTable;
if (vdfTable != null)
{
var value = vdfTable.FirstOrDefault(v => v.Name.Equals("appid", StringComparison.OrdinalIgnoreCase));
if (value != null) result.appid = GetValue(value);
value = vdfTable.FirstOrDefault(v => v.Name.Equals("SizeOnDisk", StringComparison.OrdinalIgnoreCase));
if (value != null) result.SizeOnDisk = GetValue(value);
value = vdfTable.FirstOrDefault(v => v.Name.Equals("NeedsUpdate", StringComparison.OrdinalIgnoreCase));
if (value != null) result.NeedsUpdate = GetValue(value);
value = vdfTable.FirstOrDefault(v => v.Name.Equals("NeedsDownload", StringComparison.OrdinalIgnoreCase));
if (value != null) result.NeedsDownload = GetValue(value);
value = vdfTable.FirstOrDefault(v => v.Name.Equals("TimeLastUpdated", StringComparison.OrdinalIgnoreCase));
if (value != null) result.TimeLastUpdated = GetValue(value);
value = vdfTable.FirstOrDefault(v => v.Name.Equals("TimeLastAppRan", StringComparison.OrdinalIgnoreCase));
if (value != null) result.TimeLastAppRan = GetValue(value);
value = vdfTable.FirstOrDefault(v => v.Name.Equals("WorkshopItemsInstalled", StringComparison.OrdinalIgnoreCase));
var tableValue = value as VdfTable;
if (tableValue != null && tableValue.Count > 0)
{
result.WorkshopItemsInstalled = new List<SteamCmdWorkshopItemsInstalled>();
foreach (var item in tableValue)
{
if (item is VdfTable)
{
var temp = new SteamCmdWorkshopItemsInstalled();
temp.publishedfileid = item.Name;
value = ((VdfTable)item).FirstOrDefault(v => v.Name.Equals("manifest", StringComparison.OrdinalIgnoreCase));
if (value != null) temp.manifest = GetValue(value);
value = ((VdfTable)item).FirstOrDefault(v => v.Name.Equals("size", StringComparison.OrdinalIgnoreCase));
if (value != null) temp.size = GetValue(value);
value = ((VdfTable)item).FirstOrDefault(v => v.Name.Equals("timeupdated", StringComparison.OrdinalIgnoreCase));
if (value != null) temp.timeupdated = GetValue(value);
result.WorkshopItemsInstalled.Add(temp);
}
}
}
value = vdfTable.FirstOrDefault(v => v.Name.Equals("WorkshopItemDetails", StringComparison.OrdinalIgnoreCase));
tableValue = value as VdfTable;
if (tableValue != null && tableValue.Count > 0)
{
result.WorkshopItemDetails = new List<SteamCmdWorkshopItemDetails>();
foreach (var item in tableValue)
{
if (item is VdfTable)
{
var temp = new SteamCmdWorkshopItemDetails();
temp.publishedfileid = item.Name;
value = ((VdfTable)item).FirstOrDefault(v => v.Name.Equals("manifest", StringComparison.OrdinalIgnoreCase));
if (value != null) temp.manifest = GetValue(value);
value = ((VdfTable)item).FirstOrDefault(v => v.Name.Equals("timeupdated", StringComparison.OrdinalIgnoreCase));
if (value != null) temp.timeupdated = GetValue(value);
value = ((VdfTable)item).FirstOrDefault(v => v.Name.Equals("timetouched", StringComparison.OrdinalIgnoreCase));
if (value != null) temp.timetouched = GetValue(value);
result.WorkshopItemDetails.Add(temp);
}
}
}
}
return result;
}
public static string GetValue(VdfValue data)
{
if (data == null)
return null;
switch (data.Type)
{
case VdfValueType.Decimal:
return ((VdfDecimal)data).Content.ToString("G0");
case VdfValueType.Long:
return ((VdfLong)data).Content.ToString("G0");
case VdfValueType.String:
return ((VdfString)data).Content;
default:
return null;
}
}
}
}

View file

@ -0,0 +1,13 @@
namespace ServerManagerTool.Common.Model
{
public class SteamCmdWorkshopItemDetails
{
public string publishedfileid { get; set; }
public string manifest { get; set; }
public string timeupdated { get; set; }
public string timetouched { get; set; }
}
}

View file

@ -0,0 +1,13 @@
namespace ServerManagerTool.Common.Model
{
public class SteamCmdWorkshopItemsInstalled
{
public string publishedfileid { get; set; }
public string manifest { get; set; }
public string size { get; set; }
public string timeupdated { get; set; }
}
}

View file

@ -0,0 +1,23 @@
namespace ServerManagerTool.Common.Model
{
public class SteamServerDetail
{
public string addr { get; set; }
public int gmsindex { get; set; }
public string appid { get; set; }
public string gamedir { get; set; }
public int region { get; set; }
public string secure { get; set; }
public string lan { get; set; }
public int gameport { get; set; }
public int specport { get; set; }
}
}

View file

@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace ServerManagerTool.Common.Model
{
public class SteamServerDetailResponse
{
public string success { get; set; }
public List<SteamServerDetail> servers { get; set; }
}
}

View file

@ -0,0 +1,7 @@
namespace ServerManagerTool.Common.Model
{
public class SteamServerDetailResult
{
public SteamServerDetailResponse response { get; set; }
}
}

View file

@ -0,0 +1,25 @@
namespace ServerManagerTool.Common.Model
{
public class SteamUserDetail
{
public string steamid { get; set; }
public int communityvisibilitystate { get; set; }
public int profilestate { get; set; }
public string personaname { get; set; }
public int lastlogoff { get; set; }
public string profileurl { get; set; }
public string avatar { get; set; }
public string avatarmedium { get; set; }
public string avatarfull { get; set; }
public int personastate { get; set; }
}
}

View file

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace ServerManagerTool.Common.Model
{
public class SteamUserDetailResponse
{
public List<SteamUserDetail> players { get; set; }
}
}

View file

@ -0,0 +1,7 @@
namespace ServerManagerTool.Common.Model
{
public class SteamUserDetailResult
{
public SteamUserDetailResponse response { get; set; }
}
}

View file

@ -0,0 +1,39 @@
using ServerManagerTool.Common.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
public class StringIniValueList : IniValueList<string>, IIniValuesList
{
public StringIniValueList(string iniKeyName, Func<IEnumerable<string>> resetFunc) :
base(iniKeyName, resetFunc, string.Equals, m => m, ToIniValueInternal, FromIniValueInternal)
{
}
public override bool IsArray => false;
private static string ToIniValueInternal(string val)
{
return "\"" + val + "\"";
}
private static string FromIniValueInternal(string iniVal)
{
return iniVal.Trim('"');
}
public IEnumerable<string> ToIniValues(object excludeIfValue)
{
var excludeIfStringValue = excludeIfValue is string ? (string)excludeIfValue : null;
var values = new List<string>();
if (string.IsNullOrWhiteSpace(IniCollectionKey))
values.AddRange(this.Where(v => !EquivalencyFunc(v, excludeIfStringValue)).Select(d => ToIniValueInternal(d)));
else
values.AddRange(this.Where(v => !EquivalencyFunc(v, excludeIfStringValue)).Select(d => $"{this.IniCollectionKey}={ToIniValueInternal(d)}"));
return values;
}
}
}

View file

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
namespace ServerManagerTool.Common.Model
{
public class VersionFeed
{
public string Id { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public string SubTitle { get; set; } = string.Empty;
public Uri Link { get; set; } = null;
public DateTimeOffset Updated { get; set; } = DateTimeOffset.Now;
public List<VersionFeedEntry> Entries { get; set; } = new List<VersionFeedEntry>();
}
}

View file

@ -0,0 +1,17 @@
using System;
namespace ServerManagerTool.Common.Model
{
public class VersionFeedEntry
{
public string Id { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty;
public string Summary { get; set; } = string.Empty;
public Uri Link { get; set; } = null;
public DateTimeOffset Updated { get; set; } = DateTimeOffset.Now;
public string Content { get; set; } = string.Empty;
public string Author { get; set; } = string.Empty;
public bool IsCurrent { get; set; } = false;
}
}

View file

@ -0,0 +1,97 @@
using System;
namespace ServerManagerTool.Common.Model
{
public class WorkshopFileDetail
{
public int result { get; set; }
public string publishedfileid { get; set; }
public string creator { get; set; }
public string creator_appid { get; set; }
public string consumer_appid { get; set; }
public int consumer_shortcutid { get; set; }
public string filename { get; set; }
public string file_size { get; set; }
public string preview_file_size { get; set; }
public string file_url { get; set; }
public string preview_url { get; set; }
public string url { get; set; }
public string hcontent_file { get; set; }
public string hcontent_preview { get; set; }
public string title { get; set; }
public string file_description { get; set; }
public int time_created { get; set; }
public int time_updated { get; set; }
public int visibility { get; set; }
public int flags { get; set; }
public bool workshop_file { get; set; }
public bool workshop_accepted { get; set; }
public bool show_subscribe_all { get; set; }
public int num_comments_developer { get; set; }
public int num_comments_public { get; set; }
public bool banned { get; set; }
public string ban_reason { get; set; }
public string banner { get; set; }
public bool can_be_deleted { get; set; }
public bool incompatible { get; set; }
public string app_name { get; set; }
public int file_type { get; set; }
public bool can_subscribe { get; set; }
public int subscriptions { get; set; }
public int favorited { get; set; }
public int followers { get; set; }
public int lifetime_subscriptions { get; set; }
public int lifetime_favorited { get; set; }
public int lifetime_followers { get; set; }
public int views { get; set; }
public bool spoiler_tag { get; set; }
public int num_children { get; set; }
public int num_reports { get; set; }
public int language { get; set; }
public bool IsAdded { get; set; }
}
}

View file

@ -0,0 +1,32 @@
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.IO;
namespace ServerManagerTool.Common.Model
{
public class WorkshopFileDetailResponse
{
public DateTime cached = DateTime.UtcNow;
public int total { get; set; }
public List<WorkshopFileDetail> publishedfiledetails { get; set; }
public static WorkshopFileDetailResponse Load(string file)
{
if (string.IsNullOrWhiteSpace(file) || !File.Exists(file))
return null;
return JsonUtils.DeserializeFromFile<WorkshopFileDetailResponse>(file);
}
public bool Save(string file)
{
if (string.IsNullOrWhiteSpace(file))
return false;
return JsonUtils.SerializeToFile(this, file);
}
}
}

View file

@ -0,0 +1,7 @@
namespace ServerManagerTool.Common.Model
{
public class WorkshopFileDetailResult
{
public WorkshopFileDetailResponse response { get; set; }
}
}

View file

@ -0,0 +1,107 @@
using ServerManagerTool.Common.Utils;
using System;
using System.Windows;
namespace ServerManagerTool.Common.Model
{
public class WorkshopFileItem : DependencyObject
{
public static readonly DependencyProperty AppIdProperty = DependencyProperty.Register(nameof(AppId), typeof(string), typeof(WorkshopFileItem), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty CreatedDateProperty = DependencyProperty.Register(nameof(CreatedDate), typeof(DateTime), typeof(WorkshopFileItem), new PropertyMetadata(DateTime.MinValue));
public static readonly DependencyProperty FileSizeProperty = DependencyProperty.Register(nameof(FileSize), typeof(long), typeof(WorkshopFileItem), new PropertyMetadata(-1L));
public static readonly DependencyProperty SubscriptionsProperty = DependencyProperty.Register(nameof(Subscriptions), typeof(int), typeof(WorkshopFileItem), new PropertyMetadata(0));
public static readonly DependencyProperty TimeUpdatedProperty = DependencyProperty.Register(nameof(TimeUpdated), typeof(int), typeof(WorkshopFileItem), new PropertyMetadata(0));
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(WorkshopFileItem), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty UpdatedDateProperty = DependencyProperty.Register(nameof(UpdatedDate), typeof(DateTime), typeof(WorkshopFileItem), new PropertyMetadata(DateTime.MinValue));
public static readonly DependencyProperty WorkshopIdProperty = DependencyProperty.Register(nameof(WorkshopId), typeof(string), typeof(WorkshopFileItem), new PropertyMetadata(string.Empty));
public string AppId
{
get { return (string)GetValue(AppIdProperty); }
set { SetValue(AppIdProperty, value); }
}
public DateTime CreatedDate
{
get { return (DateTime)GetValue(CreatedDateProperty); }
set { SetValue(CreatedDateProperty, value); }
}
public long FileSize
{
get { return (long)GetValue(FileSizeProperty); }
set { SetValue(FileSizeProperty, value); }
}
public int Subscriptions
{
get { return (int)GetValue(SubscriptionsProperty); }
set { SetValue(SubscriptionsProperty, value); }
}
public int TimeUpdated
{
get { return (int)GetValue(TimeUpdatedProperty); }
set { SetValue(TimeUpdatedProperty, value); }
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set
{
SetValue(TitleProperty, value);
TitleFilterString = value?.ToLower();
}
}
public DateTime UpdatedDate
{
get { return (DateTime)GetValue(UpdatedDateProperty); }
set { SetValue(UpdatedDateProperty, value); }
}
public string WorkshopId
{
get { return (string)GetValue(WorkshopIdProperty); }
set { SetValue(WorkshopIdProperty, value); }
}
public string TitleFilterString
{
get;
private set;
}
public string WorkshopUrl => $"http://steamcommunity.com/sharedfiles/filedetails/?id={WorkshopId}";
public static WorkshopFileItem GetItem(WorkshopFileDetail item)
{
if (string.IsNullOrWhiteSpace(item.publishedfileid) || string.IsNullOrWhiteSpace(item.title))
return null;
var result = new WorkshopFileItem();
result.AppId = item.creator_appid;
result.CreatedDate = DateTimeUtils.UnixTimeStampToDateTime(item.time_created);
result.FileSize = -1;
result.Subscriptions = item.subscriptions;
result.TimeUpdated = item.time_updated;
result.Title = item.title ?? string.Empty;
result.UpdatedDate = DateTimeUtils.UnixTimeStampToDateTime(item.time_updated);
result.WorkshopId = item.publishedfileid ?? string.Empty;
long fileSize;
if (long.TryParse(item.file_size, out fileSize))
result.FileSize = fileSize;
return result;
}
public override string ToString()
{
return $"{WorkshopId} - {Title}";
}
}
}

View file

@ -0,0 +1,55 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
namespace ServerManagerTool.Common.Model
{
public class WorkshopFileList : ObservableCollection<WorkshopFileItem>
{
public DateTime CachedTime
{
get;
set;
}
public string CachedTimeFormatted
{
get
{
if (CachedTime == DateTime.MinValue)
return "";
return CachedTime.ToString("G");
}
}
public new void Add(WorkshopFileItem item)
{
if (item == null || this.Any(m => m.WorkshopId.Equals(item.WorkshopId)))
return;
base.Add(item);
}
public static WorkshopFileList GetList(WorkshopFileDetailResponse response)
{
var result = new WorkshopFileList();
if (response != null)
{
result.CachedTime = response.cached.ToLocalTime();
if (response.publishedfiledetails != null)
{
foreach (var detail in response.publishedfiledetails)
{
result.Add(WorkshopFileItem.GetItem(detail));
}
}
}
return result;
}
public override string ToString()
{
return $"{nameof(WorkshopFileList)} - {Count}";
}
}
}

View file

@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ServerManager Common Library")]
[assembly: AssemblyDescription("The library is used to provide common functionality to the server managers.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Bletch1971")]
[assembly: AssemblyProduct("Server Managers")]
[assembly: AssemblyCopyright("Copyright © 2015-2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("7c99d9f7-0c65-4116-927a-94eb018c88fd")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,461 @@
using ServerManagerTool.Common.Attibutes;
using ServerManagerTool.Common.Enums;
using ServerManagerTool.Common.Interfaces;
using ServerManagerTool.Common.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ServerManagerTool.Common.Serialization
{
public abstract class BaseSystemIniFile
{
protected BaseSystemIniFile(string iniPath)
{
this.BasePath = iniPath;
}
public string BasePath
{
get;
private set;
}
public abstract Dictionary<Enum, string> FileNames
{
get;
}
public abstract Dictionary<Enum, string> SectionNames
{
get;
}
public void Deserialize(object obj, Enum[] exclusions)
{
var iniFiles = new Dictionary<string, IniFile>();
var fields = obj.GetType().GetProperties().Where(f => f.IsDefined(typeof(BaseIniFileEntryAttribute), false));
if (exclusions == null)
exclusions = new Enum[0];
foreach (var field in fields)
{
var attributes = field.GetCustomAttributes(typeof(BaseIniFileEntryAttribute), false);
foreach (var attr in attributes.OfType<BaseIniFileEntryAttribute>())
{
if (exclusions.Contains(attr.Category))
continue;
try
{
if (attr.IsCustom)
{
// this code is to handle custom sections
var collection = field.GetValue(obj) as IIniSectionCollection;
if (collection != null)
{
ReadFile(iniFiles, attr.File);
var sectionNames = ReadCustomSectionNames(iniFiles, attr.File);
foreach (var sectionName in sectionNames)
{
var sectionValues = ReadSection(iniFiles, attr.File, sectionName);
collection.Add(sectionName, sectionValues);
}
}
}
else
{
var keyName = string.IsNullOrWhiteSpace(attr.Key) ? field.Name : attr.Key;
if (attr.WriteBoolValueIfNonEmpty)
{
// Don't really need to do anything here, we don't care about this on reading it.
// extraBoolValue = Convert.ToBoolean(IniReadValue(SectionNames[attr.Section], attr.Key));
}
else
{
var iniValue = ReadValue(iniFiles, attr.File, attr.Section, keyName);
var fieldType = field.PropertyType;
var collection = field.GetValue(obj) as IIniValuesCollection;
if (collection != null)
{
var section = ReadSection(iniFiles, attr.File, attr.Section);
var filteredSection = collection.IsArray
? section.Where(s => s.StartsWith(collection.IniCollectionKey + "["))
: section.Where(s => s.StartsWith(collection.IniCollectionKey + "="));
collection.FromIniValues(filteredSection);
}
else if (fieldType == typeof(string))
{
var stringValue = iniValue;
if (attr.QuotedString == QuotedStringType.True)
{
// remove the leading and trailing quotes, if any
if (stringValue.StartsWith("\""))
stringValue = stringValue.Substring(1);
if (stringValue.EndsWith("\""))
stringValue = stringValue.Substring(0, stringValue.Length - 1);
}
else if (attr.QuotedString == QuotedStringType.Remove)
{
// remove the leading and trailing quotes, if any
if (stringValue.StartsWith("\""))
stringValue = stringValue.Substring(1);
if (stringValue.EndsWith("\""))
stringValue = stringValue.Substring(0, stringValue.Length - 1);
}
if (attr.Multiline)
{
stringValue = stringValue.Replace(attr.MultilineSeparator, Environment.NewLine);
}
field.SetValue(obj, stringValue);
}
else
{
if (string.IsNullOrWhiteSpace(iniValue))
{
// Skip non-string values which are not found
continue;
}
// Update the ConditionedOn flag, if this field has one.
if (!string.IsNullOrWhiteSpace(attr.ConditionedOn))
{
var conditionField = obj.GetType().GetProperty(attr.ConditionedOn);
conditionField.SetValue(obj, true);
}
var valueSet = StringUtils.SetPropertyValue(iniValue, obj, field, attr);
if (!valueSet)
throw new ArgumentException($"Unexpected field type {fieldType} for INI key {keyName} in section {attr.Section}.");
}
}
}
}
catch (Exception)
{
throw;
}
}
}
}
public void Serialize(object obj, Enum[] exclusions)
{
var iniFiles = new Dictionary<string, IniFile>();
var fields = obj.GetType().GetProperties().Where(f => f.IsDefined(typeof(BaseIniFileEntryAttribute), false));
if (exclusions == null)
exclusions = new Enum[0];
foreach (var field in fields)
{
var attributes = field.GetCustomAttributes(typeof(BaseIniFileEntryAttribute), false).OfType<BaseIniFileEntryAttribute>();
foreach (var attr in attributes)
{
if (exclusions.Contains(attr.Category))
continue;
try
{
if (attr.IsCustom)
{
// this code is to handle custom sections
var collection = field.GetValue(obj) as IIniSectionCollection;
if (collection != null)
{
collection.Update();
foreach (var section in collection.Sections)
{
// clear the entire section
WriteValue(iniFiles, attr.File, section.IniCollectionKey, null, null);
if (section.IsEnabled)
{
WriteSection(iniFiles, attr.File, section.IniCollectionKey, section.ToIniValues().ToArray());
}
}
}
}
else
{
var value = field.GetValue(obj);
var keyName = string.IsNullOrWhiteSpace(attr.Key) ? field.Name : attr.Key;
if (attr.ClearSection)
{
WriteValue(iniFiles, attr.File, attr.Section, null, null);
}
//
// If this is a collection, we need to first remove all of its values from the INI.
//
var collection = value as IIniValuesCollection;
if (collection != null)
{
var section = ReadSection(iniFiles, attr.File, attr.Section);
var filteredSection = section
.Where(s => !s.StartsWith(collection.IniCollectionKey + (collection.IsArray ? "[" : "=")))
.ToArray();
WriteSection(iniFiles, attr.File, attr.Section, filteredSection);
}
if (!string.IsNullOrEmpty(attr.ConditionedOn))
{
var conditionField = obj.GetType().GetProperty(attr.ConditionedOn);
var conditionValue = conditionField.GetValue(obj);
if (conditionValue is bool && (bool)conditionValue == false)
{
// The condition value was not set to true, so clear this attribute instead of writing it
WriteValue(iniFiles, attr.File, attr.Section, keyName, null);
continue;
}
}
if (!string.IsNullOrEmpty(attr.ClearWhenOff))
{
var updateOffField = obj.GetType().GetProperty(attr.ClearWhenOff);
var updateOffValue = updateOffField.GetValue(obj);
if (updateOffValue is bool && (bool)updateOffValue == false)
{
// The attributed value was set to false, so clear this attribute instead of writing it
WriteValue(iniFiles, attr.File, attr.Section, keyName, null);
}
continue;
}
if (attr.WriteBoolValueIfNonEmpty)
{
if (value == null)
{
var keyValue = string.Empty;
if (attr.WriteBooleanAsInteger)
keyValue = "0";
else
keyValue = "False";
WriteValue(iniFiles, attr.File, attr.Section, keyName, keyValue);
}
else
{
if (value is string)
{
var strValue = value as string;
var keyValue = string.Empty;
if (attr.WriteBooleanAsInteger)
keyValue = string.IsNullOrEmpty(strValue) ? "0" : "1";
else
keyValue = string.IsNullOrEmpty(strValue) ? "False" : "True";
WriteValue(iniFiles, attr.File, attr.Section, keyName, keyValue);
}
else
{
// Not supported
throw new NotSupportedException("Unexpected IniFileEntry value type.");
}
}
}
else
{
if (collection != null)
{
if (collection.IsEnabled)
{
// Remove all the values in the collection with this key name
var section = ReadSection(iniFiles, attr.File, attr.Section);
var filteredSection = collection.IsArray
? section.Where(s => !s.StartsWith(keyName + "["))
: section.Where(s => !s.StartsWith(keyName + "="));
var result = filteredSection;
var objValue = attr.WriteIfNotValue;
if (objValue != null && collection is IIniValuesList valueList)
{
result = result.Concat(valueList.ToIniValues(objValue));
}
else
{
result = result.Concat(collection.ToIniValues());
}
WriteSection(iniFiles, attr.File, attr.Section, result?.ToArray());
}
}
else
{
//
// If this is a NullableValue, we need to check if it has a value.
//
if (value is INullableValue nullableValue && !nullableValue.HasValue)
{
// The attributed value does not have a value, so clear this attribute instead of writing it.
WriteValue(iniFiles, attr.File, attr.Section, keyName, null);
continue;
}
var strValue = StringUtils.GetPropertyValue(value, field, attr);
var objValue = attr.WriteIfNotValue;
if (objValue != null)
{
var strValue2 = StringUtils.GetPropertyValue(objValue, field, attr);
if (string.Equals(strValue, strValue2, StringComparison.OrdinalIgnoreCase))
{
// The attributed value is the same as the specified value, so clear this attribute instead of writing it.
WriteValue(iniFiles, attr.File, attr.Section, keyName, null);
continue;
}
}
if (attr.QuotedString == QuotedStringType.True)
{
// add the leading and trailing quotes, if not already have them.
if (!strValue.StartsWith("\""))
strValue = "\"" + strValue;
if (!strValue.EndsWith("\""))
strValue = strValue + "\"";
}
else if (attr.QuotedString == QuotedStringType.Remove)
{
// remove the leading and trailing quotes, if any
if (strValue.StartsWith("\""))
strValue = strValue.Substring(1);
if (strValue.EndsWith("\""))
strValue = strValue.Substring(0, strValue.Length - 1);
}
if (attr.Multiline)
{
// substitutes the NewLine string with "\n"
strValue = strValue.Replace(Environment.NewLine, attr.MultilineSeparator);
}
WriteValue(iniFiles, attr.File, attr.Section, keyName, strValue);
}
}
}
}
catch (Exception)
{
throw;
}
}
}
SaveFiles(iniFiles);
}
public string[] ReadSection(Enum iniFile, Enum section)
{
return ReadSection(iniFile, SectionNames[section]);
}
public string[] ReadSection(Enum iniFile, string sectionName)
{
var file = Path.Combine(this.BasePath, FileNames[iniFile]);
return IniFileUtils.ReadSection(file, sectionName);
}
public void WriteSection(Enum iniFile, Enum section, string[] values)
{
WriteSection(iniFile, SectionNames[section], values);
}
public void WriteSection(Enum iniFile, string sectionName, string[] values)
{
var file = Path.Combine(this.BasePath, FileNames[iniFile]);
var result = IniFileUtils.WriteSection(file, sectionName, values);
}
private string[] ReadCustomSectionNames(Dictionary<string, IniFile> iniFiles, Enum iniFile)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return new string[0];
return iniFiles[FileNames[iniFile]].Sections.Select(s => s.SectionName).Where(s => !SectionNames.ContainsValue(s)).ToArray();
}
private string[] ReadSection(Dictionary<string, IniFile> iniFiles, Enum iniFile, Enum section)
{
return ReadSection(iniFiles, iniFile, SectionNames[section]);
}
private string[] ReadSection(Dictionary<string, IniFile> iniFiles, Enum iniFile, string sectionName)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return new string[0];
return iniFiles[FileNames[iniFile]].GetSection(sectionName)?.KeysToStringArray() ?? new string[0];
}
private string ReadValue(Dictionary<string, IniFile> iniFiles, Enum iniFile, Enum section, string keyName)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return string.Empty;
return iniFiles[FileNames[iniFile]].GetKey(SectionNames[section], keyName)?.KeyValue ?? string.Empty;
}
private void WriteSection(Dictionary<string, IniFile> iniFiles, Enum iniFile, Enum section, string[] values)
{
WriteSection(iniFiles, iniFile, SectionNames[section], values);
}
private void WriteSection(Dictionary<string, IniFile> iniFiles, Enum iniFile, string sectionName, string[] values)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return;
iniFiles[FileNames[iniFile]].WriteSection(sectionName, values);
}
private void WriteValue(Dictionary<string, IniFile> iniFiles, Enum iniFile, Enum section, string keyName, string keyValue)
{
WriteValue(iniFiles, iniFile, SectionNames[section], keyName, keyValue);
}
private void WriteValue(Dictionary<string, IniFile> iniFiles, Enum iniFile, string sectionName, string keyName, string keyValue)
{
ReadFile(iniFiles, iniFile);
if (!iniFiles.ContainsKey(FileNames[iniFile]))
return;
iniFiles[FileNames[iniFile]].WriteKey(sectionName, keyName, keyValue);
}
private void ReadFile(Dictionary<string, IniFile> iniFiles, Enum iniFile)
{
if (!iniFiles.ContainsKey(FileNames[iniFile]))
{
var file = Path.Combine(this.BasePath, FileNames[iniFile]);
iniFiles.Add(FileNames[iniFile], IniFileUtils.ReadFromFile(file));
}
}
private void SaveFiles(Dictionary<string, IniFile> iniFiles)
{
foreach (var iniFile in iniFiles)
{
var file = Path.Combine(this.BasePath, iniFile.Key);
var result = IniFileUtils.SaveToFile(file, iniFile.Value);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more