I'm a (relatively) experienced Cocoa/Objective-C coder, and am teaching myself C# and the WPF framework.
In Cocoa, when populating an NSTableView
, it's relatively simply to assign a delegate and datasource to the view. Those delegate/datasource methods are then used to populate the table, and to determine its behavior.
I'm putting together a simple application that has a list of objects, lets call them Dog
objects, that each have a public string name
. This is the return value of Dog.ToString()
.
The objects will be displayed in a ListBox
, and I would like to populate this view using a similar pattern to Cocoa's NSTableViewDataSource
. It currently seems to be working using:
public partial class MainWindow : Window, IEnumerable<Dog>
{
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<Dog> GetEnumerator()
{
return currentContext.subjects.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
But I'm wondering how correct this is. I've literally had Visual Studio installed for less than an hour, so it's safe to say I have no idea what I'm doing.
- Is this the proper pattern?
- Adding the second item to the list (
spot
) seems to update theListBox
properly, but I'm wondering what triggers the updates? - What happens if I update the
Pound
on a background thread? - How can I manually ask the
ListBox
to update itself? (Do I even need to?)
One change that I know I need to make is refactoring the IEnumerable<Dog>
implementation into its own class, like DogListItemsSource
, but I want to make sure I have a solid approach before polishing it.
Feel free to point out, in comments, any other points I should address or keep in mind, big or small. I'd like to learn this the right way, the first time.
My suggestion would be to create a class besides your Window which would be responsible for providing the data to your
ListBox
. A common approach is WPF is called MVVM, which like any pattern has many implementations.The basics are each Model (e.g.
Pound
andDog
) would have a View Model responsible for presenting the model in a manner which is easy to interact with from the UI.To get you started, WPF provides an excellent class,
ObservableCollection<T>
, which is a collection that fires off a "Hey I Changed" event whenever anybody is added, moved, or removed.Below is an example that doesn't intend to teach you MVVM, nor does it use any framework for MVVM. However, if you set some breakpoints and play with it, you'll learn about bindings, commands, INotifyPropertyChanged, and ObservableCollection; all of which play a large role in WPF application development.
Starting in the
MainWindow
, you can set yourDataContext
to a View Model:Where the
PoundViewModel
manages a collection ofDogViewModel
objects:And in your XAML (be sure to map
xmlns:local
to allow XAML to use your View Models):Of course, you'd need a
DogViewModel
:Finally you'll need an implementation of
DelegateCommand<T>
:This answer by no means will have you whipping up immersive, fully bound WPF UI's, but hopefully it'll give you a feel for how the UI can interact with your code!
In WPF you usually just have some collection as ItemsSource and data templates to display the item.
Normally those controls only update if the ItemsSource instance implements
INotifyCollectionChanged
, maybe you added the item before theListBox
retrieved it.What is Pound? Unless Pound has some thread-affinity as e.g.
ObservableCollection
does, that is no problem, if it does you need to use dispatching.ListBox.Items.Refresh()
could do that, but usually you just use a collection with notifications.WPF heavily uses data binding, so if you want to learn the framework the respective overview (along with all the others) might be of interest.