使用MVVM框架内的Button动态添加TextBox

rsg*_*mon 9 c# wpf xaml mvvm

我一直爬着陡峭的WPF山!所以我想创建一个允许用户动态添加文本框的UI.要做到这一点,他们会点击一个按钮.

我已经设法使用后面的代码创建它,但我想转向MVVM结构,所以我在视图中没有任何代码.我已经尝试过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>
Run Code Online (Sandbox Code Playgroud)

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);

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题:我需要什么代码(XAML和C#)才能将方法移出后面的代码并进入viewmodel?

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

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

Roh*_*ats 14

请按照以下步骤操作:

  1. 使用ItemsControl并绑定ItemsSource到ViewModel中的某个集合(最好是ObservableCollection).
  2. ItemTemplate使用TextBox 定义ItemsControl.
  3. ICommand在ViewModel中创建一个并将其绑定到按钮.
  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>
Run Code Online (Sandbox Code Playgroud)

ViewModel:

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

RelayCommand:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

注意 - 我假设您知道如何通过设置DataContext来使用ViewModel插入View以使绑定魔法工作.

  • 谢谢。哇,从没想过使用一组“虚拟”模型来创建 UI 控件。学习 WPF 的一个具有挑战性的部分就是找到属性,哪些对象可以使用它们以及它们的用途。 (2认同)