One of the hardest things in WPF it’s that there are many ways to reach the
same result. The same is true with other frameworks, but WPF and its language,
XAML, allow for some powerful and complex design with a large collection
of concepts : dependency properties , attached properties, control templates,
item templates, styles and so on… I’m currently writing a simple Twitter viewer
as a way to learn WPF. This "application" simply shows the xml-based feed of a user’s
friends through the API :

I created classes from the feed through the XSD schema generation tool (xsd.exe).
Be careful before splitting the generated classes, read the Serialization
section on MSDN :

A helper class creates an HTTP request with basic authentication to get the feed :
//object to hold twitter response
Statuses statuses
= null; //request
to twitter service HttpWebRequest request
= (HttpWebRequest)WebRequest.Create("http://twitter.com/statuses/friends_timeline.xml"); //authentication
info CredentialCache authInfo = newCredentialCache();
authInfo.Add(newUri(http://twitter.com/statuses/friends_timeline.xml),
"Basic", newNetworkCredential(username,
password)); request.Credentials = authInfo; //make
the call WebResponse response =
request.GetResponse(); //deserialize response XmlSerializer mySerializer
= newXmlSerializer(typeof(Statuses));
statuses = (Statuses)mySerializer.Deserialize(response.GetResponseStream());
response.Close(); listStatut = newList<Status>(statuses.status);
This method is called by the ObjectDataProvider which
provides the user and password :
<
ObjectDataProvider
x
:
Key
="TwitterDataSource"
d
:
IsDataSource
="True"
ObjectType
="{x:Type TwitterWPF:TwitterManager}"
MethodName
="GetStatuses">
<
ObjectDataProvider
.
ConstructorParameters
>
<
sys
:
String
>
user
</
sys
:
String
>
<
sys
:
String
>
password
</
sys
:
String
>
</
ObjectDataProvider
.
ConstructorParameters
>
</
ObjectDataProvider
>
This class puts the collection returned in an ObservableCollection object
that provides notification when an item is added or removed. This can be useful
since we want to refresh the UI with a timer to get new statuses from Twitter.
I found severalarticles to
design items with alternate backgrounds in a ListView but
none works for me. They overwrite the style property of the items and they will
hide the background of the border. This border
is used to simulate rounded panels around the text :
<
ListView
.
ItemTemplate
>
<
DataTemplate
>
<
Border
Width
="400"
Height
="75"
CornerRadius
="10,10,10,10"
Margin
="4,4,4,4"
Padding
="4,4,4,4"
Background
="{Binding
RelativeSource={RelativeSource AncestorType=ListViewItem},
Converter={StaticResource backgroundConverter}}">
<
Grid
x
:
Name
="statusBox"
Height
="auto"
Width
="auto">
<
Grid
.
ColumnDefinitions
>
<
ColumnDefinition
Width
="0.168*"
/>
<
ColumnDefinition
Width
="0.832*"
/>
</
Grid
.
ColumnDefinitions
>
<
Grid
.
RowDefinitions
>
<
RowDefinition
/>
</
Grid
.
RowDefinitions
>
<
Image
Source
="{Binding
Path=User.ProfileImageUrl}"
Grid
.
Column
="0"
Grid
.
Row
="0"
x
:
Name
="userImage"/>
<
Label
Margin
="8,0,8,0"
x
:
Name
="status"
Grid
.
Column
="1"
>
<
TextBlock
TextWrapping
="WrapWithOverflow"
Text
="{Binding Path=Text}"></
TextBlock
>
</
Label
>
</
Grid
>
</
Border
>
</
DataTemplate
>
</
ListView
.
ItemTemplate
>

So I built an implementation of IValueConverter to
convert the binding of the background value property. I need to know the current ListViewItem,
so I provide the ancestor of type ListViewItem as the object to be converted. The
converter class finds its index inside the ListView and returns the color accordingly
:
public
object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{ ListViewItem item = (ListViewItem)value; ListView listView
= ItemsControl.ItemsControlFromItemContainer(item) asListView; //
Get the index of a ListViewItem int index
= listView.ItemContainerGenerator.IndexFromContainer(item); if (index
% 2 == 0) { returnBrushes.LightBlue;
} else { returnBrushes.Beige;
} }
The last thing to add is the call to refresh the list of the statuses : I put
a timer that refreshes both the ObjectDataProvider and the ListView (without
the latter the index property is not correctly returned in the converter method) :
void TimerClock_Tick(object sender, EventArgs e)
{ ObjectDataProvider odp = Resources["TwitterDataSource"] asObjectDataProvider;
odp.Refresh(); ICollectionView dataView
= CollectionViewSource.GetDefaultView(statusList.ItemsSource);
dataView.Refresh(); }
As I said, there are surely other ways to do this, maybe even more efficiently.
But the Twitter API returning only the 20 latest statuses, efficiently is not
an issue. And it’s a good thing because I’m still discovering the WPF world.
download
the Visual Studio Orcas solution (beta1).
