Josh Smith

Follow me down the rabbit hole of cutting edge technology.
Binding a XamDataGrid Field Property

I recently needed to bind the Visibility of a Field in a XamDataGrid to a property on my ViewModel.  I wanted to provide a way for the user to show/hide a column of images in the data grid.  My ViewModel object is a POCO (Plain Old Clr Object) that implements INotifyPropertyChanged, and represents the data and UI state of my Window.  Unfortunately a Field object is not in the element tree and does not derive from Freezable, which means it does not have an inheritance context, thus its properties cannot participate in normal WPF data binding. 

If/when WPF eventually provides a way to give any object an inheritance context, this won't be an issue, but for now there is no clean way to bind a Field's properties to objects inherited down the logical tree, or to the properties of other elements.  This blog post shows a workaround that I came up with, allowing me to easily bind the Visibility of a Field to any object.

Here is the basic idea of what I'm trying to accomplish.  First the grid displays a column of images:

 

If you then click the "Show Photos" CheckBox in the ToolBar, the column of photos is hidden, as seen below:

 

 Here is the code-behind of the Window:

public partial class Window1 : Window
{
    public Window1()
    {
        Person[] people = new Person[]
        {
            new Person("Boss Hogg", 42, "hogg.jpg"),
            new Person("Johann Bach", 50, "bach.jpg"),
            new Person("Mugatu", 39, "mugatu.gif"),
            new Person("Simon Wolcott", 24, "wolcott.jpg")
        };

        base.DataContext = new CommunityViewModel(people);
        Application.Current.Resources.Add("DATA_CommunityViewModel", base.DataContext);

        InitializeComponent();
    }
}

Notice that I'm adding the CommunityViewModel class to both the DataContext of the Window and the Resources of the App.  I set the DataContext to the ViewModel so that the XamDataGrid and CheckBox controls can bind to its properties.  I add it to the App's Resources so that the Field's Visibility binding can access it.  Here is the CommunityViewModel class:

class CommunityViewModel : INotifyPropertyChanged
{
    bool _showPhotos;

    public CommunityViewModel(IList<Person> constituents)
    {
        this.Constituents = new ReadOnlyCollection<Person>(constituents);
        _showPhotos = true;
    }

    public ReadOnlyCollection<Person> Constituents { get; set; }

    public bool ShowPhotos
    {
        get { return _showPhotos; }
        set
        {
            if (value == _showPhotos)
                return;

            _showPhotos = value;

            this.OnPropertyChanged("ShowPhotos");
        }
    }


    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

The magic happens in the XAML.  Pay close attention to the 'Photo' Field declaration:

<Window
  x:Class="XamDataGridWithBoundField.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:igDP="http://infragistics.com/DataPresenter"
  Title="Window1"
  Width="400" Height="400"
  >
  <Window.Resources>
    <Style
      x:Key="PhotoCellStyle"
      TargetType="{x:Type igDP:CellValuePresenter}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type igDP:CellValuePresenter}">
            <Image
              Source="{Binding
                RelativeSource={RelativeSource TemplatedParent},
                Path=Content}"
              Width="60" Height="60"
              />
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Resources>
  <DockPanel>
    <ToolBar DockPanel.Dock="Top">
      <CheckBox
        Content="Show Photos"
        IsChecked="{Binding Path=ShowPhotos}"
        />

    </ToolBar>

    <igDP:XamDataGrid
      AutoFit="True"
      DataSource="{Binding Constituents}"
      >
      <igDP:XamDataGrid.FieldLayouts>
        <igDP:FieldLayout>
          <igDP:FieldLayout.Fields>
            <igDP:Field Label="Name" Name="Name" />
            <igDP:Field Label="Photo" Name="ImageUri">
              <igDP:Field.Settings>
                <igDP:FieldSettings
                  CellMaxWidth="70" LabelMaxWidth="70"
                  CellValuePresenterStyle="{StaticResource PhotoCellStyle}"
                  />
              </igDP:Field.Settings>
              <igDP:Field.Visibility>
                <Binding
                  Path="ShowPhotos"
                  Source="{StaticResource DATA_CommunityViewModel}"
                  >
                  <Binding.Converter>
                    <BooleanToVisibilityConverter />
                  </Binding.Converter>
                </Binding>
              </igDP:Field.Visibility>
            </igDP:Field>

            <igDP:Field Label="Age" Name="Age" />
          </igDP:FieldLayout.Fields>
        </igDP:FieldLayout>
      </igDP:XamDataGrid.FieldLayouts>
    </igDP:XamDataGrid>
  </DockPanel>
</Window>


You can download the demo source code here.  You will need to have the Infragistics NetAdvantage for WPF installed to run the application.

Posted: 05 Jun 2008, 21:53
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS