142 lines
4.5 KiB
C#
142 lines
4.5 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Data;
|
||
using System.Drawing;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Runtime.InteropServices;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using WinFormsControlLibrary1.Exceptions;
|
||
|
||
namespace WinFormsControlLibrary1;
|
||
|
||
public partial class TemplatedListBox : UserControl
|
||
{
|
||
private readonly ListBox _lb = new();
|
||
|
||
private string _template = "";
|
||
private char _open = '{';
|
||
private char _close = '}';
|
||
|
||
private List<string> _placeholders = new();
|
||
private readonly List<object> _items = new();
|
||
|
||
public event EventHandler? SelectedIndexChanged;
|
||
public TemplatedListBox()
|
||
{
|
||
InitializeComponent();
|
||
Controls.Add(_lb);
|
||
_lb.SelectedIndexChanged += (_, __) => SelectedIndexChanged?.Invoke(this, EventArgs.Empty);
|
||
}
|
||
|
||
public void SetTemplate(string template, char open = '{', char close = '}')
|
||
{
|
||
if(string.IsNullOrEmpty(template))
|
||
throw new TemplateConfigurationException("Шаблон не должен быть пустым.");
|
||
_template = template;
|
||
_open = open;
|
||
_close = close;
|
||
_placeholders = ParsePlaceholders(template, open, close);
|
||
|
||
if (template[0] == open || template[template.Length - 1] == close)
|
||
throw new TemplateConfigurationException("Шаблон не должен начинаться или заканчиваться свойством.");
|
||
|
||
CheckNoDoubleProperties(template,open, close);
|
||
}
|
||
|
||
public void Clear()
|
||
{
|
||
_lb.Items.Clear();
|
||
_items.Clear();
|
||
}
|
||
|
||
public void AddItem<T>(T item)
|
||
{
|
||
if (string.IsNullOrEmpty(_template))
|
||
throw new TemplateConfigurationException("Сначала вызовите SetTemplate.");
|
||
var text = Render(item!);
|
||
_lb.Items.Add(text);
|
||
_items.Add(text);
|
||
}
|
||
|
||
public T? GetSelected<T>()
|
||
{
|
||
int id = _lb.SelectedIndex;
|
||
if (id < 0 || id >= _items.Count) return default;
|
||
return _items[id] is T t ? t : default;
|
||
}
|
||
|
||
private string Render(object obj)
|
||
{
|
||
var type = obj.GetType();
|
||
var sb = new StringBuilder();
|
||
int i = 0;
|
||
while (i < _template.Length)
|
||
{
|
||
if (_template[i] == _open)
|
||
{
|
||
int j = _template.IndexOf(_close, i + 1);
|
||
var name = _template.Substring(i + 1, j - i - 1);
|
||
string val = GetMemberString(type, obj, name);
|
||
sb.Append(val);
|
||
i = j + 1;
|
||
}
|
||
else
|
||
{
|
||
sb.Append(_template[i]);
|
||
i++;
|
||
}
|
||
}
|
||
return sb.ToString();
|
||
}
|
||
|
||
private static string GetMemberString(Type t, object obj, string name)
|
||
{
|
||
var p = t.GetProperty(name);
|
||
if (p != null) return Convert.ToString(p.GetValue(obj)) ?? string.Empty;
|
||
|
||
var f = t.GetField(name);
|
||
if (f != null) return Convert.ToString(f.GetValue(obj)) ?? string.Empty;
|
||
|
||
return string.Empty;
|
||
}
|
||
|
||
private static List<string> ParsePlaceholders(string template, char open, char close)
|
||
{
|
||
var list = new List<String>();
|
||
int i = 0;
|
||
while (i < template.Length)
|
||
{
|
||
if (template[i] == open)
|
||
{
|
||
int j = template.IndexOf(close, i + 1);
|
||
if (j < 0) throw new TemplateConfigurationException("Несогласованные скобки в шаблоне.");
|
||
string name = template.Substring(i + 1, j - i - 1).Trim();
|
||
if (string.IsNullOrEmpty(name)) throw new TemplateConfigurationException("Пустое имя свойства в шаблоне.");
|
||
list.Add(name);
|
||
i = j + 1;
|
||
}
|
||
else i++;
|
||
}
|
||
return list;
|
||
}
|
||
|
||
private static void CheckNoDoubleProperties(string template, char open, char close)
|
||
{
|
||
for (int i = 0; i < template.Length; i++)
|
||
{
|
||
if (template[i] == close)
|
||
{
|
||
int k = i + 1;
|
||
while (k < template.Length && char.IsWhiteSpace(template[k])) k++;
|
||
if (k < template.Length && template[k] == open)
|
||
throw new TemplateConfigurationException("В шаблоне не должно идти два свойства подряд без текста между ними.");
|
||
}
|
||
}
|
||
}
|
||
}
|