在C#中动态添加元素到UI

Ato*_*rce 6 c# wpf user-interface winforms

问题

我有一个C#窗口,上面有一些文本字段和按钮.它开始类似于: 初始界面

当用户单击"+添加机器功能"按钮时,我需要创建一个新的控件行并将按钮移动到以下位置: 增加了机器功能

如果用户单击"+ Add Scale Unit",程序需要在右侧添加一些控件: 增加了比例单位

尝试解决方案

我已经尝试过使用Windows Forms的TableLayoutPanel但它似乎处理调整自身大小以适应奇怪的方式来控制其他控件,例如,它会使一行控件比其他控件宽得多,并且会使某些行如此短,从而切断部分我的控件.

我还尝试通过简单地计算它们的相对位置来简单地将控件放入表单中.但是我觉得这是糟糕的编程习惯,因为它使得表单的布局在以后相对难以改变.在用户通过按下它旁边的"X"来删除行或标度单位的情况下,该方法还要求程序找到该单元下面的每个元素并单独向上移动,这非常低效.

我的问题是:如何通过Windows Forms布局或WPF或其他方式创建动态增长/缩小的应用程序?

Usm*_*far 9

在WPF中,您可以这样做:

public class MachineFunction
{
    public string Name { get; set; }
    public int Machines { get; set; }

    public ObservableCollection<ScaleUnit> ScaleUnits { get; set; }

    public MachineFunction()
    {
        ScaleUnits = new ObservableCollection<ScaleUnit>();
    }
}

public class ScaleUnit
{
    public string Name { get; set; }
    public int Index { get; set; }

    public ScaleUnit(int index)
    {
        this.Index = index;
    }
}
Run Code Online (Sandbox Code Playgroud)

Window.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <ItemsControl Name="lstMachineFunctions">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition/>
                            <RowDefinition/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <TextBlock Grid.Row="0" Grid.Column="1" Text="Machine Function"/>
                        <TextBlock Grid.Row="0" Grid.Column="2" Text="Number of Machines"/>
                        <Button Grid.Row="1" Grid.Column="0" Click="OnDeleteMachineFunction">X</Button>
                        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Name}"/>
                        <TextBox Grid.Row="1" Grid.Column="2" Text="{Binding Machines}"/>
                    </Grid>

                    <ItemsControl ItemsSource="{Binding ScaleUnits}">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Grid Margin="12,0,0,0">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition/>
                                        <ColumnDefinition/>
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition/>
                                        <RowDefinition/>
                                        <RowDefinition/>
                                    </Grid.RowDefinitions>
                                    <TextBlock Grid.Row="0" Grid.Column="1" Text="Machine/Scale Unit"/>
                                    <Button Grid.Row="1" Grid.Column="0" Click="OnDeleteScaleUnit">X</Button>
                                    <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Name}"/>
                                    <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Index, StringFormat='Scale Unit {0}'}"/>
                                </Grid>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                    </ItemsControl>
                    <Button VerticalAlignment="Center" Click="OnAddScaleUnit">Add Scale Unit</Button>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    <Button HorizontalAlignment="Left" Click="OnAddMachineFunction">Add Machine Function</Button>
</StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)

Window.cs

public partial class MainWindow : Window
{
    public ObservableCollection<MachineFunction> MachineFunctions { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        lstMachineFunctions.ItemsSource = MachineFunctions = new ObservableCollection<MachineFunction>();
    }

    private void OnDeleteMachineFunction(object sender, RoutedEventArgs e)
    {
        MachineFunctions.Remove((sender as FrameworkElement).DataContext as MachineFunction);
    }

    private void OnAddMachineFunction(object sender, RoutedEventArgs e)
    {
        MachineFunctions.Add(new MachineFunction());   
    }

    private void OnAddScaleUnit(object sender, RoutedEventArgs e)
    {
        var mf = (sender as FrameworkElement).DataContext as MachineFunction;

        mf.ScaleUnits.Add(new ScaleUnit(mf.ScaleUnits.Count));
    }

    private void OnDeleteScaleUnit(object sender, RoutedEventArgs e)
    {
        var delScaleUnit = (sender as FrameworkElement).DataContext as ScaleUnit;

        var mf = MachineFunctions.FirstOrDefault(_ => _.ScaleUnits.Contains(delScaleUnit));

        if( mf != null )
        {
            mf.ScaleUnits.Remove(delScaleUnit);

            foreach (var scaleUnit in mf.ScaleUnits)
            {
                scaleUnit.Index = mf.ScaleUnits.IndexOf(scaleUnit);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)