mirror of
https://github.com/tribufu/ServerManagers
synced 2026-05-06 15:17:34 +00:00
source code checkin
This commit is contained in:
parent
5f8fb2c825
commit
7e57b72e35
675 changed files with 168433 additions and 0 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
164
src/ServerManager.Common/CommonConfig.Designer.cs
generated
Normal file
164
src/ServerManager.Common/CommonConfig.Designer.cs
generated
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/ServerManager.Common/CommonConfig.settings
Normal file
48
src/ServerManager.Common/CommonConfig.settings
Normal 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>
|
||||
16
src/ServerManager.Common/Constants.cs
Normal file
16
src/ServerManager.Common/Constants.cs
Normal 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";
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
292
src/ServerManager.Common/Controls/AnnotatedSlider.xaml
Normal file
292
src/ServerManager.Common/Controls/AnnotatedSlider.xaml
Normal 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>
|
||||
148
src/ServerManager.Common/Controls/AnnotatedSlider.xaml.cs
Normal file
148
src/ServerManager.Common/Controls/AnnotatedSlider.xaml.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/ServerManager.Common/Controls/DropDownButton.cs
Normal file
53
src/ServerManager.Common/Controls/DropDownButton.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/ServerManager.Common/Converters/EnumConverter.cs
Normal file
32
src/ServerManager.Common/Converters/EnumConverter.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/ServerManager.Common/Converters/EnumFlagsConverter.cs
Normal file
27
src/ServerManager.Common/Converters/EnumFlagsConverter.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/ServerManager.Common/Converters/IsNullValueConverter.cs
Normal file
23
src/ServerManager.Common/Converters/IsNullValueConverter.cs
Normal 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/ServerManager.Common/Converters/NullValueConverter.cs
Normal file
23
src/ServerManager.Common/Converters/NullValueConverter.cs
Normal 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/ServerManager.Common/Enums/ConsoleStatus.cs
Normal file
8
src/ServerManager.Common/Enums/ConsoleStatus.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
namespace ServerManagerTool.Common.Enums
|
||||
{
|
||||
public enum ConsoleStatus
|
||||
{
|
||||
Disconnected,
|
||||
Connected,
|
||||
};
|
||||
}
|
||||
12
src/ServerManager.Common/Enums/QuotedStringType.cs
Normal file
12
src/ServerManager.Common/Enums/QuotedStringType.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace ServerManagerTool.Common.Enums
|
||||
{
|
||||
[DefaultValue(False)]
|
||||
public enum QuotedStringType
|
||||
{
|
||||
False,
|
||||
True,
|
||||
Remove,
|
||||
}
|
||||
}
|
||||
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/ServerManager.Common/Extensions/IconExtension.cs
Normal file
47
src/ServerManager.Common/Extensions/IconExtension.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/ServerManager.Common/Interfaces/IAsyncDisposable.cs
Normal file
9
src/ServerManager.Common/Interfaces/IAsyncDisposable.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace ServerManagerTool.Common.Interfaces
|
||||
{
|
||||
public interface IAsyncDisposable
|
||||
{
|
||||
Task DisposeAsync();
|
||||
}
|
||||
}
|
||||
11
src/ServerManager.Common/Interfaces/IIniSectionCollection.cs
Normal file
11
src/ServerManager.Common/Interfaces/IIniSectionCollection.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
namespace ServerManagerTool.Common.Interfaces
|
||||
{
|
||||
public interface IIniSectionCollection
|
||||
{
|
||||
IIniValuesCollection[] Sections { get; }
|
||||
|
||||
void Add(string sectionName, string[] values);
|
||||
|
||||
void Update();
|
||||
}
|
||||
}
|
||||
14
src/ServerManager.Common/Interfaces/IIniValuesCollection.cs
Normal file
14
src/ServerManager.Common/Interfaces/IIniValuesCollection.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
9
src/ServerManager.Common/Interfaces/IIniValuesList.cs
Normal file
9
src/ServerManager.Common/Interfaces/IIniValuesList.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace ServerManagerTool.Common.Interfaces
|
||||
{
|
||||
public interface IIniValuesList
|
||||
{
|
||||
IEnumerable<string> ToIniValues(object excludeIfValue);
|
||||
}
|
||||
}
|
||||
11
src/ServerManager.Common/Interfaces/INullableValue.cs
Normal file
11
src/ServerManager.Common/Interfaces/INullableValue.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
namespace ServerManagerTool.Common.Interfaces
|
||||
{
|
||||
public interface INullableValue
|
||||
{
|
||||
bool HasValue { get; }
|
||||
|
||||
INullableValue Clone();
|
||||
|
||||
void SetValue(object value);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/ServerManager.Common/Lib/ActionQueue.cs
Normal file
53
src/ServerManager.Common/Lib/ActionQueue.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/ServerManager.Common/Lib/BindingProxy.cs
Normal file
21
src/ServerManager.Common/Lib/BindingProxy.cs
Normal 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
|
||||
}
|
||||
}
|
||||
32
src/ServerManager.Common/Lib/BrowserBehavior.cs
Normal file
32
src/ServerManager.Common/Lib/BrowserBehavior.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/ServerManager.Common/Lib/CommandListener.cs
Normal file
15
src/ServerManager.Common/Lib/CommandListener.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/ServerManager.Common/Lib/ConsoleCommand.cs
Normal file
18
src/ServerManager.Common/Lib/ConsoleCommand.cs
Normal 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];
|
||||
}
|
||||
}
|
||||
179
src/ServerManager.Common/Lib/ListViewSorting.cs
Normal file
179
src/ServerManager.Common/Lib/ListViewSorting.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/ServerManager.Common/Lib/NetworkAdapterEntry.cs
Normal file
31
src/ServerManager.Common/Lib/NetworkAdapterEntry.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
src/ServerManager.Common/Lib/PropertyChangeNotifier.cs
Normal file
136
src/ServerManager.Common/Lib/PropertyChangeNotifier.cs
Normal 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 i’ve 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
|
||||
}
|
||||
}
|
||||
84
src/ServerManager.Common/Lib/RelayCommand.cs
Normal file
84
src/ServerManager.Common/Lib/RelayCommand.cs
Normal 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
|
||||
}
|
||||
}
|
||||
24
src/ServerManager.Common/Lib/ServerUpdater.cs
Normal file
24
src/ServerManager.Common/Lib/ServerUpdater.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
196
src/ServerManager.Common/Lib/SteamCmdUpdater.cs
Normal file
196
src/ServerManager.Common/Lib/SteamCmdUpdater.cs
Normal 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
331
src/ServerManager.Common/Model/AggregateIniValue.cs
Normal file
331
src/ServerManager.Common/Model/AggregateIniValue.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
src/ServerManager.Common/Model/AggregateIniValueList.cs
Normal file
86
src/ServerManager.Common/Model/AggregateIniValueList.cs
Normal 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()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
56
src/ServerManager.Common/Model/ComboBoxItem.cs
Normal file
56
src/ServerManager.Common/Model/ComboBoxItem.cs
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/ServerManager.Common/Model/ComboBoxItemList.cs
Normal file
11
src/ServerManager.Common/Model/ComboBoxItemList.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Specialized;
|
||||
|
||||
namespace ServerManagerTool.Common.Model
|
||||
{
|
||||
public class ComboBoxItemList : SortableObservableCollection<ComboBoxItem>
|
||||
{
|
||||
public ComboBoxItemList()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/ServerManager.Common/Model/CustomItem.cs
Normal file
55
src/ServerManager.Common/Model/CustomItem.cs
Normal 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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
112
src/ServerManager.Common/Model/CustomSection.cs
Normal file
112
src/ServerManager.Common/Model/CustomSection.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/ServerManager.Common/Model/CustomSectionList.cs
Normal file
69
src/ServerManager.Common/Model/CustomSectionList.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/ServerManager.Common/Model/FloatIniValueArray.cs
Normal file
47
src/ServerManager.Common/Model/FloatIniValueArray.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/ServerManager.Common/Model/FloatIniValueList.cs
Normal file
41
src/ServerManager.Common/Model/FloatIniValueList.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/ServerManager.Common/Model/IniValueArray.cs
Normal file
6
src/ServerManager.Common/Model/IniValueArray.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
namespace ServerManagerTool.Common.Model
|
||||
{
|
||||
public class IniValueArray
|
||||
{
|
||||
}
|
||||
}
|
||||
138
src/ServerManager.Common/Model/IniValueList.cs
Normal file
138
src/ServerManager.Common/Model/IniValueList.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/ServerManager.Common/Model/IntegerIniValueList.cs
Normal file
41
src/ServerManager.Common/Model/IntegerIniValueList.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/ServerManager.Common/Model/PlayerUserItem.cs
Normal file
45
src/ServerManager.Common/Model/PlayerUserItem.cs
Normal 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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
93
src/ServerManager.Common/Model/PlayerUserList.cs
Normal file
93
src/ServerManager.Common/Model/PlayerUserList.cs
Normal 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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/ServerManager.Common/Model/ProcessorAffinityItem.cs
Normal file
29
src/ServerManager.Common/Model/ProcessorAffinityItem.cs
Normal 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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/ServerManager.Common/Model/ProcessorAffinityList.cs
Normal file
67
src/ServerManager.Common/Model/ProcessorAffinityList.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/ServerManager.Common/Model/PublishedFileDetail.cs
Normal file
55
src/ServerManager.Common/Model/PublishedFileDetail.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace ServerManagerTool.Common.Model
|
||||
{
|
||||
public class PublishedFileDetailsResult
|
||||
{
|
||||
public PublishedFileDetailsResponse response { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/ServerManager.Common/Model/SteamCmdAppManifest.cs
Normal file
11
src/ServerManager.Common/Model/SteamCmdAppManifest.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
23
src/ServerManager.Common/Model/SteamCmdAppWorkshop.cs
Normal file
23
src/ServerManager.Common/Model/SteamCmdAppWorkshop.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace ServerManagerTool.Common.Model
|
||||
{
|
||||
public class SteamCmdManifestUserConfig
|
||||
{
|
||||
public string betakey { get; set; }
|
||||
}
|
||||
}
|
||||
111
src/ServerManager.Common/Model/SteamCmdWorkshopDetailsResult.cs
Normal file
111
src/ServerManager.Common/Model/SteamCmdWorkshopDetailsResult.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
23
src/ServerManager.Common/Model/SteamServerDetail.cs
Normal file
23
src/ServerManager.Common/Model/SteamServerDetail.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
11
src/ServerManager.Common/Model/SteamServerDetailResponse.cs
Normal file
11
src/ServerManager.Common/Model/SteamServerDetailResponse.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace ServerManagerTool.Common.Model
|
||||
{
|
||||
public class SteamServerDetailResult
|
||||
{
|
||||
public SteamServerDetailResponse response { get; set; }
|
||||
}
|
||||
}
|
||||
25
src/ServerManager.Common/Model/SteamUserDetail.cs
Normal file
25
src/ServerManager.Common/Model/SteamUserDetail.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace ServerManagerTool.Common.Model
|
||||
{
|
||||
public class SteamUserDetailResponse
|
||||
{
|
||||
public List<SteamUserDetail> players { get; set; }
|
||||
}
|
||||
}
|
||||
7
src/ServerManager.Common/Model/SteamUserDetailResult.cs
Normal file
7
src/ServerManager.Common/Model/SteamUserDetailResult.cs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
namespace ServerManagerTool.Common.Model
|
||||
{
|
||||
public class SteamUserDetailResult
|
||||
{
|
||||
public SteamUserDetailResponse response { get; set; }
|
||||
}
|
||||
}
|
||||
39
src/ServerManager.Common/Model/StringIniValueList.cs
Normal file
39
src/ServerManager.Common/Model/StringIniValueList.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/ServerManager.Common/Model/VersionFeed.cs
Normal file
16
src/ServerManager.Common/Model/VersionFeed.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
17
src/ServerManager.Common/Model/VersionFeedEntry.cs
Normal file
17
src/ServerManager.Common/Model/VersionFeedEntry.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
97
src/ServerManager.Common/Model/WorkshopFileDetail.cs
Normal file
97
src/ServerManager.Common/Model/WorkshopFileDetail.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
32
src/ServerManager.Common/Model/WorkshopFileDetailResponse.cs
Normal file
32
src/ServerManager.Common/Model/WorkshopFileDetailResponse.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace ServerManagerTool.Common.Model
|
||||
{
|
||||
public class WorkshopFileDetailResult
|
||||
{
|
||||
public WorkshopFileDetailResponse response { get; set; }
|
||||
}
|
||||
}
|
||||
107
src/ServerManager.Common/Model/WorkshopFileItem.cs
Normal file
107
src/ServerManager.Common/Model/WorkshopFileItem.cs
Normal 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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/ServerManager.Common/Model/WorkshopFileList.cs
Normal file
55
src/ServerManager.Common/Model/WorkshopFileList.cs
Normal 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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/ServerManager.Common/Properties/AssemblyInfo.cs
Normal file
35
src/ServerManager.Common/Properties/AssemblyInfo.cs
Normal 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")]
|
||||
461
src/ServerManager.Common/Serialization/BaseSystemIniFile.cs
Normal file
461
src/ServerManager.Common/Serialization/BaseSystemIniFile.cs
Normal 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
Loading…
Add table
Add a link
Reference in a new issue