mirror of
https://github.com/Stone-Red-Code/DesktopMagic.git
synced 2026-09-04 00:46:12 +02:00
Add web plugin creation flow and settings bridge to WebPluginWindow
This commit is contained in:
@@ -16,9 +16,9 @@
|
|||||||
WindowCornerPreference="Round"
|
WindowCornerPreference="Round"
|
||||||
WindowBackdropType="Tabbed"
|
WindowBackdropType="Tabbed"
|
||||||
Height="230"
|
Height="230"
|
||||||
Width="300"
|
Width="320"
|
||||||
MinHeight="160"
|
MinHeight="160"
|
||||||
MinWidth="300"
|
MinWidth="320"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
ExtendsContentIntoTitleBar="True">
|
ExtendsContentIntoTitleBar="True">
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -48,7 +48,8 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="5">
|
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="5">
|
||||||
<Button x:Name="okButton" Content="{DynamicResource ok }" HorizontalAlignment="Left" Margin="0 0 5 0" VerticalAlignment="Top" Width="100" Click="OkButton_Click" Cursor="Hand" />
|
<Button x:Name="okButton" Content=".NET Plugin" HorizontalAlignment="Left" Margin="0 0 5 0" VerticalAlignment="Top" Width="100" Click="DotNetButton_Click" Cursor="Hand" />
|
||||||
|
<Button x:Name="webPluginButton" Content="Web Plugin" HorizontalAlignment="Left" Margin="0 0 5 0" VerticalAlignment="Top" Width="100" Click="WebPluginButton_Click" Cursor="Hand" />
|
||||||
<Button x:Name="cancelButton" Content="{DynamicResource cancel }" HorizontalAlignment="Left" Margin="0 0 0 0" VerticalAlignment="Top" Width="100" Click="CancelButton_Click" />
|
<Button x:Name="cancelButton" Content="{DynamicResource cancel }" HorizontalAlignment="Left" Margin="0 0 0 0" VerticalAlignment="Top" Width="100" Click="CancelButton_Click" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ public partial class CreatePluginDialog : Wpf.Ui.Controls.FluentWindow
|
|||||||
set => textBox.Text = value;
|
set => textBox.Text = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsWebPlugin { get; private set; }
|
||||||
|
|
||||||
public CreatePluginDialog()
|
public CreatePluginDialog()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -17,8 +19,15 @@ public partial class CreatePluginDialog : Wpf.Ui.Controls.FluentWindow
|
|||||||
Resources.MergedDictionaries.Add(App.LanguageDictionary);
|
Resources.MergedDictionaries.Add(App.LanguageDictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OkButton_Click(object sender, RoutedEventArgs e)
|
private void DotNetButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
IsWebPlugin = false;
|
||||||
|
DialogResult = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WebPluginButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
IsWebPlugin = true;
|
||||||
DialogResult = true;
|
DialogResult = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -486,6 +486,15 @@ public partial class PluginManager : Page
|
|||||||
string pluginMetadataPath = Path.Combine(pluginPath, "metadata.json");
|
string pluginMetadataPath = Path.Combine(pluginPath, "metadata.json");
|
||||||
await File.WriteAllTextAsync(pluginMetadataPath, JsonSerializer.Serialize(pluginMetadata));
|
await File.WriteAllTextAsync(pluginMetadataPath, JsonSerializer.Serialize(pluginMetadata));
|
||||||
|
|
||||||
|
if (inputDialog.IsWebPlugin)
|
||||||
|
{
|
||||||
|
await CreateNewWebPlugin(pluginPath, pluginName);
|
||||||
|
changed = true;
|
||||||
|
await InitializePluginManager();
|
||||||
|
pluginManagerDataContext.IsLoading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
App.Logger.LogInfo($"Creating .NET project at: {pluginProjectPath}", source: "PluginManager");
|
App.Logger.LogInfo($"Creating .NET project at: {pluginProjectPath}", source: "PluginManager");
|
||||||
string cmd = $"new classlib -n {pluginSafeName} -o {pluginProjectPath} -f net8.0 --target-framework-override net8.0-windows7";
|
string cmd = $"new classlib -n {pluginSafeName} -o {pluginProjectPath} -f net8.0 --target-framework-override net8.0-windows7";
|
||||||
Process process = Process.Start("dotnet", cmd);
|
Process process = Process.Start("dotnet", cmd);
|
||||||
@@ -608,6 +617,49 @@ public class {pluginSafeName}Plugin : Plugin
|
|||||||
pluginManagerDataContext.IsLoading = false;
|
pluginManagerDataContext.IsLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CreateNewWebPlugin(string pluginPath, string pluginName)
|
||||||
|
{
|
||||||
|
App.Logger.LogInfo($"Creating web plugin at: {pluginPath}", source: "PluginManager");
|
||||||
|
|
||||||
|
string mainHtml = $@"<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset=""utf-8"">
|
||||||
|
<style>
|
||||||
|
body {{ margin: 0; padding: 16px; font-family: var(--font-family); }}
|
||||||
|
h1 {{ color: var(--primary-color); }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 id=""greeting"">{pluginName}</h1>
|
||||||
|
<script>
|
||||||
|
function render() {{
|
||||||
|
const s = window.desktopMagic.getSettings();
|
||||||
|
document.getElementById('greeting').innerHTML = s.message;
|
||||||
|
document.getElementById('greeting').style.color = s.color;
|
||||||
|
document.getElementById('greeting').style.fontWeight = s.bold ? 'bold' : 'normal';
|
||||||
|
}}
|
||||||
|
|
||||||
|
window.desktopMagic.onSettingChanged = (id, value) => render();
|
||||||
|
render();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>";
|
||||||
|
|
||||||
|
var settings = new List<Dictionary<string, object?>>
|
||||||
|
{
|
||||||
|
new() { ["id"] = "message", ["name"] = "Greeting Message", ["type"] = "textbox", ["default"] = "Hello, World!" },
|
||||||
|
new() { ["id"] = "bold", ["name"] = "Bold Text", ["type"] = "checkbox", ["default"] = true },
|
||||||
|
new() { ["id"] = "color", ["name"] = "Text Color", ["type"] = "colorpicker", ["default"] = "#FF5722" }
|
||||||
|
};
|
||||||
|
|
||||||
|
string settingsJson = JsonSerializer.Serialize(settings, new JsonSerializerOptions { WriteIndented = true });
|
||||||
|
await File.WriteAllTextAsync(Path.Combine(pluginPath, "settings.json"), settingsJson);
|
||||||
|
await File.WriteAllTextAsync(Path.Combine(pluginPath, "main.html"), mainHtml);
|
||||||
|
|
||||||
|
App.Logger.LogInfo($"Successfully created web plugin: {pluginName}", source: "PluginManager");
|
||||||
|
}
|
||||||
|
|
||||||
private async void LogInButton_Click(object sender, RoutedEventArgs e)
|
private async void LogInButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (pluginManagerDataContext.IsAuthenticated)
|
if (pluginManagerDataContext.IsAuthenticated)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using DesktopMagic.Api.Settings;
|
||||||
using DesktopMagic.Helpers;
|
using DesktopMagic.Helpers;
|
||||||
using DesktopMagic.Plugins;
|
using DesktopMagic.Plugins;
|
||||||
using DesktopMagic.Settings;
|
using DesktopMagic.Settings;
|
||||||
@@ -5,7 +6,10 @@ using DesktopMagic.Settings;
|
|||||||
using Microsoft.Web.WebView2.Core;
|
using Microsoft.Web.WebView2.Core;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
@@ -193,6 +197,8 @@ public partial class WebPluginWindow : Window, IPluginWindow
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
LoadWebPluginSettings();
|
||||||
|
|
||||||
string userDataFolder = Path.Combine(Path.GetTempPath(), "DesktopMagic", "WebView2", PluginMetadata.Id.ToString());
|
string userDataFolder = Path.Combine(Path.GetTempPath(), "DesktopMagic", "WebView2", PluginMetadata.Id.ToString());
|
||||||
CoreWebView2Environment environment = await CoreWebView2Environment.CreateAsync(null, userDataFolder);
|
CoreWebView2Environment environment = await CoreWebView2Environment.CreateAsync(null, userDataFolder);
|
||||||
await webView.EnsureCoreWebView2Async(environment);
|
await webView.EnsureCoreWebView2Async(environment);
|
||||||
@@ -202,6 +208,8 @@ public partial class WebPluginWindow : Window, IPluginWindow
|
|||||||
webView.CoreWebView2.Settings.IsStatusBarEnabled = false;
|
webView.CoreWebView2.Settings.IsStatusBarEnabled = false;
|
||||||
webView.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = true;
|
webView.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = true;
|
||||||
|
|
||||||
|
_ = await webView.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(GetSettingsBridgeScript());
|
||||||
|
|
||||||
string htmlUri = new Uri(htmlPath).AbsoluteUri;
|
string htmlUri = new Uri(htmlPath).AbsoluteUri;
|
||||||
webView.Source = new Uri(htmlUri);
|
webView.Source = new Uri(htmlUri);
|
||||||
|
|
||||||
@@ -251,6 +259,268 @@ public partial class WebPluginWindow : Window, IPluginWindow
|
|||||||
|
|
||||||
private void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
|
private void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
|
||||||
{
|
{
|
||||||
webView.CoreWebView2.DOMContentLoaded += (_, _) => ThemeChanged();
|
webView.CoreWebView2.DOMContentLoaded += (_, _) =>
|
||||||
|
{
|
||||||
|
ThemeChanged();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadWebPluginSettings()
|
||||||
|
{
|
||||||
|
string settingsPath = Path.Combine(PluginFolderPath, "settings.json");
|
||||||
|
if (!File.Exists(settingsPath))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string json = File.ReadAllText(settingsPath);
|
||||||
|
using JsonDocument doc = JsonDocument.Parse(json);
|
||||||
|
JsonElement root = doc.RootElement;
|
||||||
|
|
||||||
|
if (root.ValueKind != JsonValueKind.Array)
|
||||||
|
{
|
||||||
|
App.Logger.LogWarn($"\"{PluginMetadata.Name}\" - settings.json must be a JSON array", source: "WebPlugin");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SettingElement> settingElements = [];
|
||||||
|
int orderIndex = 0;
|
||||||
|
|
||||||
|
foreach (JsonElement element in root.EnumerateArray())
|
||||||
|
{
|
||||||
|
string id = element.GetProperty("id").GetString() ?? $"setting-{orderIndex}";
|
||||||
|
string name = element.TryGetProperty("name", out JsonElement nameEl) ? nameEl.GetString() ?? id : id;
|
||||||
|
string type = element.TryGetProperty("type", out JsonElement typeEl) ? typeEl.GetString() ?? "textbox" : "textbox";
|
||||||
|
|
||||||
|
Setting? setting = CreateSetting(type, element);
|
||||||
|
if (setting is null)
|
||||||
|
{
|
||||||
|
App.Logger.LogWarn($"\"{PluginMetadata.Name}\" - Unknown setting type \"{type}\" for \"{id}\"", source: "WebPlugin");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingElement settingElement = new(setting, id, name, orderIndex);
|
||||||
|
|
||||||
|
if (settings.Settings.Exists(e => e.Id == id))
|
||||||
|
{
|
||||||
|
SettingElement saved = settings.Settings.First(e => e.Id == id);
|
||||||
|
settingElement.JsonValue = saved.JsonValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string capturedId = id;
|
||||||
|
if (setting is Button button)
|
||||||
|
{
|
||||||
|
button.OnClick += () =>
|
||||||
|
{
|
||||||
|
_ = webView.Dispatcher.InvokeAsync(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ = await webView.ExecuteScriptAsync($"window.desktopMagic?.onClick?.({JsonSerializer.Serialize(capturedId)})");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setting.OnValueChanged += () =>
|
||||||
|
{
|
||||||
|
_ = webView.Dispatcher.InvokeAsync(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await NotifySettingChange(capturedId, setting);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
settingElements.Add(settingElement);
|
||||||
|
orderIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Settings = [.. settingElements.OrderBy(x => x.OrderIndex)];
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
App.Logger.LogWarn($"\"{PluginMetadata.Name}\" - Failed to load settings from settings.json: {ex.Message}", source: "WebPlugin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetSettingsBridgeScript()
|
||||||
|
{
|
||||||
|
string settingsJson = SerializeSettingsToJson();
|
||||||
|
|
||||||
|
return $@"
|
||||||
|
(function() {{
|
||||||
|
window.desktopMagic = {{}};
|
||||||
|
window.desktopMagic._settings = {settingsJson};
|
||||||
|
|
||||||
|
window.desktopMagic.getSettings = function() {{
|
||||||
|
return JSON.parse(JSON.stringify(window.desktopMagic._settings));
|
||||||
|
}};
|
||||||
|
|
||||||
|
window.desktopMagic.getSetting = function(id) {{
|
||||||
|
return window.desktopMagic._settings ? window.desktopMagic._settings[id] : undefined;
|
||||||
|
}};
|
||||||
|
|
||||||
|
window.desktopMagic.onSettingChanged = null;
|
||||||
|
window.desktopMagic.onButtonClick = null;
|
||||||
|
|
||||||
|
window.desktopMagic.dispatchSettingChanged = function(id, value) {{
|
||||||
|
if (window.desktopMagic._settings) {{
|
||||||
|
window.desktopMagic._settings[id] = value;
|
||||||
|
}}
|
||||||
|
if (typeof window.desktopMagic.onSettingChanged === 'function') {{
|
||||||
|
window.desktopMagic.onSettingChanged(id, value);
|
||||||
|
}}
|
||||||
|
}};
|
||||||
|
|
||||||
|
window.desktopMagic.onClick = function(id) {{
|
||||||
|
if (typeof window.desktopMagic.onButtonClick === 'function') {{
|
||||||
|
window.desktopMagic.onButtonClick(id);
|
||||||
|
}}
|
||||||
|
}};
|
||||||
|
}})();
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
|
private async System.Threading.Tasks.Task NotifySettingChange(string id, Setting setting)
|
||||||
|
{
|
||||||
|
object? value = GetSettingValue(setting);
|
||||||
|
string serializedValue = JsonSerializer.Serialize(value);
|
||||||
|
string serializedId = JsonSerializer.Serialize(id);
|
||||||
|
_ = await webView.ExecuteScriptAsync($"window.desktopMagic?.dispatchSettingChanged?.({serializedId}, {serializedValue})");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SerializeSettingsToJson()
|
||||||
|
{
|
||||||
|
Dictionary<string, object?> dict = [];
|
||||||
|
foreach (SettingElement element in settings.Settings)
|
||||||
|
{
|
||||||
|
dict[element.Id] = GetSettingValue(element.Input);
|
||||||
|
}
|
||||||
|
return JsonSerializer.Serialize(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object? GetSettingValue(Setting setting)
|
||||||
|
{
|
||||||
|
return setting switch
|
||||||
|
{
|
||||||
|
TextBox tb => tb.Value,
|
||||||
|
CheckBox cb => cb.Value,
|
||||||
|
Slider sl => sl.Value,
|
||||||
|
IntegerUpDown iud => iud.Value,
|
||||||
|
ComboBox cb => cb.Value,
|
||||||
|
ColorPicker cp => $"#{cp.Value.A:X2}{cp.Value.R:X2}{cp.Value.G:X2}{cp.Value.B:X2}",
|
||||||
|
Button btn => btn.Value,
|
||||||
|
Label lbl => lbl.Value,
|
||||||
|
FileSelector fs => fs.Value,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Setting? CreateSetting(string type, JsonElement element)
|
||||||
|
{
|
||||||
|
return type.ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
"textbox" => new TextBox(
|
||||||
|
element.TryGetProperty("default", out JsonElement tbDefault) ? tbDefault.GetString() ?? "" : ""),
|
||||||
|
|
||||||
|
"checkbox" => new CheckBox(
|
||||||
|
element.TryGetProperty("default", out JsonElement cbDefault) && cbDefault.ValueKind == JsonValueKind.True),
|
||||||
|
|
||||||
|
"slider" => new Slider(
|
||||||
|
element.TryGetProperty("min", out JsonElement slMin) ? slMin.GetDouble() : 0,
|
||||||
|
element.TryGetProperty("max", out JsonElement slMax) ? slMax.GetDouble() : 100,
|
||||||
|
element.TryGetProperty("default", out JsonElement slDefault) ? slDefault.GetDouble() : 0),
|
||||||
|
|
||||||
|
"integer" => new IntegerUpDown(
|
||||||
|
element.TryGetProperty("min", out JsonElement intMin) ? intMin.GetInt32() : 0,
|
||||||
|
element.TryGetProperty("max", out JsonElement intMax) ? intMax.GetInt32() : 100,
|
||||||
|
element.TryGetProperty("default", out JsonElement intDefault) ? intDefault.GetInt32() : 0),
|
||||||
|
|
||||||
|
"combobox" => CreateComboBox(element),
|
||||||
|
|
||||||
|
"colorpicker" => new ColorPicker(
|
||||||
|
element.TryGetProperty("default", out JsonElement cpDefault)
|
||||||
|
? ParseHexColor(cpDefault.GetString() ?? "#FFFFFFFF")
|
||||||
|
: System.Drawing.Color.White),
|
||||||
|
|
||||||
|
"button" => new Button(
|
||||||
|
element.TryGetProperty("default", out JsonElement btnDefault) ? btnDefault.GetString() ?? "" : ""),
|
||||||
|
|
||||||
|
"label" => new Label(
|
||||||
|
element.TryGetProperty("default", out JsonElement lblDefault) ? lblDefault.GetString() ?? "" : "",
|
||||||
|
element.TryGetProperty("bold", out JsonElement boldEl) && boldEl.ValueKind == JsonValueKind.True),
|
||||||
|
|
||||||
|
"file" => new FileSelector(
|
||||||
|
element.TryGetProperty("default", out JsonElement fsDefault) ? fsDefault.GetString() ?? "" : "",
|
||||||
|
element.TryGetProperty("filter", out JsonElement filterEl) ? filterEl.GetString() ?? "All Files|*.*" : "All Files|*.*",
|
||||||
|
element.TryGetProperty("title", out JsonElement titleEl) ? titleEl.GetString() ?? "Select File" : "Select File",
|
||||||
|
element.TryGetProperty("selectFolder", out JsonElement sfEl) && sfEl.ValueKind == JsonValueKind.True),
|
||||||
|
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ComboBox CreateComboBox(JsonElement element)
|
||||||
|
{
|
||||||
|
List<string> items = [];
|
||||||
|
if (element.TryGetProperty("items", out JsonElement itemsEl) && itemsEl.ValueKind == JsonValueKind.Array)
|
||||||
|
{
|
||||||
|
foreach (JsonElement item in itemsEl.EnumerateArray())
|
||||||
|
{
|
||||||
|
items.Add(item.GetString() ?? "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox comboBox = new([.. items]);
|
||||||
|
|
||||||
|
if (element.TryGetProperty("default", out JsonElement cbDefault))
|
||||||
|
{
|
||||||
|
string defaultVal = cbDefault.GetString() ?? "";
|
||||||
|
if (!string.IsNullOrEmpty(defaultVal) && items.Contains(defaultVal))
|
||||||
|
{
|
||||||
|
comboBox.Value = defaultVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return comboBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static System.Drawing.Color ParseHexColor(string hex)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(hex))
|
||||||
|
{
|
||||||
|
return System.Drawing.Color.White;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hex.StartsWith("#"))
|
||||||
|
{
|
||||||
|
hex = hex[1..];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hex.Length == 6)
|
||||||
|
{
|
||||||
|
hex = "FF" + hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hex.Length == 8 &&
|
||||||
|
byte.TryParse(hex[..2], System.Globalization.NumberStyles.HexNumber, null, out byte a) &&
|
||||||
|
byte.TryParse(hex[2..4], System.Globalization.NumberStyles.HexNumber, null, out byte r) &&
|
||||||
|
byte.TryParse(hex[4..6], System.Globalization.NumberStyles.HexNumber, null, out byte g) &&
|
||||||
|
byte.TryParse(hex[6..8], System.Globalization.NumberStyles.HexNumber, null, out byte b))
|
||||||
|
{
|
||||||
|
return System.Drawing.Color.FromArgb(a, r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return System.Drawing.Color.White;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user