为Wpf敏捷开发做准备-Wpf实现Form表单2
AIStudio框架汇总及介绍
前言:上一节实现的FormItem中,还需要自己写TextBox或者ComboBox,代码还是比较多,我们能不能设置一个属性,让其自动生成呢?说干就干。
第一步:实现FormCodeItem继承FormItem,定义依赖性属性ControlType,根据ControlType自动生成控件,思路很明确,代码很多。
#region ControlType
public static readonly DependencyProperty ControlTypeProperty = DependencyProperty.Register(
"ControlType", typeof(FormControlType), typeof(FormCodeItem), new PropertyMetadata(FormControlType.TextBox, OnControlTypeChanged));
private static void OnControlTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is FormCodeItem formCodeItem)
{
formCodeItem.GetControl((FormControlType)e.NewValue);
}
}
[DisplayName("控件类型")]
public FormControlType ControlType
{
get
{
return (FormControlType)GetValue(ControlTypeProperty);
}
set
{
SetValue(ControlTypeProperty, value);
}
}
private void GetControl(FormControlType controlType)
{
if (_contentPresenter == null)
return;
bool hideHeader = false;
switch (controlType)
{
case FormControlType.TextBox:
{
_control = new TextBox() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(TextBox.TextProperty, binding);
}
break;
}
case FormControlType.ComboBox:
{
_control = new ComboBox() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(ComboBox.SelectedValueProperty, binding);
}
_control.SetValue(ComboBox.DisplayMemberPathProperty, "Text");
_control.SetValue(ComboBox.SelectedValuePathProperty, "Value");
break;
}
case FormControlType.PasswordBox:
{
_control = new PasswordBox() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(PasswordBoxBindingBehavior.PasswordProperty, binding);
}
break;
}
case FormControlType.DatePicker:
{
_control = new DatePicker() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(DatePicker.SelectedDateProperty, binding);
}
break;
}
case FormControlType.TreeSelect:
{
_control = new TreeSelect() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(TreeSelect.SelectedValueProperty, binding);
}
_control.SetValue(TreeSelect.DisplayMemberPathProperty, "Text");
_control.SetValue(TreeSelect.SelectedValuePathProperty, "Value");
var dataTemplate = new HierarchicalDataTemplate();
dataTemplate.ItemsSource = new Binding("Children");
FrameworkElementFactory fef = new FrameworkElementFactory(typeof(TextBlock));
Binding bind = new Binding("Text");
fef.SetBinding(TextBlock.TextProperty, bind);
dataTemplate.VisualTree = fef;
(_control as TreeSelect).ItemTemplate = dataTemplate;
break;
}
case FormControlType.MultiComboBox:
{
_control = new MultiComboBox() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(CustomeSelectionValues.SelectedValuesProperty, binding);
}
_control.SetValue(ComboBox.DisplayMemberPathProperty, "Text");
_control.SetValue(ComboBox.SelectedValuePathProperty, "Value");
break;
}
case FormControlType.MultiTreeSelect:
{
_control = new TreeSelect() { Background = Brushes.Transparent, IsMulti = true };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(TreeSelect.SelectedValuesProperty, binding);
}
_control.SetValue(TreeSelect.DisplayMemberPathProperty, "Text");
_control.SetValue(TreeSelect.SelectedValuePathProperty, "Value");
var dataTemplate = new HierarchicalDataTemplate();
dataTemplate.ItemsSource = new Binding("Children");
FrameworkElementFactory fef = new FrameworkElementFactory(typeof(StackPanel));
fef.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
FrameworkElementFactory checkbox_fef = new FrameworkElementFactory(typeof(CheckBox));
fef.AppendChild(checkbox_fef);
Binding checkbox_bind = new Binding("IsChecked");
checkbox_fef.SetBinding(CheckBox.IsCheckedProperty, checkbox_bind);
FrameworkElementFactory textblock_fef = new FrameworkElementFactory(typeof(TextBlock));
fef.AppendChild(textblock_fef);
Binding textblock_bind = new Binding("Text");
textblock_fef.SetBinding(TextBlock.TextProperty, textblock_bind);
textblock_fef.SetValue(TextBlock.MarginProperty, new Thickness(2, 0, 0, 0));
dataTemplate.VisualTree = fef;
(_control as TreeSelect).ItemTemplate = dataTemplate;
break;
}
case FormControlType.IntegerUpDown:
{
_control = new IntegerUpDown() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(IntegerUpDown.ValueProperty, binding);
}
break;
}
case FormControlType.LongUpDown:
{
_control = new LongUpDown() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(IntegerUpDown.ValueProperty, binding);
}
break;
}
case FormControlType.DoubleUpDown:
{
_control = new DoubleUpDown() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(IntegerUpDown.ValueProperty, binding);
}
break;
}
case FormControlType.DecimalUpDown:
{
_control = new DecimalUpDown() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(IntegerUpDown.ValueProperty, binding);
}
break;
}
case FormControlType.DateTimeUpDown:
{
_control = new DateTimeUpDown() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(IntegerUpDown.ValueProperty, binding);
}
break;
}
case FormControlType.CheckBox:
{
_control = new CheckBox() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(CheckBox.IsCheckedProperty, binding);
}
break;
}
case FormControlType.ToggleButton:
{
_control = new ToggleButton() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(ToggleButton.IsCheckedProperty, binding);
}
break;
}
case FormControlType.RichTextBox:
{
_control = new RichTextBox() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(RichTextBox.TextProperty, binding);
}
break;
}
case FormControlType.UploadFile:
{
_control = new UploadFile() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(UploadFile.FileProperty, binding);
}
_control.SetValue(UploadFile.UploadUrlProperty, ExtField1);
_control.SetValue(UploadFile.UploadTokenProperty, ExtField2);
break;
}
case FormControlType.UploadImage:
{
_control = new UploadFile() { Background = Brushes.Transparent };
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(UploadFile.FileProperty, binding);
_control.SetValue(UploadFile.UploadFileTypeProperty, UploadFileType.Image);
}
_control.SetValue(UploadFile.UploadUrlProperty, ExtField1);
_control.SetValue(UploadFile.UploadTokenProperty, ExtField2);
break;
}
case FormControlType.DataGrid:
{
_control = new DataGrid() { Background = Brushes.Transparent };
(_control as DataGrid).IsReadOnly = true;
if (!string.IsNullOrEmpty(Path))
{
Binding binding = new Binding(Path);
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidatesOnExceptions = true;
binding.ValidatesOnDataErrors = true;
binding.NotifyOnValidationError = true;
_control.SetBinding(DataGrid.ItemsSourceProperty, binding);
}
if (ExtField1 is IEnumerable<DataGridColumn> columns)
{
if (columns != null)
{
foreach (var column in columns)
{
var copy = System.Windows.Markup.XamlReader.Parse(System.Windows.Markup.XamlWriter.Save(column)) as DataGridColumn;
(_control as DataGrid).Columns.Add(copy);
}
}
}
else if (ExtField1 is IEnumerable<DataGridColumnConfig> columnconfigs)
{
if (columnconfigs != null)
{
foreach (var columnconfig in columnconfigs)
{
(_control as DataGrid).Columns.Add(columnconfig.GetColumn());
}
}
}
else
{
(_control as DataGrid).Columns.Add(new DataGridTextColumn()
{
Binding = new Binding("Field1"),
Header = "字段1",
Width = new DataGridLength(100, DataGridLengthUnitType.Pixel)
});
(_control as DataGrid).Columns.Add(new DataGridTextColumn()
{
Binding = new Binding("Field2"),
Header = "字段2",
Width = new DataGridLength(100, DataGridLengthUnitType.Pixel)
});
(_control as DataGrid).Columns.Add(new DataGridTextColumn()
{
Binding = new Binding("Field3"),
Header = "字段3",
Width = new DataGridLength(100, DataGridLengthUnitType.Pixel)
});
(_control as DataGrid).Columns.Add(new DataGridTextColumn()
{
Binding = new Binding("Field4"),
Header = "字段4",
Width = new DataGridLength(100, DataGridLengthUnitType.Pixel)
});
}
_control.SetValue(DataGridColumnsConfigAttach.ShowConfigProperty, true);
break;
}
case FormControlType.Query:
case FormControlType.Submit:
{
hideHeader = true;
_control = new Button();
Binding binding = new Binding($"DataContext.{Path}");
binding.RelativeSource = new RelativeSource { AncestorType = typeof(UserControl), Mode = RelativeSourceMode.FindAncestor };
_control.SetBinding(Button.CommandProperty, binding);
Binding binding2 = new Binding(".");
_control.SetBinding(Button.CommandParameterProperty, binding2);
Binding binding3 = new Binding("Header");
binding3.Source = this;
_control.SetBinding(Button.ContentProperty, binding3);
break;
}
default:
{
_control = null;
break;
}
}
if (_header != null)
{
_header.Visibility = hideHeader ? Visibility.Collapsed : Visibility.Visible;
}
if (_control != null)
{
_control.SetCurrentValue(ControlAttach.ClearTextButtonProperty, true);
_contentPresenter.Content = _control;
}
SetItemsSource(ItemsSource);
}
#endregion
需要生成什么控件就需要定义一个类型,然后在cs中添加代码。
第二步:样式实现
<Style x:Key="AIStudio.Styles.FormCodeItem" BasedOn="{StaticResource AIStudio.Styles.FormItem}" TargetType="controls:FormCodeItem">
<Style.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource AIStudio.Styles.Button}" />
<Style TargetType="{x:Type CheckBox}" BasedOn="{StaticResource AIStudio.Styles.CheckBox}" />
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource AIStudio.Styles.ComboBox.Underline}" />
<Style TargetType="{x:Type DatePicker}" BasedOn="{StaticResource AIStudio.Styles.DatePicker.Underline}" />
<Style TargetType="{x:Type PasswordBox}" BasedOn="{StaticResource AIStudio.Styles.PasswordBox.Underline}" />
<Style TargetType="{x:Type RadioButton}" BasedOn="{StaticResource AIStudio.Styles.RadioButton}" />
<Style TargetType="{x:Type RichTextBox}" BasedOn="{StaticResource AIStudio.Styles.RichTextBox.Underline}" />
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource AIStudio.Styles.TextBox.Underline}" />
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource AIStudio.Styles.ToggleButton.Switch}" />
<Style TargetType="{x:Type controls:TreeSelect}" BasedOn="{StaticResource AIStudio.Styles.TreeSelect.Underline}" />
<Style TargetType="{x:Type controls:MultiComboBox}" BasedOn="{StaticResource AIStudio.Styles.MultiComboBox.Underline}" />
<Style TargetType="{x:Type controls:UploadFile}" BasedOn="{StaticResource AIStudio.Styles.UploadFile.Underline}" />
<Style TargetType="{x:Type controls:RichTextBox}" BasedOn="{StaticResource AIStudio.Styles.RichTextBox.Underline}" />
</Style.Resources>
</Style>
这样,生成的控件样式也就有了。
如何使用
<ac:Form
VerticalAlignment="Top"
DataContext="{Binding Base_User2}"
Margin="2">
<ac:FormCodeItem Header="{Binding .,Converter={StaticResource DisplayNameConverter},ConverterParameter='UserName'}" Path="UserName" ControlType="TextBox"/>
<ac:FormCodeItem Header="{Binding .,Converter={StaticResource DisplayNameConverter},ConverterParameter='Password'}" Path="Password" ControlType="PasswordBox"/>
<ac:FormCodeItem Header="{Binding .,Converter={StaticResource DisplayNameConverter},ConverterParameter='Sex'}" Path="Sex" ItemsSource="SexList" ControlType="ComboBox"/>
<ac:FormCodeItem Header="{Binding .,Converter={StaticResource DisplayNameConverter},ConverterParameter='Birthday'}" Path="Birthday" ControlType="DatePicker"/>
<ac:FormCodeItem Header="{Binding .,Converter={StaticResource DisplayNameConverter},ConverterParameter='DepartmentId'}" Path="DepartmentId" ItemsSource="Departments" ControlType="TreeSelect"/>
<ac:FormCodeItem Header="{Binding .,Converter={StaticResource DisplayNameConverter},ConverterParameter='RoleIdList'}" Path="RoleIdList" ItemsSource="RolesList" ControlType="MultiComboBox"/>
<ac:FormCodeItem Header="{Binding .,Converter={StaticResource DisplayNameConverter},ConverterParameter='SelectedDuty'}" Path="SelectedDuty" ItemsSource="Duties" ControlType="ComboBox"/>
<ac:FormCodeItem Header="{Binding .,Converter={StaticResource DisplayNameConverter},ConverterParameter='Email'}" Path="Email" ControlType="TextBox"/>
<ac:FormCodeItem Header="{Binding .,Converter={StaticResource DisplayNameConverter},ConverterParameter='PhoneNumber'}" Path="PhoneNumber" ControlType="TextBox"/>
<ac:FormCodeItem Header="提交" Path="SubmitCommand" ControlType="Submit"/>
</ac:Form>
是不是比FormItem用起来更方便简洁了。实现的效果和Form是一样的
最后老规矩,上源码地址,在Controls下的Form文件夹中。
https://gitee.com/akwkevin/AI-wpf-controls