从用户在运行时选择的字段列表中创建动态数据输入表单



我有一个WPF应用程序,我在其中有一个视图,可以让用户在运行时选择字段列表,我存储在一个文本文件中,我试图根据用户创建的运行时字段列表创建一个数据输入表单。

我已经使用代码隐藏开发了一个解决方案,但我正在尝试使用MVVM来实现它。

方法1:我可以在代码后面创建textBlock和Textbox,并将其绑定到Viewmodel中的属性。视图模型将具有所有可能的字段属性。

<TabControl Margin="335,10,10,71" TabStripPlacement="Bottom">
<TabControl.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Margin="0,0,0,0"
Background="Transparent"
BorderBrush="Black"
BorderThickness="1,1,1,1"
CornerRadius="5">
<ContentPresenter
x:Name="ContentSite"
Margin="12,2,12,2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ContentSource="Header"
RecognizesAccessKey="True">
<ContentPresenter.LayoutTransform>
<RotateTransform Angle="0" />
</ContentPresenter.LayoutTransform>
</ContentPresenter>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Height" Value="40" />
<Setter Property="FontSize" Value="20" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Panel.ZIndex" Value="200" />
<Setter TargetName="Border" Property="Background" Value="Black" />
<Setter TargetName="Border" Property="BorderBrush" Value="White" />
<Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
<Setter Property="Foreground" Value="White" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="FontSize" Value="20" />
<Setter Property="FontWeight" Value="Bold" />
<Setter TargetName="Border" Property="Background" Value="Black" />
<Setter TargetName="Border" Property="BorderBrush" Value="White" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabItem Header="Product Data 1">
<Grid x:Name="Grid1">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="Column_1" Width="*" />
<ColumnDefinition x:Name="Column_2" Width="*" />
</Grid.ColumnDefinitions>
<Border
Margin="0,0,0,10"
Background="LightSkyBlue"
BorderBrush="Gray"
BorderThickness="2,2,2,2">
<StackPanel
x:Name="MainStack"
Margin="20,0,0,0"
x:FieldModifier="public"
Grid.IsSharedSizeScope="True"
Orientation="Vertical" />
</Border>
<Border
Grid.Column="1"
Margin="0,0,0,10"
Background="LightSkyBlue"
BorderBrush="Gray"
BorderThickness="2,2,2,2">
<StackPanel
x:Name="SecondStack"
Grid.Column="1"
Margin="20,0,0,0"
x:FieldModifier="public"
Grid.IsSharedSizeScope="True"
Orientation="Vertical" />
</Border>
<!--<StackPanel x:Name="ThirdStack" x:FieldModifier="public"  Grid.Column="2" Orientation="Vertical" Grid.IsSharedSizeScope="True" Width="auto" Height="476"  VerticalAlignment="Center" HorizontalAlignment="Center" />
<Border BorderBrush="Black" BorderThickness="1,1,1,1" Grid.Column="2" Margin="0,0,0,10"/>-->
</Grid>
</TabItem>
</TabControl>

代码隐藏=

string[] Data = File.ReadAllLines("Field.txt");
foreach (var part in Data)
{
Grid mytxtBStack = new Grid();
MainStack.Children.Add(mytxtBStack);
ColumnDefinition column_1 = new ColumnDefinition();
column_1.SharedSizeGroup = "FirstColumn";
ColumnDefinition column_2 = new ColumnDefinition();
column_2.SharedSizeGroup = "SecondColumn";
mytxtBStack.ColumnDefinitions.Add(column_1);
mytxtBStack.ColumnDefinitions.Add(column_2);
txtBlock = new TextBlock();
txtBlock.Name = "MyBlock" + i;
txtBlock.Text = part;
txtBlock.FontSize = 14;
txtBlock.FontWeight = FontWeights.DemiBold;
txtBlock.Foreground = Brushes.Black;
txtBlock.Margin = new Thickness(0, 20, 0, 0);
mytxtBStack.Children.Add(txtBlock);
txtBox = new TextBox();
txtBox.Name = "MyText" + i.ToString();
txtBox.FontSize = 12;
txtBox.Height = 25;
txtBox.Width = 250;
txtBox.BorderThickness = new Thickness(1, 1, 1, 1);
txtBox.Margin = new Thickness(130, 20, 0, 0);
txtBox.Foreground = Brushes.Black;
txtBox.BorderBrush = Brushes.Black;
txtBox.Background = Brushes.White;
txtList.Add(txtBox);
mytxtBStack.Children.Add(txtBox);
}

方法2:我可以使用基于Textfile的Expandoobject创建一个动态类,并创建一个项控件来绑定视图,并提到Viewmodel中所有可能的字段属性。我正在考虑用TabControl内部,

<ItemsControl Grid.Row="1" ItemsSource="{Binding Path=Fields">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<TextBox Width="300" Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

有人能给我推荐一种使用MVVM wpf的方法吗?

我使用CommunityToolkit.MvvmNuGet包实现了这一点。

MainWindowViewModel.cs

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
namespace WpfApp1;
public class Field
{
public string Block { get; set; } = string.Empty;
public string Text { get; set; } = string.Empty;
}
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
// CommunityToolkit's source generator will create a "Field" property.
private ObservableCollection<Field> fields = new();
[RelayCommand]
// CommunityToolkit's source generator will create a "LoadFieldsCommand" command.
private void LoadFields()
{
for (int i = 0; i < 10; i++)
{
Fields.Add(new Field() { Block = $"Block#{i + 1}", Text = $"Text{i + 1}" });
}
}
[ObservableProperty]
// Bind this to the Text property.
private string textBlockText = string.Empty;
[ObservableProperty]
// Bind this to the ItemsSource property.
private List<string> comboBoxItems = new()
{
"Item A",
"Item B",
"Item C",
};
}

主窗口.xaml.cs

using System.Windows;
namespace WpfApp1;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public MainWindowViewModel ViewModel { get; } = new();
}

主窗口.xaml

<Window
x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="ThisWindow"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button
Grid.Row="0"
Command="{Binding ElementName=ThisWindow, Path=ViewModel.LoadFieldsCommand}"
Content="Load fields" />
<ItemsControl Grid.Row="1" ItemsSource="{Binding ElementName=ThisWindow, Path=ViewModel.Fields}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="local:Field">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Block}" />
<TextBox Text="{Binding Text}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>

最新更新