377 lines
10 KiB
C#
377 lines
10 KiB
C#
using ImageProcessing.Core;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
|
||
namespace ImageProcessing.Controls;
|
||
|
||
/// <summary>
|
||
/// 通用参数配置 UserControl
|
||
/// 可以根据不同算子的参数自动生成对应的 UI 控件
|
||
/// </summary>
|
||
public partial class ProcessorParameterControl : UserControl
|
||
{
|
||
private ImageProcessorBase? _currentProcessor;
|
||
|
||
/// <summary>
|
||
/// 参数变化事件
|
||
/// </summary>
|
||
public event EventHandler? ParameterChanged;
|
||
|
||
public ProcessorParameterControl()
|
||
{
|
||
InitializeComponent();
|
||
UpdateNoProcessorText();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新"未选择算子"的文本
|
||
/// </summary>
|
||
private void UpdateNoProcessorText()
|
||
{
|
||
txtProcessorName.Text = LocalizationHelper.GetString("NoProcessorSelected");
|
||
txtProcessorDescription.Text = LocalizationHelper.GetString("PleaseSelectProcessor");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 触发参数变化事件
|
||
/// </summary>
|
||
protected virtual void OnParameterChanged()
|
||
{
|
||
ParameterChanged?.Invoke(this, EventArgs.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载算子参数并生成 UI
|
||
/// </summary>
|
||
public void LoadProcessor(ImageProcessorBase? processor)
|
||
{
|
||
_currentProcessor = processor;
|
||
pnlParameters.Children.Clear();
|
||
|
||
if (processor == null)
|
||
{
|
||
UpdateNoProcessorText();
|
||
return;
|
||
}
|
||
|
||
// 显示算子信息
|
||
txtProcessorName.Text = processor.Name;
|
||
txtProcessorDescription.Text = processor.Description;
|
||
|
||
// 生成参数控件
|
||
var parameters = processor.GetParameters();
|
||
|
||
foreach (var param in parameters)
|
||
{
|
||
CreateParameterControl(param);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据参数类型创建对应的控件
|
||
/// </summary>
|
||
private void CreateParameterControl(ProcessorParameter param)
|
||
{
|
||
// 如果参数不可见,跳过创建
|
||
if (!param.IsVisible)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 参数标签
|
||
var label = new TextBlock
|
||
{
|
||
Text = param.DisplayName + ":",
|
||
Margin = new Thickness(0, 10, 0, 5),
|
||
FontWeight = FontWeights.Bold,
|
||
FontSize = 13
|
||
};
|
||
pnlParameters.Children.Add(label);
|
||
|
||
// 根据参数类型创建不同的控件
|
||
UIElement? control = null;
|
||
|
||
if (param.ValueType == typeof(int))
|
||
{
|
||
control = CreateIntegerControl(param);
|
||
}
|
||
else if (param.ValueType == typeof(double) || param.ValueType == typeof(float))
|
||
{
|
||
control = CreateDoubleControl(param);
|
||
}
|
||
else if (param.ValueType == typeof(bool))
|
||
{
|
||
control = CreateBooleanControl(param);
|
||
}
|
||
else if (param.ValueType == typeof(string) && param.Options != null)
|
||
{
|
||
control = CreateComboBoxControl(param);
|
||
}
|
||
else if (param.ValueType == typeof(string))
|
||
{
|
||
control = CreateTextBoxControl(param);
|
||
}
|
||
|
||
if (control != null)
|
||
{
|
||
pnlParameters.Children.Add(control);
|
||
|
||
// 添加描述标签
|
||
if (!string.IsNullOrEmpty(param.Description))
|
||
{
|
||
var desc = new TextBlock
|
||
{
|
||
Text = param.Description,
|
||
Margin = new Thickness(0, 5, 0, 0),
|
||
FontSize = 11,
|
||
Foreground = System.Windows.Media.Brushes.Gray,
|
||
TextWrapping = TextWrapping.Wrap
|
||
};
|
||
pnlParameters.Children.Add(desc);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建整数类型控件(Slider + TextBox 或仅 TextBox)
|
||
/// 当 MinValue 和 MaxValue 都为 null 时,只显示文本框,不显示滑块
|
||
/// </summary>
|
||
private UIElement CreateIntegerControl(ProcessorParameter param)
|
||
{
|
||
var panel = new StackPanel();
|
||
|
||
var textBox = new TextBox
|
||
{
|
||
Text = param.Value.ToString(),
|
||
Width = 100,
|
||
HorizontalAlignment = HorizontalAlignment.Left
|
||
};
|
||
|
||
if (param.MinValue != null && param.MaxValue != null)
|
||
{
|
||
var slider = new Slider
|
||
{
|
||
Minimum = Convert.ToDouble(param.MinValue),
|
||
Maximum = Convert.ToDouble(param.MaxValue),
|
||
Value = Convert.ToDouble(param.Value),
|
||
TickFrequency = 1,
|
||
IsSnapToTickEnabled = true,
|
||
Margin = new Thickness(0, 0, 0, 5)
|
||
};
|
||
|
||
slider.ValueChanged += (s, e) =>
|
||
{
|
||
int value = (int)slider.Value;
|
||
textBox.Text = value.ToString();
|
||
_currentProcessor?.SetParameter(param.Name, value);
|
||
OnParameterChanged();
|
||
};
|
||
|
||
textBox.TextChanged += (s, e) =>
|
||
{
|
||
if (int.TryParse(textBox.Text, out int value))
|
||
{
|
||
var min = Convert.ToInt32(param.MinValue);
|
||
var max = Convert.ToInt32(param.MaxValue);
|
||
|
||
if (value >= min && value <= max)
|
||
{
|
||
slider.Value = value;
|
||
}
|
||
}
|
||
};
|
||
|
||
panel.Children.Add(slider);
|
||
}
|
||
else
|
||
{
|
||
textBox.TextChanged += (s, e) =>
|
||
{
|
||
if (int.TryParse(textBox.Text, out int value))
|
||
{
|
||
_currentProcessor?.SetParameter(param.Name, value);
|
||
OnParameterChanged();
|
||
}
|
||
};
|
||
}
|
||
|
||
panel.Children.Add(textBox);
|
||
|
||
return panel;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建浮点数类型控件(Slider + TextBox 或仅 TextBox)
|
||
/// 当 MinValue 和 MaxValue 都为 null 时,只显示文本框,不显示滑块
|
||
/// </summary>
|
||
private UIElement CreateDoubleControl(ProcessorParameter param)
|
||
{
|
||
var panel = new StackPanel();
|
||
|
||
var textBox = new TextBox
|
||
{
|
||
Text = Convert.ToDouble(param.Value).ToString("F2"),
|
||
Width = 100,
|
||
HorizontalAlignment = HorizontalAlignment.Left
|
||
};
|
||
|
||
if (param.MinValue != null && param.MaxValue != null)
|
||
{
|
||
var slider = new Slider
|
||
{
|
||
Minimum = Convert.ToDouble(param.MinValue),
|
||
Maximum = Convert.ToDouble(param.MaxValue),
|
||
Value = Convert.ToDouble(param.Value),
|
||
TickFrequency = 0.1,
|
||
Margin = new Thickness(0, 0, 0, 5)
|
||
};
|
||
|
||
slider.ValueChanged += (s, e) =>
|
||
{
|
||
double value = Math.Round(slider.Value, 2);
|
||
textBox.Text = value.ToString("F2");
|
||
_currentProcessor?.SetParameter(param.Name, value);
|
||
OnParameterChanged();
|
||
};
|
||
|
||
textBox.TextChanged += (s, e) =>
|
||
{
|
||
if (double.TryParse(textBox.Text, out double value))
|
||
{
|
||
var min = Convert.ToDouble(param.MinValue);
|
||
var max = Convert.ToDouble(param.MaxValue);
|
||
|
||
if (value >= min && value <= max)
|
||
{
|
||
slider.Value = value;
|
||
}
|
||
}
|
||
};
|
||
|
||
panel.Children.Add(slider);
|
||
}
|
||
else
|
||
{
|
||
textBox.TextChanged += (s, e) =>
|
||
{
|
||
if (double.TryParse(textBox.Text, out double value))
|
||
{
|
||
_currentProcessor?.SetParameter(param.Name, value);
|
||
OnParameterChanged();
|
||
}
|
||
};
|
||
}
|
||
|
||
panel.Children.Add(textBox);
|
||
|
||
return panel;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建布尔类型控件(CheckBox)
|
||
/// </summary>
|
||
private UIElement CreateBooleanControl(ProcessorParameter param)
|
||
{
|
||
var checkBox = new CheckBox
|
||
{
|
||
Content = param.DisplayName,
|
||
IsChecked = Convert.ToBoolean(param.Value),
|
||
Margin = new Thickness(0, 5, 0, 0)
|
||
};
|
||
|
||
checkBox.Checked += (s, e) =>
|
||
{
|
||
_currentProcessor?.SetParameter(param.Name, true);
|
||
OnParameterChanged();
|
||
};
|
||
|
||
checkBox.Unchecked += (s, e) =>
|
||
{
|
||
_currentProcessor?.SetParameter(param.Name, false);
|
||
OnParameterChanged();
|
||
};
|
||
|
||
return checkBox;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建下拉框控件(ComboBox)
|
||
/// </summary>
|
||
private UIElement CreateComboBoxControl(ProcessorParameter param)
|
||
{
|
||
var comboBox = new ComboBox
|
||
{
|
||
Margin = new Thickness(0, 5, 0, 0),
|
||
Width = 200,
|
||
HorizontalAlignment = HorizontalAlignment.Left
|
||
};
|
||
|
||
if (param.Options != null)
|
||
{
|
||
foreach (var option in param.Options)
|
||
{
|
||
comboBox.Items.Add(option);
|
||
}
|
||
}
|
||
|
||
comboBox.SelectedItem = param.Value;
|
||
|
||
comboBox.SelectionChanged += (s, e) =>
|
||
{
|
||
if (comboBox.SelectedItem != null)
|
||
{
|
||
_currentProcessor?.SetParameter(param.Name, comboBox.SelectedItem.ToString()!);
|
||
|
||
// 如果是 FilterType 参数,重新加载界面以更新参数可见性
|
||
if (param.Name == "FilterType")
|
||
{
|
||
LoadProcessor(_currentProcessor);
|
||
}
|
||
|
||
OnParameterChanged();
|
||
}
|
||
};
|
||
|
||
return comboBox;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建文本框控件(TextBox)
|
||
/// </summary>
|
||
private UIElement CreateTextBoxControl(ProcessorParameter param)
|
||
{
|
||
var textBox = new TextBox
|
||
{
|
||
Text = param.Value?.ToString() ?? "",
|
||
Margin = new Thickness(0, 5, 0, 0),
|
||
Width = 200,
|
||
HorizontalAlignment = HorizontalAlignment.Left
|
||
};
|
||
|
||
textBox.TextChanged += (s, e) =>
|
||
{
|
||
_currentProcessor?.SetParameter(param.Name, textBox.Text);
|
||
OnParameterChanged();
|
||
};
|
||
|
||
return textBox;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前配置的算子
|
||
/// </summary>
|
||
public ImageProcessorBase? GetProcessor()
|
||
{
|
||
return _currentProcessor;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空参数控件
|
||
/// </summary>
|
||
public void Clear()
|
||
{
|
||
_currentProcessor = null;
|
||
pnlParameters.Children.Clear();
|
||
UpdateNoProcessorText();
|
||
}
|
||
} |