Question

How would I bind the IsChecked member of a CheckBox to a member variable in my form?

(I realize I can access it directly, but I am trying to learn about databinding and WPF)

Below is my failed attempt to get this working.

XAML:

<Window x:Class="MyProject.Form1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Title" Height="386" Width="563" WindowStyle="SingleBorderWindow">
<Grid>
    <CheckBox Name="checkBoxShowPending" 
              TabIndex="2" Margin="0,12,30,0" 
              Checked="checkBoxShowPending_CheckedChanged" 
              Height="17" Width="92" 
              VerticalAlignment="Top" HorizontalAlignment="Right" 
              Content="Show Pending" IsChecked="{Binding ShowPending}">
    </CheckBox>
</Grid>
</Window>

Code:

namespace MyProject
{
    public partial class Form1 : Window
    {
        private ListViewColumnSorter lvwColumnSorter;

        public bool? ShowPending
        {
            get { return this.showPending; }
            set { this.showPending = value; }
        }

        private bool showPending = false;

        private void checkBoxShowPending_CheckedChanged(object sender, EventArgs e)
        {
            //checking showPending.Value here.  It's always false
        }
    }
}
Was it helpful?

Solution

<Window ... Name="MyWindow">
  <Grid>
    <CheckBox ... IsChecked="{Binding ElementName=MyWindow, Path=ShowPending}"/>
  </Grid>
</Window>

Note i added a name to <Window>, and changed the binding in your CheckBox. You will need to implement ShowPending as a DependencyProperty as well if you want it to be able to update when changed.

OTHER TIPS

Addendum to @Will's answer: this is what your DependencyProperty might look like (created using Dr. WPF's snippets):

#region ShowPending

/// <summary>
/// ShowPending Dependency Property
/// </summary>
public static readonly DependencyProperty ShowPendingProperty =
    DependencyProperty.Register("ShowPending", typeof(bool), typeof(MainViewModel),
        new FrameworkPropertyMetadata((bool)false));

/// <summary>
/// Gets or sets the ShowPending property. This dependency property 
/// indicates ....
/// </summary>
public bool ShowPending
{
    get { return (bool)GetValue(ShowPendingProperty); }
    set { SetValue(ShowPendingProperty, value); }
}

#endregion

You must make your binding mode as TwoWay :

<Checkbox IsChecked="{Binding Path=ShowPending, Mode=TwoWay}"/>

If you have only one control that you want to bind to a property of your code-behind, then you can specify this as the source in your binding via a RelativeSource like this:

<CheckBox ...
IsChecked="{Binding ShowPending, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}">

That could be the end of the answer. But more generally you will have multiple controls and wish to bind them to various properties on your class. In this case it is neater and more convenient to make use of the fact that the DataContext property (which is the default source object for data binding) is inherited down through the control hierarchy, so setting it at the top level will make it available to all the child controls.

There is no default value for DataContext, but there are at least two ways you can set the DataContext property of your Window element to point at itself:

  • By setting DataContext = this in the code-behind constructor. This is very simple, but some might argue that it's not clear in the XAML where the DataContext is pointing.
  • By setting the DataContext in XAML using DataBinding

The simplest and, I think, most elegant way to set the DataContext at the Window/UserControl level in XAML is very straight forward; just add DataContext="{Binding RelativeSource={RelativeSource Self}}" to your Window element. RelativeSource Self just means "bind directly to the object", which in this case is the Window object. The lack of a Path property results in the default Path, which is the source object itself (i.e. the Window).

<Window x:Class="MyProject.Form1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <CheckBox ... 
            IsChecked="{Binding ShowPending}">
        </CheckBox>
    </Grid>
</Window>

Once you have done this, the DataContext property for all child controls will be the Window class, so data binding to properties in your code-behind will be natural.

If for some reason you don't want to set the DataContext on the Window, but wish to set it lower down the control hierarchy, then you can do so by using the FindAncestor mechanism. E.g. if you want to set it on the Grid element and all children of the Grid:

<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}">
    <CheckBox ...
          IsChecked="{Binding ShowPending}">
    </CheckBox>
</Grid>

It's probably worth noting at this point that what we have achieved so far is the ability to bind a UI Control to a property of your code-behind class, and for that code-behind property to be kept up-to-date with changes to the UI element. So if the user checks the CheckBox, the ShowPending property will be updated.

But quite often you also want the reverse to be true; a change to the source property should be reflected in a corresponding change to the UI Control. You can see this by adding another CheckBox control to your window, bound to the same ShowPending property. When you click one checkbox, you would probably hope or expect the other Checkbox to be synchronized, but it won't happen. To achieve this your code-behind class should either (a) implement INotifyPropertyChanged, (b) add a ShowPendingChanged event or (c) make ShowPending a Dependency Property. Of the 3, I suggest implementing INotifyPropertryChanged on your code-behind is the most common mechanism.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top