我的建议是在你的窗口之外创建一个类,该类负责为你的ListBox
提供数据。WPF中常用的一种方法称为MVVM,就像任何模式一样,有许多实现方式。
基本原则是每个模型(例如Pound
和Dog
)都会有一个视图模型,负责以易于从UI交互的方式呈现模型。
为了让你开始工作,WPF提供了一个很好的类,ObservableCollection<T>
,它是一个集合,每当有人添加、移动或删除时就会触发“嘿,我改变了”事件。
以下是一个示例,它不打算教你MVVM,也不使用任何MVVM框架。但是,如果你设置一些断点并尝试一下,你将学习到绑定、命令、INotifyPropertyChanged和ObservableCollection,所有这些在WPF应用程序开发中都扮演着重要的角色。
从MainWindow
开始,你可以将你的DataContext
设置为一个视图模型:
public class MainWindow : Window
{
public MainWindow()
{
this.DataContext = new PoundViewModel();
this.InitializeComponent();
}
}
PoundViewModel
管理着一组 DogViewModel
对象:
public class PoundViewModel
{
public ObservableCollection<DogViewModel> Dogs
{
get;
private set;
}
public ICommand AddDogCommand
{
get;
private set;
}
public PoundViewModel()
{
this.Dogs = new ObservableCollection<DogViewModel>();
this.AddDogCommand = new DelegateCommand<string>(
name => this.Dogs.Add(new DogViewModel { Name = name }),
name => !String.IsNullOrWhitespace(name)
);
}
}
在你的 XAML 中(一定要将 xmlns:local
映射,以便 XAML 可以使用你的视图模型):
<!-- <Window ...
xmlns:local="clr-namespace:YourNameSpace" -->
<!-- Binding the ItemsSource to Dogs, will use the Dogs property
-- On your DataContext, which is currently a PoundViewModel
-->
<ListBox x:Name="listBox1"
ItemsSource="{Binding Dogs}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:DogViewModel}">
<Border BorderBrush="Black" BorderThickness="1" CornerRadius="5">
<TextBox Text="{Binding Name}" />
</Border>
</DataTemplate>
</ListBox.Resources>
</ListBox>
<GroupBox Header="New Dog">
<StackPanel>
<Label>Name:</Label>
<TextBox x:Name="NewDog" />
<!-- Commands are another big part of WPF -->
<Button Content="Add"
Command="{Binding AddDogCommand}"
CommandParameter="{Binding Text, ElementName=NewDog}" />
</StackPanel>
</GroupBox>
当然,你需要一个
DogViewModel
:
public class DogViewModel : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return this.name; }
set
{
this.name = value;
this.RaisePropertyChanged("Name");
}
}
public event PropertyChangedHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
最后你需要一个DelegateCommand<T>
的实现:
public class DelegateCommand<T> : ICommand
{
private readonly Action<T> execute;
private readonly Func<T, bool> canExecute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
{
if (execute == null) throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(T parameter)
{
return this.canExecute != null && this.canExecute(parameter);
}
bool ICommand.CanExecute(object parameter)
{
return this.CanExecute((T)parameter);
}
public void Execute(T parameter)
{
this.execute(parameter);
}
bool ICommand.Execute(object parameter)
{
return this.Execute((T)parameter);
}
}
这个答案并不能让你轻松地创建沉浸式、完全绑定的WPF用户界面,但希望能让你感受到UI如何与你的代码交互!