使用ItemsSource填充WPF ListBox – 好主意?
我是(相对)经验丰富的Cocoa / Objective-C编码器,我正在自学C#和WPF框架。
在Cocoa中,当填充NSTableView
,相对简单地将一个委托和数据源分配给视图。 然后使用这些委托/数据源方法填充表,并确定其行为。
我正在整理一个包含对象列表的简单应用程序,让我们称之为Dog
对象,每个对象都有一个public string name
。 这是Dog.ToString()
的返回值。
对象将显示在ListBox
,我想使用与Cocoa的NSTableViewDataSource
类似的模式填充此视图。 它目前似乎正在使用:
public partial class MainWindow : Window, IEnumerable { public Pound pound = new Pound(); public MainWindow() { InitializeComponent(); Dog fido = new Dog(); fido.name = "Fido"; pound.AddDog(fido); listBox1.ItemsSource = this; Dog spot = new Dog(); spot.name = "Spot"; pound.AddDog(spot); } public IEnumerator GetEnumerator() { return currentContext.subjects.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } }
但我想知道这是多么正确 。 我确实安装了Visual Studio不到一个小时,所以可以肯定地说我不知道我在做什么。
- 这是正确的模式吗?
- 将第二项添加到列表(
spot
)似乎正确地更新了ListBox
,但我想知道是什么触发了更新? - 如果我在后台线程上更新
Pound
会发生什么? - 如何手动要求
ListBox
自行更新? (我甚至需要吗?)
我知道我需要做的一个改变是将IEnumerable
实现重构到它自己的类中,比如DogListItemsSource
,但我想确保在抛光之前我有一个可靠的方法。
请在评论中指出我应该解决或记住的任何其他要点,无论大小。 我想第一次以正确的方式学习这个。
我的建议是创建一个除了Window之外的类,它将负责向ListBox
提供数据。 一种常见的方法是WPF称为MVVM ,它与任何模式都有很多实现。
基础是每个模型(例如Pound
和Dog
)都有一个View Model,负责以易于与UI交互的方式呈现模型。
为了帮助您入门,WPF提供了一个优秀的类ObservableCollection
,这是一个集合,无论何时添加,移动或删除任何人,都会触发“Hey I Changed”事件。
下面是一个不打算教你MVVM的例子,它也没有使用MVVM的任何框架。 但是,如果你设置一些断点并使用它,你将学习绑定,命令,INotifyPropertyChanged和ObservableCollection; 所有这些都在WPF应用程序开发中发挥了重要作用。
从MainWindow
开始,您可以将DataContext
设置为View Model:
public class MainWindow : Window { // ... public MainWindow() { // Assigning to the DataContext is important // as all of the UIElement bindings inside the UI // will be a part of this hierarchy this.DataContext = new PoundViewModel(); this.InitializeComponent(); } }
PoundViewModel
管理DogViewModel
对象集合的DogViewModel
:
public class PoundViewModel { // No WPF application is complete without at least 1 ObservableCollection public ObservableCollection Dogs { get; private set; } // Commands play a large role in WPF as a means of // transmitting "actions" from UI elements public ICommand AddDogCommand { get; private set; } public PoundViewModel() { this.Dogs = new ObservableCollection (); // The Command takes a string parameter which will be provided // by the UI. The first method is what happens when the command // is executed. The second method is what is queried to find out // if the command should be executed this.AddDogCommand = new DelegateCommand( name => this.Dogs.Add(new DogViewModel { Name = name }), name => !String.IsNullOrWhitespace(name) ); } }
在您的XAML中( 确保映射xmlns:local
以允许XAML使用您的View Models ):
当然,你需要一个DogViewModel
:
public class DogViewModel : INotifyPropertyChanged { private string name; public string Name { get { return this.name; } set { this.name = value; // Needed to alert WPF to a change in the data // which will then update the UI 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
:
public class DelegateCommand : ICommand { private readonly Action execute; private readonly Func canExecute; public event EventHandler CanExecuteChanged; public DelegateCommand(Action execute, Func 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,但希望它能让你感受到UI如何与你的代码进行交互!
-
在WPF中,您通常只有一些集合作为ItemsSource和数据模板来显示项目。
-
通常,如果ItemsSource实例实现
INotifyCollectionChanged
,那些控件只会更新,也许您在ListBox
检索它之前添加了该项。 -
什么是庞德? 除非Pound具有一些线程亲和性,例如
ObservableCollection
,否则没问题,如果确实如此,则需要使用调度 。 -
ListBox.Items.Refresh()
可以做到这一点,但通常只使用带通知的集合。
WPF大量使用数据绑定,因此如果您想学习框架,可能会对相应的概述 (以及所有其他 概述 )感兴趣。