Data Context
An introduction to the Eto Data Context

An Overview

All Eto.Forms.Control objects have the DataContext property. DataContext lets us choose a data object for our View to bind to, this will likely be a ViewModel, or a data object class. But it could even be as simple as an integer (although this would be unusual). If a View does not have or need bindings, it will likely not need a DataContext object. The DataContext should not be used for arbitrary data storage, use Tag for this.

The relationship between DataContext and DataStore

Some Controls have a DataStore property, a good example is the GridView. The DataStore is similar to the DataContext, but should be used differently. The DataStore will always be an enumerable, such as a list, array, or better yet, an ObservableCollection<T>.

Trickle Down

A very useful feature to be aware of is the trickle-down effect of DataContext. Any Control, (including Forms and Dialogs) that has a DataContext will set the DataContext of every child control meaning that this can be accessed anywhere in your UI Tree. If a child control overrides its DataContext with a new DataContext then a new lineage of this DataContext is created.

using Eto.Forms;

using Rhino.UI;

class MyMainViewModel {}
class MyNewViewModel {}

var dialog = new Dialog()
{
  DataContext = new MyMainViewModel(), // <-- Start of Main View Model
  Content = new TableLayout()
  {
    Rows = {
      new TableRow( // <-- TableRow has a DataContext of MyMainViewModel
        new StackLayout() // <-- StackLayout has a DataContext of MyNewViewModel
        {
          DataContext = new MyNewViewModel(), // <-- Start of New View Model
          Items = {
            new Drawable(), // <-- Drawable has a DataContext of MyNewViewModel
            new Button()    // <-- Button has a DataContext of MyNewViewModel
          }
        }
      ),
      new TableRow(    // <-- TableRow has a DataContext of MyMainViewModel
        new Button(), 
        new Button(), // <-- Buttons all have a DataContext of MyMainViewModel
        new Button()
      ),
    }
  }
};

var parent = RhinoEtoApp.MainWindowForDocument(__rhino_doc__);
dialog.ShowModal(parent);
import scriptcontext as sc
 
import Rhino
from Rhino.UI import RhinoEtoApp, EtoExtensions
import Eto.Forms as ef
import Eto.Drawing as ed
 
parent = RhinoEtoApp.MainWindowForDocument(sc.doc)

class MyMainViewModel():
  pass

class MyNewViewModel():
  pass

stack_layout = ef.StackLayout()
stack_layout.DataContext = ef.MyNewViewModel()

# Drawable has a DataContext of MyNewViewModel
stack_layout.Items.Add(ef.StackLayoutItem(ef.Drawable()))

# Button has a DataContext of MyNewViewModel
stack_layout.Items.Add(ef.StackLayoutItem(ef.Button()))

table_layout = ef.TableLayout()
table_layout.Rows.Add(ef.TableRow(ef.TableCell(stack_layout)))

# Buttons and TableRow all have a DataContext of MyMainViewModel
table_layout.Rows.Add(ef.TableRow(ef.TableCell(ef.Button()), ef.TableCell(ef.Button()), ef.TableCell(ef.Button())))

dialog = ef.Dialog()
dialog.DataContext = ef.MyMainViewModel()
dialog.Content = table_layout

dialog.ShowModal(parent)