我是 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/