c# - 将 ICommand 绑定(bind)到按钮?

标签 c# wpf mvvm

我是 MVVM 模式的新手,事情变得如此缓慢,我希望能够单击表单上的按钮,然后它在运行时动态创建一个文本框。我有一个“添加标题”和“添加问题”,它们都添加了文本框,但在不同的位置,您可以在一个标题下添加尽可能多的问题。我创建了一个名为 Standard 的类在这个类中它拥有:

public class Standard
{
    string _title;
    ObservableCollection<string> _questions;
    public event PropertyChangedEventHandler PropertyChanged;

  #region NofiftyPropChnage
  protected void NotifyOfPropertyChanged(string name)
  {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null)
      {
          handler(this, new PropertyChangedEventArgs(name));
      }
  }

  protected void NotifyOfPropertyChanged<TProperty>(Expression<Func<TProperty>> property)
  {
      NotifyOfPropertyChanged(property.GetMemberInfo().Name);
  }
  #endregion

  #region Properties
  public string Title
    {
        get { return _title; }
        set
        {
            _title = value;
            NotifyOfPropertyChanged(() => Title);
        }
    }

    public ObservableCollection<string> Questions
    {
        get { return _questions; }
        set
        {
            _questions = value;
            NotifyOfPropertyChanged(() => Questions);
        }
    }
  #endregion
}

此类包含 Title 属性和 Questions 属性列表,因为您可以在 Title 下添加 Questions。

我还有一个 ViewModel持有的类:
class ViewModel :INotifyPropertyChanged
{
    #region NotifyPropertyChange
    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyOfPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
}

protected void NotifyOfPropertyChanged<TProperty>(Expression<Func<TProperty>> property)
{
        NotifyOfPropertyChanged(property.GetMemberInfo().Name);
}
    #endregion

private ObservableCollection<Standard> _standardCollection;
public ObservableCollection<Standard> StandardCollection
{
        get
        {
            return _standardCollection;
        }
        set
        {
            _standardCollection = value;
            NotifyOfPropertyChanged(() => StandardCollection);
        }
}
}

这个类包含一个标准列表,一个标准是当你点击保存文本框和文本框中的信息时完成的。它保存为 Standard

最后是我的 XAML 代码:
<Grid>

<button Content="Add Title"/>
<button Content="Add Question"/>

<StackPanel>
        <ItemsControl ItemsSource="{Binding StandardCollection}">
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type local:Standard}">
                    <Grid>
                        <TextBox Text="{Binding Title}"/>
                        <ItemsControl ItemsSource="{Binding Questions}">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <TextBox Text="{Binding Questions}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
</StackPanel>


</Grid>

一切都运行并且没有错误,但是当我单击“添加标题”或“添加问题”时,没有出现文本框,有什么帮助吗?

最佳答案

好的,我会再试一次。我已经去掉了标题部分,只专注于问题,以保持这个作为一个最小的例子。首先,您需要一个为您的 View 模型实现 INotifyPropertyChanged 的​​基类:

public abstract class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged<T>(Expression<Func<T>> propertyExpresion)
    {
        var property = (MemberExpression)propertyExpresion.Body;
        this.OnPropertyChanged(property.Member.Name);
    }

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

接下来,您将需要一个实现 ICommand 的类,以便您的按钮绑定(bind)到该类,从而在按下这些按钮时调用处理程序:
// by Josh Smith, http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

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

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

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members

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

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

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

    #endregion // ICommand Members
}

这两个类是由其他人编写的,如果您将 MVVM Lite 项目添加到您的项目中,您将为您提供它们。

接下来,我们需要创建一个带有 ObservableCollection 问题的 View 模型和一个在用户按下按钮时被调用的处理程序:
public class MyViewModel : ObservableObject
{
    public ICommand AddQuestionCommand {get; private set;}

    ObservableCollection<string> _questions = new ObservableCollection<string>();
    public ObservableCollection<string> Questions
    {
        get { return _questions; }
        set
        {
            _questions = value;
            OnPropertyChanged(() => Questions);
        }
    }

    public MyViewModel()
    {
        this.AddQuestionCommand = new RelayCommand(new Action<object>((o) => OnAddQuestion()));
    }

    private void OnAddQuestion()
    {
        this.Questions.Add("new item");
    }

}

显然,您需要创建它的一个实例并将其设置为您的窗口的 DataContext。当命令被触发时,处理程序会被调用,然后它会向集合中添加一个新字符串。 XAML 现在需要将一个按钮绑定(bind)到该命令并使用 Questions 集合创建一个 TextBlocks 列表来显示它们:
<StackPanel>
    <Button Content="Add Question" Command="{Binding AddQuestionCommand}" HorizontalAlignment="Left"/>
    <ItemsControl ItemsSource="{Binding Questions}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox Text="{Binding .}" Width="200" HorizontalAlignment="Left"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

希望这能给你一个起点。如果我遗漏了什么,或者您需要澄清任何事情,请发布后续内容,我会尽力而为。

关于c# - 将 ICommand 绑定(bind)到按钮?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20968516/

相关文章:

c# - Visual Studio 2012 中的 DEBUG 常量不会激活

c# - “为什么”和 'Where' 泛型实际上被使用了?

c# - 为什么 HttpWebRequest.GetResponse() 在连接到 VPN 后失败?

c# - 如何为复选框图像创建自定义 WPF XAML 样式

wpf - WPF:ItemsPanelTemplate中的WrapPanel扩展列表宽度

c# - PropertyGroupDescription 未按预期工作

c# - WPF Mahapps - 如何隐藏汉堡菜单集合中的选项卡?

c# - 我可以从数据源创建和反对 "self-loads"属性吗?

javascript - 执行绑定(bind)时的 WinJS 通知

c# - 来自 ViewModel 的焦点控制