WPF - Parameters to DataTemplates?

Gus Cavalcanti picture Gus Cavalcanti · Nov 6, 2009 · Viewed 8.2k times · Source

I have a ListBox showing data about employees such as name, department photo, badge number, etc. Employees may have different types such as Manager, Staff, Volunteers. I have 3 separate data templates - one for each type. All of these templates show basically the same data but presented differently.

Depending on the user logged into the application pictures, Badge Number, etc, can or cannot be visible. So I have boolean properties for that - CanSeePhotos, CanSeeBadgeNumbers, etc. So if CanSeePhotos == false, all data templates should hide the photos.

My question is, how can I use these boolean properties inside my data templates to toggle the visibility of the appropriate items? Is there a way to pass parameters to Data Templates as I return them from my TemplateSelector?

Thanks!

edit: following Ray's idea I ended up doing this:

Visibility="{Binding Source={x:Static local:Global.CanSeePhoto}, Converter={StaticResource BooleanToVisibilityConverter}}"

Answer

Ray Burns picture Ray Burns · Nov 6, 2009

Actually there is a way to customize DataTemplates as they are returned from the TemplateSelector by wrapping them inside a FrameworkElementFactory, but it is much too complex for your needs.

For your case there are two solutions that are much easier: triggers and converters.

Triggers

You can use a trigger inside the DataTemplate. For example, give the TextBox or Panel where you display the badge number an x:Name, then create a DataTrigger on the CanSeeBadgeNumebers property. Add one setter to the DataTrigger and set the Visible property to Hidden or Collapsed, referencing it by name.

Basic idea:

<DataTemplate>
  ...
  <DockPanel x:Name="BadgeNumberPanel">
    <Label ... />
    <TextBox ... />
  </DockPanel>
  ...

  <DataTemplate.Triggers>
    <DataTrigger Binding="{Binding CanSeeBadgeNumbers}" Value="true">
      <Setter ElementName="BadgeNumberPanel" Property="Visibility" Value="Collapsed" />
    </DataTrigger>
  </DataTemplate.Triggers>
</DataTemplate>

Converters

You can create an IValueConverter in code that converts "bool" type to "Visibility" type (there are many examples out there you can cut and paste), then bind the visibilty of the TextBox to the CanSeeBadgeNumbers, using the converter.

<DockPanel Visibility="{Binding CanSeeBadgeNumbers, Converter="{x:Static local:BoolToVisibilityConverter.Instance}}">
  <Label ... />
  <TextBox ... />
</DockPanel>

How I Do It

I actually use a different technique for my own code: My data foundation includes a MarkupExtension I wrote that calls my core C# expression parser, so I can say something like

Visibility="{edf:Visibility CanSeeBadgeNumber || Owner.SecurityLevel.Count() > 3}"

Unfortunately my data foundation has not yet been released. When it is, I plan to make it free and open source, but that's a few months away yet.