check point
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using Inspectron.Settings.Attributes;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
|
||||
namespace Inspectron.Settings.Windows.Configuration;
|
||||
|
||||
public class DefaultControlFactory : IControlFactory
|
||||
{
|
||||
public virtual Control CreateControl(string name, string description, PropertyInfo propertyInfo,
|
||||
object initialValue, Action<object> valueChangedCallback, OptionsWindow optionsWindow)
|
||||
{
|
||||
var type = propertyInfo.PropertyType;
|
||||
|
||||
// Check for SettingDescriptionAttribute
|
||||
var settingDescriptionAttribute = propertyInfo.GetCustomAttribute<SettingDescriptionAttribute>();
|
||||
string settingDescription = settingDescriptionAttribute?.Description;
|
||||
|
||||
// Check for SettingPreviewAttribute
|
||||
var previewAttribute = propertyInfo.GetCustomAttribute<SettingPreviewAttribute>();
|
||||
Label previewLabel = null;
|
||||
Func<object, string> getPreview = null;
|
||||
|
||||
if (previewAttribute != null)
|
||||
{
|
||||
var method = previewAttribute.PreviewClass.GetMethod(previewAttribute.PreviewFunction, BindingFlags.Public | BindingFlags.Static);
|
||||
getPreview = value => (string)method.Invoke(null, new[] { value });
|
||||
previewLabel = new Label
|
||||
{
|
||||
AutoSize = true,
|
||||
Padding = new Padding(15, 0, 0, 0),
|
||||
Font = new System.Drawing.Font("Segoe UI", 10, System.Drawing.FontStyle.Italic),
|
||||
Text = getPreview(initialValue)
|
||||
};
|
||||
}
|
||||
|
||||
if (type == typeof(string) && name.EndsWith("Path", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return CreatePathControl(name, description, initialValue, valueChangedCallback, optionsWindow, settingDescription, previewLabel, getPreview);
|
||||
}
|
||||
else if (type == typeof(string))
|
||||
{
|
||||
return CreateStringControl(description, initialValue, valueChangedCallback, settingDescription, previewLabel, getPreview);
|
||||
}
|
||||
else if (type == typeof(int))
|
||||
{
|
||||
return CreateIntControl(description, initialValue, valueChangedCallback, settingDescription, previewLabel, getPreview);
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
return CreateBoolControl(description, initialValue, valueChangedCallback, settingDescription, previewLabel, getPreview);
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
return CreateEnumControl(description, type, initialValue, valueChangedCallback, settingDescription, previewLabel, getPreview);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Label { Text = $"Unsupported type: {type.Name}", AutoSize = true };
|
||||
}
|
||||
}
|
||||
|
||||
private Control CreatePathControl(string name, string description, object initialValue, Action<object> valueChangedCallback,
|
||||
OptionsWindow optionsWindow, string settingDescription, Label previewLabel, Func<object, string> getPreview)
|
||||
{
|
||||
var textBox = new TextBox { Text = initialValue as string, Width = 400 };
|
||||
var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
|
||||
var browseButton = new Button { Text = "Browse", AutoSize = true };
|
||||
|
||||
browseButton.Click += (s, e) =>
|
||||
{
|
||||
using (var dialog = new CommonOpenFileDialog { IsFolderPicker = true })
|
||||
{
|
||||
if (dialog.ShowDialog(optionsWindow.Handle) == CommonFileDialogResult.Ok)
|
||||
{
|
||||
textBox.Text = dialog.FileName;
|
||||
valueChangedCallback(dialog.FileName);
|
||||
if (previewLabel != null && getPreview != null)
|
||||
previewLabel.Text = getPreview(dialog.FileName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
textBox.TextChanged += (s, e) =>
|
||||
{
|
||||
valueChangedCallback(textBox.Text);
|
||||
if (previewLabel != null && getPreview != null)
|
||||
previewLabel.Text = getPreview(textBox.Text);
|
||||
};
|
||||
|
||||
return CreateOuterPanel(settingDescription, previewLabel, label, textBox, browseButton);
|
||||
}
|
||||
|
||||
private Control CreateStringControl(string description, object initialValue, Action<object> valueChangedCallback,
|
||||
string settingDescription, Label previewLabel, Func<object, string> getPreview)
|
||||
{
|
||||
var textBox = new TextBox { Text = initialValue as string, Width = 400 };
|
||||
var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
|
||||
|
||||
textBox.TextChanged += (s, e) =>
|
||||
{
|
||||
valueChangedCallback(textBox.Text);
|
||||
if (previewLabel != null && getPreview != null)
|
||||
previewLabel.Text = getPreview(textBox.Text);
|
||||
};
|
||||
|
||||
return CreateOuterPanel(settingDescription, previewLabel, label, textBox);
|
||||
}
|
||||
|
||||
private Control CreateIntControl(string description, object initialValue, Action<object> valueChangedCallback,
|
||||
string settingDescription, Label previewLabel, Func<object, string> getPreview)
|
||||
{
|
||||
var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
|
||||
var numericUpDown = new NumericUpDown { Minimum = 0, Maximum = 99999999999, Value = Convert.ToDecimal(initialValue), Width = 200 };
|
||||
|
||||
numericUpDown.ValueChanged += (s, e) =>
|
||||
{
|
||||
valueChangedCallback(Convert.ToInt32(numericUpDown.Value));
|
||||
if (previewLabel != null && getPreview != null)
|
||||
previewLabel.Text = getPreview(Convert.ToInt32(numericUpDown.Value));
|
||||
};
|
||||
|
||||
return CreateOuterPanel(settingDescription, previewLabel, label, numericUpDown);
|
||||
}
|
||||
|
||||
private Control CreateBoolControl(string description, object initialValue, Action<object> valueChangedCallback,
|
||||
string settingDescription, Label previewLabel, Func<object, string> getPreview)
|
||||
{
|
||||
var checkBox = new CheckBox { Text = description, Checked = (bool)initialValue, AutoSize = true };
|
||||
|
||||
checkBox.CheckedChanged += (s, e) =>
|
||||
{
|
||||
valueChangedCallback(checkBox.Checked);
|
||||
if (previewLabel != null && getPreview != null)
|
||||
previewLabel.Text = getPreview(checkBox.Checked);
|
||||
};
|
||||
|
||||
return CreateOuterPanel(settingDescription, previewLabel, checkBox);
|
||||
}
|
||||
|
||||
private Control CreateEnumControl(string description, Type enumType, object initialValue, Action<object> valueChangedCallback,
|
||||
string settingDescription, Label previewLabel, Func<object, string> getPreview)
|
||||
{
|
||||
var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
|
||||
var comboBox = new ComboBox { DropDownStyle = ComboBoxStyle.DropDownList, Width = 200 };
|
||||
|
||||
// Populate ComboBox with enum values
|
||||
foreach (var value in Enum.GetValues(enumType))
|
||||
{
|
||||
comboBox.Items.Add(value);
|
||||
}
|
||||
|
||||
// Set initial value
|
||||
comboBox.SelectedItem = initialValue;
|
||||
|
||||
comboBox.SelectedIndexChanged += (s, e) =>
|
||||
{
|
||||
valueChangedCallback(comboBox.SelectedItem);
|
||||
if (previewLabel != null && getPreview != null)
|
||||
previewLabel.Text = getPreview(comboBox.SelectedItem);
|
||||
};
|
||||
|
||||
return CreateOuterPanel(settingDescription, previewLabel, label, comboBox);
|
||||
}
|
||||
|
||||
private Control CreateOuterPanel(string settingDescription, Label previewLabel, params Control[] controls)
|
||||
{
|
||||
var outerPanel = new FlowLayoutPanel { FlowDirection = FlowDirection.TopDown, AutoSize = true, Margin = new Padding(0, 25, 0, 0) };
|
||||
|
||||
if (!string.IsNullOrEmpty(settingDescription))
|
||||
{
|
||||
var descriptionLabel = new Label { Text = settingDescription, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
|
||||
outerPanel.Controls.Add(descriptionLabel);
|
||||
}
|
||||
|
||||
foreach (var control in controls)
|
||||
{
|
||||
outerPanel.Controls.Add(control);
|
||||
}
|
||||
|
||||
if (previewLabel != null)
|
||||
outerPanel.Controls.Add(previewLabel);
|
||||
|
||||
return outerPanel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Inspectron.Settings.Windows.Configuration;
|
||||
|
||||
public interface IControlFactory
|
||||
{
|
||||
Control CreateControl(string name, string description, PropertyInfo propertyInfo, object initialValue,
|
||||
Action<object> valueChangedCallback, OptionsWindow optionsWindow);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace Inspectron.Settings.Windows.Configuration;
|
||||
|
||||
internal class OptionSetting
|
||||
{
|
||||
public object Owner { get; set; }
|
||||
public PropertyInfo Property { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string TreePath { get; set; }
|
||||
public object Value { get; set; } // Temporary value until OK is pressed
|
||||
}
|
||||
69
framework/Inspectron.Settings.Windows/Configuration/OptionsWindow.Designer.cs
generated
Normal file
69
framework/Inspectron.Settings.Windows/Configuration/OptionsWindow.Designer.cs
generated
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Inspectron.Settings.Windows.Configuration;
|
||||
|
||||
public partial class OptionsWindow
|
||||
{
|
||||
private TreeView treeViewCategories;
|
||||
private FlowLayoutPanel flowLayoutPanelSettings;
|
||||
private Button buttonOK;
|
||||
private Button buttonCancel;
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
treeViewCategories = new TreeView();
|
||||
flowLayoutPanelSettings = new FlowLayoutPanel();
|
||||
buttonOK = new Button();
|
||||
buttonCancel = new Button();
|
||||
SuspendLayout();
|
||||
//
|
||||
// treeViewCategories
|
||||
//
|
||||
treeViewCategories.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left;
|
||||
treeViewCategories.Location = new Point(12, 12);
|
||||
treeViewCategories.Name = "treeViewCategories";
|
||||
treeViewCategories.Size = new Size(200, 582);
|
||||
treeViewCategories.TabIndex = 0;
|
||||
//
|
||||
// flowLayoutPanelSettings
|
||||
//
|
||||
flowLayoutPanelSettings.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
|
||||
flowLayoutPanelSettings.AutoScroll = true;
|
||||
flowLayoutPanelSettings.FlowDirection = FlowDirection.TopDown;
|
||||
flowLayoutPanelSettings.Location = new Point(220, 12);
|
||||
flowLayoutPanelSettings.Name = "flowLayoutPanelSettings";
|
||||
flowLayoutPanelSettings.Size = new Size(852, 582);
|
||||
flowLayoutPanelSettings.TabIndex = 1;
|
||||
flowLayoutPanelSettings.WrapContents = false;
|
||||
//
|
||||
// buttonOK
|
||||
//
|
||||
buttonOK.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
buttonOK.Location = new Point(912, 612);
|
||||
buttonOK.Name = "buttonOK";
|
||||
buttonOK.Size = new Size(75, 23);
|
||||
buttonOK.TabIndex = 2;
|
||||
buttonOK.Text = "OK";
|
||||
//
|
||||
// buttonCancel
|
||||
//
|
||||
buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
buttonCancel.Location = new Point(1002, 612);
|
||||
buttonCancel.Name = "buttonCancel";
|
||||
buttonCancel.Size = new Size(75, 23);
|
||||
buttonCancel.TabIndex = 3;
|
||||
buttonCancel.Text = "Cancel";
|
||||
//
|
||||
// OptionsWindow
|
||||
//
|
||||
ClientSize = new Size(1089, 649);
|
||||
Controls.Add(treeViewCategories);
|
||||
Controls.Add(flowLayoutPanelSettings);
|
||||
Controls.Add(buttonOK);
|
||||
Controls.Add(buttonCancel);
|
||||
Name = "OptionsWindow";
|
||||
Text = "Options";
|
||||
ResumeLayout(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Inspectron.Settings.Windows.Configuration;
|
||||
|
||||
public partial class OptionsWindow : Form
|
||||
{
|
||||
private Dictionary<string, List<OptionSetting>> settingsByCategory;
|
||||
private IControlFactory controlFactory;
|
||||
|
||||
public OptionsWindow(IControlFactory controlFactory)
|
||||
{
|
||||
this.controlFactory = controlFactory;
|
||||
settingsByCategory = new Dictionary<string, List<OptionSetting>>();
|
||||
|
||||
InitializeComponent();
|
||||
this.treeViewCategories.AfterSelect += new TreeViewEventHandler(this.treeViewCategories_AfterSelect);
|
||||
this.buttonOK.Click += new EventHandler(this.buttonOK_Click);
|
||||
this.buttonCancel.Click += new EventHandler(this.buttonCancel_Click);
|
||||
}
|
||||
|
||||
public void LoadFromSettings(InspectronSettings inspectronSettings)
|
||||
{
|
||||
// UserSettings is a Tree<object> with folders (string) and UserSettingsInfo nodes.
|
||||
// Traverse the tree to find all UserSettingsInfo nodes and their PropertyDescriptors.
|
||||
|
||||
void Traverse(object nodeObj, string path)
|
||||
{
|
||||
var node = nodeObj as dynamic; // Tree<object>
|
||||
object value = node.Value;
|
||||
|
||||
if (value is string folderName)
|
||||
{
|
||||
// Folder node, append to path and traverse children
|
||||
string newPath = string.IsNullOrEmpty(path) ? folderName : $"{path}/{folderName}";
|
||||
foreach (var child in node.Children)
|
||||
Traverse(child, newPath);
|
||||
}
|
||||
else if (value is Inspectron.Settings.InspectronSettings.UserSettingsInfo info)
|
||||
{
|
||||
// Leaf node: user settings group
|
||||
string groupName = info.Name;
|
||||
string groupPath = string.IsNullOrEmpty(path) ? groupName : $"{path}/{groupName}";
|
||||
foreach (var pd in info.Settings)
|
||||
{
|
||||
// Try to get owner from BoundPropertyDescriptor, else skip
|
||||
object owner = null;
|
||||
string description = pd.Description;
|
||||
if (pd is Inspectron.Settings.BoundPropertyDescriptor bpd)
|
||||
{
|
||||
owner = bpd.Owner;
|
||||
if (string.IsNullOrEmpty(description))
|
||||
description = bpd.DisplayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not a BoundPropertyDescriptor, cannot get owner, skip
|
||||
continue;
|
||||
}
|
||||
RegisterUserSetting(owner, bpd.PropertyInfo.Name, groupPath, description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Traverse(inspectronSettings.UserSettings.Root, "");
|
||||
}
|
||||
|
||||
public void RegisterUserSetting(object owner, string propertyName, string treePath, string description = null)
|
||||
{
|
||||
// Get the PropertyInfo from owner and propertyName
|
||||
var property = owner.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
|
||||
if (property == null)
|
||||
throw new ArgumentException($"Property '{propertyName}' not found on owner type.");
|
||||
|
||||
if (string.IsNullOrEmpty(description))
|
||||
description = propertyName;
|
||||
|
||||
// Create an OptionSetting instance
|
||||
var setting = new OptionSetting
|
||||
{
|
||||
Owner = owner,
|
||||
Property = property,
|
||||
Description = description,
|
||||
TreePath = treePath,
|
||||
Value = property.GetValue(owner)
|
||||
};
|
||||
|
||||
// Add to settingsByCategory
|
||||
if (!settingsByCategory.TryGetValue(treePath, out var settingsList))
|
||||
{
|
||||
settingsList = new List<OptionSetting>();
|
||||
settingsByCategory[treePath] = settingsList;
|
||||
}
|
||||
settingsList.Add(setting);
|
||||
|
||||
// Add nodes to treeViewCategories
|
||||
AddTreeNodes(treeViewCategories, treePath);
|
||||
}
|
||||
|
||||
private void AddTreeNodes(TreeView treeView, string treePath)
|
||||
{
|
||||
var parts = treePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
TreeNodeCollection nodes = treeView.Nodes;
|
||||
foreach (var part in parts)
|
||||
{
|
||||
var node = Enumerable.Cast<TreeNode>(nodes).FirstOrDefault(n => n.Text == part);
|
||||
if (node == null)
|
||||
{
|
||||
node = new TreeNode(part);
|
||||
nodes.Add(node);
|
||||
}
|
||||
nodes = node.Nodes;
|
||||
}
|
||||
}
|
||||
|
||||
private void treeViewCategories_AfterSelect(object sender, TreeViewEventArgs e)
|
||||
{
|
||||
// Display the settings for the selected category
|
||||
string selectedPath = GetFullPath(e.Node);
|
||||
DisplaySettings(selectedPath);
|
||||
}
|
||||
|
||||
private string GetFullPath(TreeNode node)
|
||||
{
|
||||
if (node.Parent == null)
|
||||
return node.Text;
|
||||
else
|
||||
return GetFullPath(node.Parent) + "/" + node.Text;
|
||||
}
|
||||
|
||||
private void DisplaySettings(string treePath)
|
||||
{
|
||||
flowLayoutPanelSettings.Controls.Clear();
|
||||
|
||||
if (settingsByCategory.TryGetValue(treePath, out var settingsList))
|
||||
{
|
||||
foreach (var setting in settingsList)
|
||||
{
|
||||
var control = controlFactory.CreateControl(
|
||||
setting.Property.Name,
|
||||
setting.Description,
|
||||
setting.Property,
|
||||
setting.Value,
|
||||
(newValue) => setting.Value = newValue,
|
||||
this);
|
||||
|
||||
flowLayoutPanelSettings.Controls.Add(control);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buttonOK_Click(object sender, EventArgs e)
|
||||
{
|
||||
// Update the owner properties with the values
|
||||
foreach (var settingsList in settingsByCategory.Values)
|
||||
{
|
||||
foreach (var setting in settingsList)
|
||||
{
|
||||
setting.Property.SetValue(setting.Owner, setting.Value);
|
||||
}
|
||||
}
|
||||
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void buttonCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.DialogResult = DialogResult.Cancel;
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Inspectron.Settings\Inspectron.Settings.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
18
framework/Inspectron.Settings.Windows/PropHelper.cs
Normal file
18
framework/Inspectron.Settings.Windows/PropHelper.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Inspectron.Settings.Windows
|
||||
{
|
||||
public static class PropHelper
|
||||
{
|
||||
public static PropertyInfo GetPrp(object obj,string name)
|
||||
{
|
||||
return obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.First(x => x.Name == name);
|
||||
}
|
||||
public static string SplitCamelCase(string input)
|
||||
{
|
||||
return System.Text.RegularExpressions.Regex.Replace(input, "([A-Z])", " $1", System.Text.RegularExpressions.RegexOptions.Compiled).Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user