jump to navigation

Using a ContentControl and DataTemplate to indicate new and/or modified data March 6, 2007

Posted by Karl Hulme in .Net, C#, WPF, XAML.
trackback

This blog is no longer actively maintained. The content is well over 5 years old – which is like 50 coder years. Use at your own risk!

I was familiar with using DataTemplate’s for multiple items, say for items in a ListBox, but what if you want to use a DataTemplate for a single item? 

Why would I want to do that?  I can declare the UIElements I want, and bind the properties that I want.  You don’t need a DataTemplate here!!

Well, not strictly true!  If you want to be able to use properties of your business object within conditions that control the layout, then you’re going to need the services of DataTrigger’s. And although most UIElements have a Triggers property, DataTriggers are only supported on a DataTemplate.  So this blog entry is an example of how to set that up…

 

Think about Visual Studio tabs for a second.  Whenever you change the content of a document, a small asterisk appears after the filename to indicate to you that it’s been changed, as illustrated below.

I wanted to do a similar thing in my application.  I wanted to..

  • Show an asterisk whenever the data has been changed since the last save, and
  • Show if an item was new (that is has never been saved.

For me, the second point is particularly important because my application deals with Customer entities, and until the customer is saved they don’t have the all-important customer number.

The first step is to add the required properties to the business object being bound to, and implement INotifyPropertyChanged so that we know when they’re changing.  A heavily abridged/shell-like version of my Entity class is below.  (Please note, the code below is only intended to highlight the need to define the properties and inplement INotifyPropertyChanged on the business object in use.)

using System; using System.Collections.Generic; using System.Text; using System.Xml; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; namespace MyNamespace { /// <summary> /// Represents an entity loaded from the database. /// </summary> public class Entity: INotifyPropertyChanged { #region properties private Int32? id; /// <summary> /// Gets the unique id of the entity. /// </summary> public Int32? Id { get { return id; } internal set { id = value; OnPropertyChanged("Id"); OnPropertyChanged("IsNew"); } } private EntityDefinition definition; /// <summary> /// Gets the type of the entity. /// </summary> public EntityDefinition Definition { get { return definition; } } /// <summary> /// Gets a value that indicates if the entity has been modified /// since it was loaded. /// </summary> public Boolean IsModified { get { return changeHistory.Count > 0; } } private EntityDataFieldChangeCollection changeHistory = new EntityDataFieldChangeCollection(); public EntityDataFieldChangeCollection ChangeHistory { get { return changeHistory; } } #endregion #region INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(String propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #endregion } }

Then in XAML, define a ContentControl and set the Content of that control to be an instance of your business object.  Clearly the ContentControl doesn’t know how to render said business object, so I’ve provided a DataTemplate.  This DataTemplate uses a horizontal StackPanel to lay out a series of TextBlock elements.  I then use the Triggers to turn the visibility on and off, dependent upon the IsNew and IsModified properties. 

<ContentControl Grid.Row="0" Content="{Binding Source={StaticResource entity}}"> <ContentControl.ContentTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Name="newBlock" Text="New " Visibility="Visible"/> <TextBlock Name="nameBlock" Text="{Binding Path=Definition.Name}" Visibility="Visible"/> <TextBlock Name="spacer" Text=" " Visibility="Collapsed"/> <TextBlock Name="idBlock" Text="{Binding Path=Id}" Visibility="Collapsed" /> <TextBlock Name="modifiedBlock" Text="*" Visibility="Collapsed"/> </StackPanel> <DataTemplate.Triggers> <DataTrigger Binding="{Binding Path=IsNew}" Value="False"> <DataTrigger.Setters> <Setter TargetName="newBlock" Property="UIElement.Visibility" Value="Collapsed" /> <Setter TargetName="idBlock" Property="UIElement.Visibility" Value="Visible" /> <Setter TargetName="spacer" Property="UIElement.Visibility" Value="Visible" /> </DataTrigger.Setters> </DataTrigger> <DataTrigger Binding="{Binding Path=IsModified}" Value="True"> <DataTrigger.Setters> <Setter TargetName="modifiedBlock" Property="UIElement.Visibility" Value="Visible" /> </DataTrigger.Setters> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </ContentControl.ContentTemplate> </ContentControl>

So the tab headers throughout the life of one of my Customer entities would start out as follows…

Then, I would expect something to be changed…

Once the first set of changes can be made, it should be saved.  This will result in an Id being returned from the database…

Obviously the data could be modified again at this point…

I originally implemented this feature using IValueConverters (and the like) but I believe the XAML solution is much nicer. 

So if you need to display information related to a business object and you have some conditions associated with the display, then you could try using a data-templated content control.

Comments»

1. Frederick Ronci - March 18, 2008

Is it possible to get the source code for this project?

Thanks,

2. Darren - January 2, 2011

Brilliant! Thanks so much for your article as it helped me solve a different problem.

I was applying a DataTemplate to items in a listbox and within each DataTemplate I wanted to re-use another DataTemplate. However the second template refused to appear at runtime!

Wrapping it in the ContentControl and setting the ContentTemplate to my second template solved the problem.

3. fenetre pvc sur mesure pas chere - April 18, 2013

I’m not that much of a online reader to be honest but your sites really nice, keep it up!

I’ll go ahead and bookmark your site to come back in the future. Cheers

4. fenetre pvc sur mesure - April 19, 2013

Have you ever considered publishing an e-book or guest authoring on other blogs?
I have a blog based upon on the same ideas you discuss and would love to have you
share some stories/information. I know my visitors would enjoy your work.
If you’re even remotely interested, feel free to send me an email.

5. devis porte de garage sectionnelle motorisée - April 19, 2013

Stunning quest there. What happened after? Take care!

6. couleur fenetre pvc - April 27, 2013

We stumbled over here by a different website and thought I should check things out.
I like what I see so now i am following you. Look forward to
looking at your web page yet again.

7. porte de garage basculante non debordante - May 28, 2013

I think that what you published made a great deal of sense.

But, think about this, suppose you added a little content?

I mean, I don’t want to tell you how to run your blog, however suppose you added a post title to maybe grab a person’s attention?

I mean Using a ContentControl and DataTemplate to indicate
new and/or modified data | Atomic Blography is kinda
plain. You might glance at Yahoo’s front page and note how they write news headlines to get viewers to click. You might add a related video or a picture or two to grab people excited about what you’ve got to say.
Just my opinion, it could bring your blog a little bit
more interesting.

8. parquet stratifié pose - June 3, 2013

I like the valuable info you provide in your articles. I will bookmark your weblog and check
again right here regularly. I am fairly certain I will learn
a lot of new stuff proper here! Best of luck for the following!

9. avis phenix option - July 15, 2013

Hi, constantly i used to check webpage posts here in the early hours in the break of day, because i like to gain knowledge of more and more.

10. traiteur a bordeaux - September 18, 2013

Hi to every single one, it’s really a nice for me to pay a visit this web site, it includes helpful Information.

11. 台北孕婦瑜珈 - August 7, 2018

This piece of writing provides clear idea for the new
viewers of blogging, that genuinely how to do running a blog.

12. flickrhivemind.Net - September 6, 2019

flickrhivemind.Net

Using a ContentControl and DataTemplate to indicate new and/or modified data | Atomic Blography

13. 369Faka.vip - October 5, 2019

369Faka.vip

Using a ContentControl and DataTemplate to indicate new and/or modified data | Atomic Blography


Leave a reply to porte de garage basculante non debordante Cancel reply