I am also one of those fools who stubbornly refuses to use a 3rd party engine. The good thing about creating your own engine is that you learn a lot, but it is very easy to get distracted by unnecessary things. Such as implementing a DataBinding system in your GUI library.
I am not aware of any major GUI library that provides a DataBinding paradigm similar to XAML's. So, well it was absolutely necessary to implement my own. If anyone is aware of one, please do let me know. It would be interesting to see how more mature implementations were done.
I took my inspiration from Microsoft's "real" implementation of the Binding class. However as a quick look at the disassembled code will tell you, it is really massive and full of unnecessary stuff that will be marginally useful in a game context. A barebone system should be able to at least provide one-way binding of MVVM data to GUI object properties. Most game UI usually just display data without needing the user to change it. After all, a game is not a data-entry application. Therefore, one-way binding will be my main priority as I go along, with two-way bindings to come at a later stage.
First of all we have a DataTemplate class, similar to XAML's.
For those not familiar with XAML, in this case the
UIElement VisualTreeproperty is a tree of controls that specifies the template of controls to create for each children of the container control this template is applied to.
public class DataTemplate{ public Dictionary Bindings {...} public Type DataType { get; set; } public string Key { get; set; } public UIElement VisualTree { get; set; }}
However since I guess that WPF determines the bindings while parsing XAML code, I had to manually define bindings through the Bindings property. See the following DataTemplate example:
DataTemplate commandTemplate = new DataTemplate(){ DataType = typeof (StackPanel), Key = "CommandTemplate", VisualTree = new Button() {Width = 64, Height = 64, Margin = new Thickness(4), Name = "Button"}, Content = new Label(){ Name = "Label", TextDescriptionClass = "Small" }}, Bindings = new Dictionary { {"Text", new Binding("CommandName", "Label")}, }};
This DataTemplate indicates that for each child item in the container a Button control has to be created, whose Content control is a Label. The Binding tells the system that the CommandName property of the ViewModel has to be bound to the Text property of an element called "Label" . Here is the sample ViewModel:
stackPanel.DataTemplate = commandTemplate;stackPanel.ItemsSource = new SampleVM[]{ new SampleVM() { CommandName = "AA" }, new SampleVM() { CommandName = "BB" },};
And here is the result:
It's very crude, but the basic principle seems to be working. And yes, that's a StackPanel with a Horizontal orientation. Controls are laid out automatically. I'm sure that a lot more problems will surface down the road but I am confident that in the long run, a simple MVVM system will save me lots of time. If you have suggestions for any improvement or simply want to know more, let me know!
You can check out the source code in my GitHub repository. Look in the OdysseyUI.sln.