Click or drag to resize

DataContext

DataContext is a property used as a source for all bindings defined on element, unless source is specified for binding explicitly.

An easy way to start looking at DataContext is as a shortcut. You could make elements bind to needed target without DataContext, but in certain cases usage of DataContext makes bindings simpler. In other cases it lets you have a common point to which multiple bindings bind, so that by changing this common point you change these multiple bindings.

Example
                  <
                  Panel
                  >  
  <Button Id="TopShrinker" IsVisible="{Binding CurrentElement.IsClickable, Converter=Invert,
    RelativeSource=SecondaryHand}" ... /> 
  <Button Id="LeftShrinker" IsVisible="{Binding CurrentElement.IsClickable, Converter=Invert,
    RelativeSource=SecondaryHand}" ... /> 
  <Button Id="RightShrinker" IsVisible="{Binding CurrentElement.IsClickable, Converter=Invert,
    RelativeSource=SecondaryHand}" ... />  
  <Button Id="BottomShrinker" IsVisible="{Binding CurrentElement.IsClickable, Converter=Invert,
    RelativeSource=SecondaryHand}" ... />  
</Panel

You have full binding expressions here, RelativeSource=SecondaryHand lets you reference hand with LabPad, and then path CurrentElement.IsClickable is resolved in relation to a hand, meaning, CurrentElement property of hand is taken.

Here is how you could write the same xml using DataContext:

Example
                  <
                  Panel
                  >
  <Button Id="TopShrinker" IsVisible="{Binding CurrentElement.IsClickable, Converter=Invert}"
    DataContext="{Binding RelativeSource=SecondaryHand}" ... />
  <Button Id="LeftShrinker" IsVisible="{Binding CurrentElement.IsClickable, Converter=Invert}"
    DataContext="{Binding RelativeSource=SecondaryHand}" ... />
  <Button Id="RightShrinker" IsVisible="{Binding CurrentElement.IsClickable, Converter=Invert}"
    DataContext="{Binding RelativeSource=SecondaryHand}" ... />
  <Button Id="BottomShrinker" IsVisible="{Binding CurrentElement.IsClickable, Converter=Invert}" 
    DataContext="{Binding RelativeSource=SecondaryHand}" ... />
</Panel

Essentially value of DataContext becomes a source of all other bindings, defined on element (object that binding binds to we call source of the binding), meaning, CurrentElement property in path is still resolved for a hand (CurrentElement is a property of hand).

Another way to write it with exactly same functionality:

Example
                  <
                  Panel
                  >
  <Button Id="TopShrinker" IsVisible="{Binding IsClickable, Converter=Invert}" 
    DataContext="{Binding CurrentElement, RelativeSource=SecondaryHand}" ... />
  <Button Id="LeftShrinker" IsVisible="{Binding IsClickable, Converter=Invert}" 
    DataContext="{Binding CurrentElement, RelativeSource=SecondaryHand}" ... />
  <Button Id="RightShrinker" IsVisible="{Binding IsClickable, Converter=Invert}" 
    DataContext="{Binding CurrentElement, RelativeSource=SecondaryHand}" ... />
  <Button Id="BottomShrinker" IsVisible="{Binding IsClickable, Converter=Invert}" 
    DataContext="{Binding CurrentElement, RelativeSource=SecondaryHand}" ... />
</Panel

DataContext in a way serves as a first part of every binding defined on element.

All previous usages of DataContext are just a demonstration of what is DataContext, you see that in examples above there is no gain from using DataContext, and rather there is a disadvantage, as instead of one binding you have two. DataContext shouldn't be used that way, as it would just add confusion.

You see that values of DataContext for all four buttons are equal. DataContext values are inherited from parent to child elements, letting you define it once for a parent, and same value will be propagated to all child elements.

Here is xml that does exactly the same as all previous examples:

Example
                  <
                  Panel DataContext="{Binding CurrentElement, RelativeSource=SecondaryHand}">
  <Button Id="TopShrinker" IsVisible="{Binding IsClickable, Converter=Invert}" ... />
  <Button Id="LeftShrinker" IsVisible="{Binding IsClickable, Converter=Invert}" ... />
  <Button Id="RightShrinker" IsVisible="{Binding IsClickable, Converter=Invert}" ... />
  <Button Id="BottomShrinker" IsVisible="{Binding IsClickable, Converter=Invert}" ... />
</Panel

Now panel has DataContext defined. And since it is not the case for any of buttons, they all use value from a parent. Notice that if you change DataContext of a panel - all bindings in buttons will get updated to use the new value. This isn't specific to panels, but is the case for all types of elements.

So here you have four elements that all use same source for their bindings. Whenever you have an xml subtree with all elements using same binding source - DataContext should be used. If not all but most bindings use same source - DataContext can still be used, and bindings with different source can specify their source in usual way - using ElementId or RelativeSource attributes.