Silverlight 4: Pattern for displaying data with a bit of logic?
I'm building a wp7 app.
I have a UserControl
that displays a news article headline, teaser, and image. The entire class is pretty short:
public partial class StoryControl : UserControl
{
public Story Story { get; private set; }
public StoryControl()
{
InitializeComponent();
}
internal StoryControl(Story story) : this()
{
this.Story = story;
Teaser.Text = story.Teaser;
Headline.Text = story.Title;
if (story.ImageSrc == null)
{
Thumbnail.Visibility = Visibility.Collapsed;
} else
{
Thumbnail.Source = new BitmapImage(story.ImageSrc);
}
}
}
And the corresponding XAML:
<Grid x:Name="LayoutRoot" Background="Transparent" Margin="0,0,0,20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<Colu开发者_开发百科mnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image x:Name="Thumbnail" Grid.Column="0" Width="89" HorizontalAlignment="Left" VerticalAlignment="Top" />
<!-- sometimes there's a hanging word in the headline that looks a bit awkward -->
<TextBlock x:Name="Headline" Grid.Column="1" Grid.Row="0" Style="{StaticResource PhoneTextAccentStyle}" TextWrapping="Wrap" HorizontalAlignment="Left" FontSize="23.333" VerticalAlignment="Top" />
<TextBlock x:Name="Teaser" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" HorizontalAlignment="Left" Style="{StaticResource PhoneTextSubtleStyle}" TextWrapping="Wrap" VerticalAlignment="Top" Width="384"/>
</Grid>
Is there a way to do with with less code-behind and more XAML? Some way to use binding to bind the text for Headline
and Teaser
to properties of the Story
, while not crashing if Story
is null?
About about the image? I've got a bit of logic there; is there some way to automatically do that in XAML, or am I stuck with that in C#?
Looks like a ViewModel is in order:
public class StoryViewModel
{
readonly Story story;
public StoryViewModel(Story story)
{
this.story = story;
}
public string Teaser { get { return story == null ? "" : story.Teaser; } }
public string Title { get { return story == null ? "" : story.Title; } }
public bool IsThumbnailVisible { get { return story != null && story.ImageSrc != null; } }
public BitmapImage Thumbnail { get { return IsThumbnailVisible ? new BitmapImage(story.ImageSrc) : null; } }
}
Making your codebehind nice and simple:
public partial class StoryControl : UserControl
{
public Story Story { get; private set; }
public StoryControl()
{
InitializeComponent();
}
internal StoryControl(Story story)
: this()
{
this.DataContext = new StoryViewModel(story);
}
}
And your XAML becomes a set of bindings:
<Grid x:Name="LayoutRoot" Background="Transparent" Margin="0,0,0,20">
<Grid.Resources>
<BooleanToVisibilityConverter x:Key="booleanToVisiblityConverter"/>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Visibility="{Binding IsThumbnailVisible, Converter={StaticResource booleanToVisiblityConverter}}" Source="{Binding Thumbnail}" Grid.Column="0" Width="89" HorizontalAlignment="Left" VerticalAlignment="Top" />
<!-- sometimes there's a hanging word in the headline that looks a bit awkward -->
<TextBlock Text="{Binding Title}" Grid.Column="1" Grid.Row="0" Style="{StaticResource PhoneTextAccentStyle}" TextWrapping="Wrap" HorizontalAlignment="Left" FontSize="23.333" VerticalAlignment="Top" />
<TextBlock Text="{Binding Teaser}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" HorizontalAlignment="Left" Style="{StaticResource PhoneTextSubtleStyle}" TextWrapping="Wrap" VerticalAlignment="Top" Width="384"/>
</Grid>
Ok, it would probably be possible to do this with just model (story) and view (xaml) via fallbackvalues and more complex converters, but i hope you'll find that viewmodels give you the most power in terms of testable, brick-wall-less, view-specific logic...
精彩评论