Добавьте файлы проекта.
This commit is contained in:
397
SQLVision.UI/Controls/ControlFactory.cs
Normal file
397
SQLVision.UI/Controls/ControlFactory.cs
Normal file
@@ -0,0 +1,397 @@
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using SQLVision.Core.Enums;
|
||||
using SQLVision.Core.Interfaces;
|
||||
using SQLVision.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SQLVision.UI.Controls;
|
||||
|
||||
public class ControlFactory : IControlFactory
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<ControlFactory> _logger;
|
||||
|
||||
public ControlFactory(IServiceProvider serviceProvider, ILogger<ControlFactory> logger)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public FrameworkElement CreateControl(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
try
|
||||
{
|
||||
var control = parameter.Type switch
|
||||
{
|
||||
ParameterType.String => CreateTextBox(parameter, onValueChanged),
|
||||
ParameterType.Int => CreateNumberBox(parameter, onValueChanged),
|
||||
ParameterType.Decimal => CreateNumberBox(parameter, onValueChanged, true),
|
||||
ParameterType.DateTime => CreateDatePicker(parameter, onValueChanged),
|
||||
ParameterType.Bool => CreateCheckBox(parameter, onValueChanged),
|
||||
ParameterType.Table => CreateComboBox(parameter, onValueChanged),
|
||||
ParameterType.MultiSelect => CreateListBox(parameter, onValueChanged),
|
||||
ParameterType.Color => CreateColorPicker(parameter, onValueChanged),
|
||||
ParameterType.File => CreateFilePicker(parameter, onValueChanged),
|
||||
ParameterType.Json => CreateJsonEditor(parameter, onValueChanged),
|
||||
_ => CreateTextBox(parameter, onValueChanged)
|
||||
};
|
||||
|
||||
// Настройка общих свойств
|
||||
control.Tag = parameter;
|
||||
control.IsEnabled = !parameter.IsRequired || parameter.DefaultValue == null;
|
||||
|
||||
// Добавление подсказки
|
||||
if (!string.IsNullOrEmpty(parameter.Description))
|
||||
{
|
||||
ToolTipService.SetToolTip(control, parameter.Description);
|
||||
}
|
||||
|
||||
return control;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error creating control for parameter {Parameter}", parameter.Name);
|
||||
return CreateFallbackControl(parameter, onValueChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private FrameworkElement CreateTextBox(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
var textBox = new TextBox
|
||||
{
|
||||
Header = parameter.DisplayName,
|
||||
PlaceholderText = parameter.Watermark ?? $"Введите {parameter.DisplayName.ToLower()}",
|
||||
Text = parameter.DefaultValue?.ToString() ?? string.Empty
|
||||
};
|
||||
|
||||
textBox.TextChanged += (s, e) => onValueChanged(textBox.Text);
|
||||
|
||||
return textBox;
|
||||
}
|
||||
|
||||
private FrameworkElement CreateNumberBox(ScriptParameter parameter, Action<object> onValueChanged, bool isDecimal = false)
|
||||
{
|
||||
var numberBox = new NumberBox
|
||||
{
|
||||
Header = parameter.DisplayName,
|
||||
PlaceholderText = parameter.Watermark ?? $"Введите {parameter.DisplayName.ToLower()}",
|
||||
SmallChange = isDecimal ? 0.1 : 1,
|
||||
LargeChange = isDecimal ? 1 : 10,
|
||||
SpinButtonPlacementMode = NumberBoxSpinButtonPlacementMode.Inline,
|
||||
AcceptsExpression = false
|
||||
};
|
||||
|
||||
if (isDecimal)
|
||||
{
|
||||
numberBox.Value = Convert.ToDouble(parameter.DefaultValue ?? 0);
|
||||
numberBox.ValueChanged += (s, e) => onValueChanged(e.NewValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
numberBox.Value = Convert.ToInt32(parameter.DefaultValue ?? 0);
|
||||
numberBox.ValueChanged += (s, e) => onValueChanged((int)e.NewValue);
|
||||
}
|
||||
|
||||
// Применение правил валидации
|
||||
if (parameter.ValidationRules != null)
|
||||
{
|
||||
if (parameter.ValidationRules.TryGetValue("min", out var min))
|
||||
numberBox.Minimum = Convert.ToDouble(min);
|
||||
|
||||
if (parameter.ValidationRules.TryGetValue("max", out var max))
|
||||
numberBox.Maximum = Convert.ToDouble(max);
|
||||
}
|
||||
|
||||
return numberBox;
|
||||
}
|
||||
|
||||
private FrameworkElement CreateDatePicker(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
var datePicker = new DatePicker
|
||||
{
|
||||
Header = parameter.DisplayName,
|
||||
Date = parameter.DefaultValue is DateTime defaultDate ?
|
||||
DateTimeOffset.Parse(defaultDate.ToString()) : DateTimeOffset.Now
|
||||
};
|
||||
|
||||
datePicker.DateChanged += (s, e) => onValueChanged(e.NewDate.DateTime);
|
||||
|
||||
return datePicker;
|
||||
}
|
||||
|
||||
private FrameworkElement CreateCheckBox(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
var checkBox = new CheckBox
|
||||
{
|
||||
Content = parameter.DisplayName,
|
||||
IsChecked = parameter.DefaultValue is bool defaultBool ? defaultBool : false
|
||||
};
|
||||
|
||||
checkBox.Checked += (s, e) => onValueChanged(true);
|
||||
checkBox.Unchecked += (s, e) => onValueChanged(false);
|
||||
|
||||
return checkBox;
|
||||
}
|
||||
|
||||
private FrameworkElement CreateComboBox(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
var comboBox = new ComboBox
|
||||
{
|
||||
Header = parameter.DisplayName,
|
||||
PlaceholderText = parameter.Watermark ?? $"Выберите {parameter.DisplayName.ToLower()}",
|
||||
DisplayMemberPath = parameter.DisplayMember,
|
||||
SelectedValuePath = parameter.ValueMember
|
||||
};
|
||||
|
||||
// Загрузка данных асинхронно
|
||||
LoadComboBoxDataAsync(comboBox, parameter).ConfigureAwait(false);
|
||||
|
||||
comboBox.SelectionChanged += (s, e) =>
|
||||
{
|
||||
if (comboBox.SelectedValue != null)
|
||||
onValueChanged(comboBox.SelectedValue);
|
||||
};
|
||||
|
||||
return comboBox;
|
||||
}
|
||||
|
||||
private async Task LoadComboBoxDataAsync(ComboBox comboBox, ScriptParameter parameter)
|
||||
{
|
||||
if (string.IsNullOrEmpty(parameter.TableQuery)) return;
|
||||
|
||||
try
|
||||
{
|
||||
// Используем сервис выполнения SQL для загрузки данных
|
||||
var executionService = _serviceProvider.GetService<ISqlExecutionService>();
|
||||
var result = await executionService.ExecuteAsync(
|
||||
parameter.TableQuery,
|
||||
new Dictionary<string, object>(),
|
||||
GetConnectionString());
|
||||
|
||||
if (result.IsSuccess && result.Data.Tables.Count > 0)
|
||||
{
|
||||
comboBox.ItemsSource = result.Data.Tables[0].DefaultView;
|
||||
|
||||
// Установка значения по умолчанию
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
comboBox.SelectedValue = parameter.DefaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error loading combo box data for {Parameter}", parameter.Name);
|
||||
}
|
||||
}
|
||||
|
||||
private FrameworkElement CreateListBox(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
var listBox = new ListBox
|
||||
{
|
||||
Header = parameter.DisplayName,
|
||||
SelectionMode = ListViewSelectionMode.Multiple
|
||||
};
|
||||
|
||||
// Загрузка данных для ListBox
|
||||
// Аналогично ComboBox
|
||||
|
||||
listBox.SelectionChanged += (s, e) =>
|
||||
{
|
||||
var selectedValues = listBox.SelectedItems.Cast<DataRowView>()
|
||||
.Select(r => r[parameter.ValueMember])
|
||||
.ToList();
|
||||
|
||||
onValueChanged(selectedValues);
|
||||
};
|
||||
|
||||
return listBox;
|
||||
}
|
||||
|
||||
private FrameworkElement CreateColorPicker(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
var colorPicker = new ColorPicker
|
||||
{
|
||||
Header = parameter.DisplayName,
|
||||
ColorSpectrumShape = ColorSpectrumShape.Box,
|
||||
IsMoreButtonVisible = true,
|
||||
IsColorSliderVisible = true,
|
||||
IsColorChannelTextInputVisible = true,
|
||||
IsHexInputVisible = true
|
||||
};
|
||||
|
||||
if (parameter.DefaultValue is string defaultColor)
|
||||
{
|
||||
if (ColorHelper.TryParse(defaultColor, out var color))
|
||||
{
|
||||
colorPicker.Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
colorPicker.ColorChanged += (s, e) =>
|
||||
onValueChanged($"#{e.NewColor.R:X2}{e.NewColor.G:X2}{e.NewColor.B:X2}");
|
||||
|
||||
return colorPicker;
|
||||
}
|
||||
|
||||
private FrameworkElement CreateFilePicker(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
var stackPanel = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8 };
|
||||
|
||||
var textBox = new TextBox
|
||||
{
|
||||
Header = parameter.DisplayName,
|
||||
PlaceholderText = "Путь к файлу",
|
||||
Width = 200,
|
||||
IsReadOnly = true
|
||||
};
|
||||
|
||||
var button = new Button
|
||||
{
|
||||
Content = "Выбрать",
|
||||
VerticalAlignment = VerticalAlignment.Bottom
|
||||
};
|
||||
|
||||
button.Click += async (s, e) =>
|
||||
{
|
||||
var openPicker = new FileOpenPicker();
|
||||
openPicker.ViewMode = PickerViewMode.List;
|
||||
openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
|
||||
|
||||
if (parameter.ValidationRules != null &&
|
||||
parameter.ValidationRules.TryGetValue("extensions", out var extensions))
|
||||
{
|
||||
foreach (var ext in extensions.ToString().Split(','))
|
||||
{
|
||||
openPicker.FileTypeFilter.Add(ext.Trim());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
openPicker.FileTypeFilter.Add("*");
|
||||
}
|
||||
|
||||
var file = await openPicker.PickSingleFileAsync();
|
||||
if (file != null)
|
||||
{
|
||||
textBox.Text = file.Path;
|
||||
onValueChanged(file.Path);
|
||||
}
|
||||
};
|
||||
|
||||
stackPanel.Children.Add(textBox);
|
||||
stackPanel.Children.Add(button);
|
||||
|
||||
return stackPanel;
|
||||
}
|
||||
|
||||
private FrameworkElement CreateJsonEditor(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
var textBox = new TextBox
|
||||
{
|
||||
Header = parameter.DisplayName,
|
||||
PlaceholderText = "Введите JSON",
|
||||
AcceptsReturn = true,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
Height = 100,
|
||||
FontFamily = new FontFamily("Consolas")
|
||||
};
|
||||
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
textBox.Text = JsonSerializer.Serialize(parameter.DefaultValue,
|
||||
new JsonSerializerOptions { WriteIndented = true });
|
||||
}
|
||||
|
||||
textBox.TextChanged += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Deserialize<JsonElement>(textBox.Text);
|
||||
onValueChanged(json);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Игнорируем ошибки парсинга JSON
|
||||
}
|
||||
};
|
||||
|
||||
return textBox;
|
||||
}
|
||||
|
||||
private FrameworkElement CreateFallbackControl(ScriptParameter parameter, Action<object> onValueChanged)
|
||||
{
|
||||
return new TextBox
|
||||
{
|
||||
Header = parameter.DisplayName,
|
||||
Text = $"Ошибка создания контрола для типа {parameter.Type}",
|
||||
IsReadOnly = true,
|
||||
Foreground = new SolidColorBrush(Colors.Red)
|
||||
};
|
||||
}
|
||||
|
||||
public void UpdateControlState(FrameworkElement control, ScriptParameter parameter, Dictionary<string, object> currentValues)
|
||||
{
|
||||
// Обновление состояния контрола на основе зависимостей
|
||||
if (!string.IsNullOrEmpty(parameter.DependsOn))
|
||||
{
|
||||
var isEnabled = CheckDependency(parameter, currentValues);
|
||||
control.IsEnabled = isEnabled;
|
||||
|
||||
if (!isEnabled)
|
||||
{
|
||||
// Сброс значения, если контрол отключен
|
||||
ResetControlValue(control);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckDependency(ScriptParameter parameter, Dictionary<string, object> currentValues)
|
||||
{
|
||||
if (!currentValues.TryGetValue(parameter.DependsOn, out var dependencyValue))
|
||||
return false;
|
||||
|
||||
if (parameter.DependencyValues != null)
|
||||
{
|
||||
return parameter.DependencyValues
|
||||
.Any(kvp => object.Equals(kvp.Value, dependencyValue));
|
||||
}
|
||||
|
||||
return dependencyValue != null && !string.IsNullOrWhiteSpace(dependencyValue.ToString());
|
||||
}
|
||||
|
||||
private void ResetControlValue(FrameworkElement control)
|
||||
{
|
||||
switch (control)
|
||||
{
|
||||
case TextBox textBox:
|
||||
textBox.Text = string.Empty;
|
||||
break;
|
||||
case ComboBox comboBox:
|
||||
comboBox.SelectedIndex = -1;
|
||||
break;
|
||||
case CheckBox checkBox:
|
||||
checkBox.IsChecked = false;
|
||||
break;
|
||||
case DatePicker datePicker:
|
||||
datePicker.Date = DateTimeOffset.Now;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetConnectionString()
|
||||
{
|
||||
// Получение строки подключения из конфигурации
|
||||
var configuration = _serviceProvider.GetService<IConfiguration>();
|
||||
return configuration.GetConnectionString("Default") ??
|
||||
configuration["Database:DefaultConnection"];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user