170 lines
4.8 KiB
C#
170 lines
4.8 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Data;
|
||
using System.Drawing;
|
||
using System.Globalization;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Runtime.InteropServices;
|
||
using System.Text;
|
||
using System.Text.RegularExpressions;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using System.Xml.Linq;
|
||
using WinFormsControlLibrary1.Exceptions;
|
||
|
||
namespace WinFormsControlLibrary1;
|
||
|
||
public partial class TemplatedListBox : UserControl
|
||
{
|
||
private readonly ListBox _lb = new() { Dock = DockStyle.Fill };
|
||
|
||
private string _template = "";
|
||
private string _open = "{";
|
||
private string _close = "}";
|
||
|
||
public event EventHandler? SelectedIndexChanged;
|
||
|
||
public TemplatedListBox()
|
||
{
|
||
InitializeComponent();
|
||
Controls.Add(_lb);
|
||
_lb.HorizontalScrollbar = true;
|
||
_lb.SelectedIndexChanged += (_, __) => SelectedIndexChanged?.Invoke(this, EventArgs.Empty);
|
||
}
|
||
|
||
public void SetTemplate(string template, string open = "{", string close = "}")
|
||
{
|
||
if (string.IsNullOrWhiteSpace(template))
|
||
throw new TemplateConfigurationException("Шаблон не должен быть пустым.");
|
||
|
||
_template = template;
|
||
_open = open;
|
||
_close = close;
|
||
|
||
if (template[0] == open[0] || template[template.Length - 1] == close[0])
|
||
throw new TemplateConfigurationException("Шаблон не должен начинаться или заканчиваться свойством.");
|
||
|
||
CheckNoDoubleProperties(template, open, close);
|
||
|
||
}
|
||
|
||
public void Clear()
|
||
{
|
||
_lb.Items.Clear();
|
||
}
|
||
|
||
public void AddItem<T>(T item)
|
||
{
|
||
if (string.IsNullOrEmpty(_template))
|
||
throw new TemplateConfigurationException("Сначала вызовите SetTemplate.");
|
||
|
||
var text = Render(item);
|
||
_lb.Items.Add(text);
|
||
}
|
||
|
||
private string Render(object obj)
|
||
{
|
||
if (string.IsNullOrEmpty(_template)) return string.Empty;
|
||
|
||
string result = _template;
|
||
var type = obj.GetType();
|
||
|
||
foreach (var p in type.GetProperties())
|
||
{
|
||
if (!p.CanRead) continue;
|
||
|
||
string name = p.Name;
|
||
|
||
string val = Convert.ToString(p.GetValue(obj)) ?? string.Empty;
|
||
|
||
result = result.Replace($"{_open}{name}{_close}", val);
|
||
}
|
||
|
||
foreach (var f in type.GetFields())
|
||
{
|
||
string name = f.Name;
|
||
|
||
string val = Convert.ToString(f.GetValue(obj)) ?? string.Empty;
|
||
|
||
result = result.Replace($"{_open}{name}{_close}", val);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
public T? GetSelectedObject<T>() where T : class, new()
|
||
{
|
||
if (_lb.SelectedIndex == -1)
|
||
{
|
||
return null;
|
||
}
|
||
string row = _lb.SelectedItem!.ToString()!;
|
||
T obj = new T();
|
||
var type = typeof(T);
|
||
|
||
List<string> substrings = new List<string>();
|
||
List<string> props = ExtractPlaceholders(_template, _open, _close);
|
||
|
||
string template = _template;
|
||
|
||
substrings.AddRange(template.Split(_open + _close));
|
||
|
||
int int1 = 0; int int2 = 0;
|
||
|
||
for (int i = 0; i < props.Count; i++)
|
||
{
|
||
int1 = row.IndexOf(substrings[i]) + substrings[i].Length;
|
||
int2 = row.IndexOf(substrings[i + 1]);
|
||
if (substrings[i + 1] == "")
|
||
{
|
||
int2 = row.Length;
|
||
}
|
||
var value = row[int1..int2];
|
||
|
||
var p = type.GetProperty(props[i]);
|
||
|
||
if (p is null) continue;
|
||
|
||
p.SetValue(obj, Convert.ChangeType(value, p.PropertyType));
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
|
||
private List<string> ExtractPlaceholders(string template, string open, string close)
|
||
{
|
||
var names = new List<string>();
|
||
int i = 0;
|
||
while (i < template.Length)
|
||
{
|
||
if (template[i] == open[0])
|
||
{
|
||
int j = template.IndexOf(close, i + 1, StringComparison.Ordinal);
|
||
string name = template.Substring(i + 1, j - i - 1).Trim();
|
||
names.Add(name);
|
||
i = j + 1;
|
||
}
|
||
else i++;
|
||
}
|
||
return names;
|
||
}
|
||
|
||
private static void CheckNoDoubleProperties(string template, string open, string close)
|
||
{
|
||
for (int i = 0; i < template.Length; i++)
|
||
{
|
||
if (template[i] == close[0])
|
||
{
|
||
int k = i + 1;
|
||
while (k < template.Length && char.IsWhiteSpace(template[k])) k++;
|
||
if (k < template.Length && template[k] == open[0])
|
||
throw new TemplateConfigurationException("В шаблоне не должно идти два свойства подряд без текста между ними.");
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|