c# - 在 MVVM 框架中使用按钮动态添加文本框

标签 c# wpf xaml mvvm

我一直在攀登陡峭的 WPF 山!所以我想创建一个允许用户动态添加文本框的 UI。为此,他们会按下一个按钮。

我已经设法使用隐藏代码创建了这个,但我想转向 MVVM 结构,因此 View 中没有任何代码。我试过 ICommand 和 ObservableCollection 但我遗漏了一些东西而且我不知道在哪里。这是我的简单示例。

XAML:非常基本,只需一个按钮即可添加一行。

<Window x:Class="WPFpractice072514.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFpractice072514"
        Title="MainWindow" Height="350" Width="525">
    <Grid Name="mymy" >
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Button Grid.Column="0" Grid.Row="0" Name="ButtonUpdateArtist"
                Content="Add TextBox" Click="ButtonAddTexboxBlockExecute" />

    </Grid>
</Window>

C# 代码隐藏

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFpractice072514
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region members
        int count = 0;
        #endregion

        public MainWindow()
        {
            InitializeComponent();
        }

        private void ButtonAddTexboxBlockExecute(Object Sender, RoutedEventArgs e)
        {
            TextBox t = new TextBox();
            t.Height = 20;
            t.Width = 20;
            t.Name = "button";

            RowDefinition rowDef1;
            rowDef1 = new RowDefinition();
            mymy.RowDefinitions.Add(rowDef1);

            ColumnDefinition colDef1;
            colDef1 = new ColumnDefinition();
            mymy.ColumnDefinitions.Add(colDef1);
            ++count;

            mymy.Children.Add(t);

            Grid.SetColumn(t, 1);
            Grid.SetRow(t, count);

        }
    }
}

问题:我需要什么代码(XAML 和 C#)才能将该方法从后面的代码中移出并移到 View 模型中?

可以使用命令动态添加文本框吗?

我假设文本框必须保存在一个容器中,在这种情况下,这就是网格的用途。但是,如果我使用的是 MVVM,我是否需要将文本框包含在 ListView 或其他使用 ItemsSource 的容器中?

最佳答案

按照以下步骤完成:

  1. 使用 ItemsControl 并将其 ItemsSource 绑定(bind)到您的 ViewModel 中的某个集合(最好是 ObservableCollection)。
  2. 为带有 TextBox 的 ItemsControl 定义 ItemTemplate
  3. 在 ViewModel 中创建一个 ICommand 并将其绑定(bind)到按钮。
  4. 在命令中执行添加项目到集合中,您将看到 TextBox 被自动添加。

XAML:

<StackPanel>
    <Button Content="Add TextBox" Command="{Binding TestCommand}"/>
    <ItemsControl ItemsSource="{Binding SomeCollection}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox Text="{Binding Path=.}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

View 模型:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public ObservableCollection<string> SomeCollection { get; set; }
    public ICommand TestCommand { get; private set; }

    public MainWindowViewModel()
    {
        SomeCollection = new ObservableCollection<string>();
        TestCommand = new RelayCommand<object>(CommandMethod);
    }

    private void CommandMethod(object parameter)
    {
        SomeCollection.Add("Some dummy string");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

中继命令:

public class RelayCommand<T> : ICommand
{    
    readonly Action<T> _execute = null;
    readonly Predicate<T> _canExecute = null;

    public RelayCommand(Action<T> execute)
        : this(execute, null)
    {
    }    

    public RelayCommand(Action<T> execute, Predicate<T> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute((T)parameter);
    }    

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute((T)parameter);
    }
}

注意 - 我假设您知道如何通过设置 DataContext 将 View 与您的 ViewModel 连接起来,使绑定(bind)魔法起作用。

关于c# - 在 MVVM 框架中使用按钮动态添加文本框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24960476/

相关文章:

c# - 将按钮图像设置为绑定(bind)其样式

c# - 如何在 WPF/XAML 中通过子控件删除父控件?

c# - 如何以编程方式关闭 Windows 10 应用程序上的打印 UI?

c# - 在 Windows 窗体应用程序中访问以自定义文件类型保存的数据

c# - 避免在 C# winform 的键盘快捷方式上发出警报

c# - 此命名空间冲突是由于 XAML 到 .NET 代码生成中的错误造成的吗?

c# - EventLog WriteEntry 不写入指定日志,而是写入应用程序日志

wpf - WPF ListBox 中的 ItemTemplate 和 ItemContainerStyle 有什么区别?

wpf - ICommand CanExecuteChanged 未更新

wpf - 所选项目的列表框项目模板