【问题标题】:Dynamically Adding TextBox using a Button within MVVM framework在 MVVM 框架中使用按钮动态添加文本框
【发布时间】:2014-09-17 14:07:15
【问题描述】:

我一直在爬陡峭的 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>

背后的 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#)才能将方法从后面的代码中移出并移到视图模型中?

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

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

【问题讨论】:

  • 这不是 MVVM,这可能就是你苦苦挣扎的原因。在 MVVM 中,我有一个 ViewModel,它具有绑定到 ItemsControl 的模型的公共可观察集合属性。我有一个模型类型的 DataTemplate。而且我将 ICommand 绑定到按钮。单击该按钮时,该命令将在视图模型中触发,我在其中将一个新模型添加到集合中。 UI 将使用 DataTemplate 自动为元素添加 UI。这就是我们做 MVVM 的原因——这很容易。你正在做的是Windows窗体。如果您想创建表单,请执行此操作。

标签: c# wpf xaml mvvm


【解决方案1】:

按照以下步骤操作即可完成:

  1. 使用ItemsControl 并将它的ItemsSource 绑定到您的ViewModel 中的某个集合(最好是ObservableCollection)。
  2. 为 ItemsControl 定义 ItemTemplate,其中包含 TextBox。
  3. 在 ViewModel 中创建一个ICommand 并将其绑定到按钮。
  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>

视图模型

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。

【讨论】:

  • 谢谢。哇,从来没有想过使用一组“虚拟”模型来创建 UI 控件。学习 WPF 的一个具有挑战性的部分就是找到属性、对象可以使用它们以及它们的用途。
  • 确切地说,WPF 更多的是数据驱动,而 WinForms 更多的是 UI 驱动技术。
【解决方案2】:
[link][1]

 class TestViewModel : BindableBase  
    {  
        private TestModel testModel;  

        public ICommand AddCommand { get; private set; }  
        public TestViewModel(StackPanel stkpnlDynamicControls)  
        {  
            testModel = new TestModel();  
            TestModel.stkPanel = stkpnlDynamicControls;  
            AddCommand = new DelegateCommand(AddMethod);  
        }  
        public TestModel TestModel  
        {  
            get { return testModel; }  
            set { SetProperty(ref testModel, value); }  
        }  
        private void AddMethod()  
        {  
            Label lblDynamic = new Label()  
            {  
                Content = "This is Dynamic Label"  
            };  
            TestModel.stkPanel.Children.Add(lblDynamic);  
        }  
    }

【讨论】:

  • 在代码中提供一些解释通常是一种很好的做法。您可以编辑您的答案以添加更多信息。
猜你喜欢
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
  • 2016-07-24
  • 1970-01-01
  • 2019-08-04
相关资源
最近更新 更多