Files
PIbd-32_BuslaevRoman_KOP/WinFormsControlLibrary1/TemplatedListBox.cs
2025-09-07 11:28:21 +04:00

142 lines
4.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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("В шаблоне не должно идти два свойства подряд без текста между ними.");
}
}
}
}