In a WPF project I am creating a wizard comprising of many steps. Each step has its own view. Currently, each view has the same outer XAML elements, like a TextBlock
for the title of the step, but different content below that.
So, for example a typical view would look like:
STEP X VIEW
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Step X text goes here"/>
<Grid Grid.Row="1">
<!-- CONTENT OF STEP X GOES HERE -->
</Grid>
</Grid>
What I would like to do is be able to 'factor out' the common outer XAML for each step into another view and just place the content of each step as the content of that new factored out view. That way, I can avoid the repetition of the same outer XAML, and if I decide to change the implementation of each step title, I only have to do it in one place.
I'm sure ContentPresenter
is the part of the solution. So, something like:
WRAPPERVIEW:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Step X text goes here"/>
<Grid Grid.Row="1">
<ContentPresenter Content="Content of Step X ??????"/>
</Grid>
</Grid>
My questions are:
1) Is my implementation of WrapperView
the right way to go?
2) What is the binding for the ContentPresenter
content property in WrapperView
?
3) How can I customise the Text
of the TextBlock
for each step using WrapperView
?
4) How can I get the client XAML using WrapperView
for the XAML of any step view to look like.
So, using WrapperView
for StepXView,
New STEP X VIEW
<Grid>
<WrapperView TitleText ="Step X Title Text">
<!-- XAML for Step X View -->
</WrapperView>
</Grid>
You had a good intuition about using a ContentPresenter
. To me, it looks exactly like you need a HeaderedContentControl
, which is a templatable Control
which handles both a Header
and a Content
property.
Although you could directly use HeaderedContentControl
, I find it clearer to inherit from it in case you want to customize it further later:
public class WrapperView : HeaderedContentControl { }
And in your XAML, you can template it and use it as you wish:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1">
<Window.Resources>
<Style TargetType="{x:Type local:WrapperView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:WrapperView">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ContentPresenter HorizontalAlignment="Center" Grid.Row="0" Content="{TemplateBinding Header}"/>
<Grid Grid.Row="1" HorizontalAlignment="Center">
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<local:WrapperView Header ="Step X Title Text">
<Rectangle Width="50" Height="50" Fill="Blue"/>
</local:WrapperView>
</Grid>
</Window>
The key here is the use of TemlateBinding
which answers your second question.
To make it even cleaner, you could move this Style
away from your Window.Resources
and set it in Themes\Generics.xaml
so that the Style
gets applied by default.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.