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.
Is it possible to get the source code for this project?
Thanks,
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.
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
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.
Stunning quest there. What happened after? Take care!
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.
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.
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!
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.
Hi to every single one, it’s really a nice for me to pay a visit this web site, it includes helpful Information.
This piece of writing provides clear idea for the new
viewers of blogging, that genuinely how to do running a blog.
flickrhivemind.Net
Using a ContentControl and DataTemplate to indicate new and/or modified data | Atomic Blography
369Faka.vip
Using a ContentControl and DataTemplate to indicate new and/or modified data | Atomic Blography