Click here to Skip to main content
15,885,216 members
Articles / Desktop Programming / WPF

Presentation Model (MVVM) Good Practices

Rate me:
Please Sign up or sign in to vote.
4.81/5 (13 votes)
11 May 2010CPOL16 min read 67.8K   944   76  
Showing some good practices that can be applied to the Presentation Model/MVVM pattern.
<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:acb="clr-namespace:AttachedCommandBehavior;assembly=AttachedCommandBehavior"
    xmlns:pm="clr-namespace:App.Core;assembly=App.Core"
    xmlns:vw="clr-namespace:WPFUI.View"
    >
    <DataTemplate x:Key="DataGridHeaderTemplate">
        <TextBlock Text="{Binding}" Foreground="Black"/>
    </DataTemplate>

    <DataTemplate DataType="{x:Type pm:ProductEditViewPresentationModel}">
        <vw:ProductEditView/>
    </DataTemplate>
    
    <DataTemplate DataType="{x:Type pm:ProductsViewPresentationModel}">
        <vw:ProductsView/>
    </DataTemplate>

    
    <Style
        x:Key="EntityListViewItemStyle"
        TargetType="{x:Type ListViewItem}"
        BasedOn="{StaticResource {x:Type ListViewItem}}"
        >
        <Setter Property="acb:CommandBehavior.Command" Value="{Binding Call}"/>
        <Setter Property="acb:CommandBehavior.CommandParameter" Value="OpenEditView"/>
        <Setter Property="acb:CommandBehavior.Event" Value="MouseDoubleClick"/>                 
    </Style>
    
    <Style
        x:Key="EntityCollectionViewListStyle"
        TargetType="{x:Type ListView}"
        BasedOn="{StaticResource {x:Type ListView}}"
        >
        <Setter Property="ItemContainerStyle" Value="{StaticResource EntityListViewItemStyle}"/>
        <Setter Property="SelectionMode" Value="Single"/>
        <Setter Property="SelectedItem" Value="{Binding Selected}"/>        
    </Style>
        
        
    <Style 
        x:Key="ViewStyle"
        TargetType="{x:Type UserControl}"
        BasedOn="{StaticResource {x:Type UserControl}}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type UserControl}">
                    <Grid
                        Background="{TemplateBinding Background}">
                        <ContentPresenter
                            x:Name="MainContent"                   
                            Content="{TemplateBinding Content}"                                    
                            >
                        </ContentPresenter>
                        <Border
                            x:Name="WorkingPanel"                            
                            Background="White"
                            Opacity="0.4"
                            CornerRadius="5"
                            Panel.ZIndex="5"
                            Height="{TemplateBinding ActualHeight}"
                            Width="{TemplateBinding ActualWidth}"
                            Visibility="Hidden"
                            >
                            <TextBlock 
                                x:Name="WorkingText"
                                VerticalAlignment="Center"
                                HorizontalAlignment="Center"
                                FontSize="16"
                                FontWeight="Bold"
                                Text="Working..."
                                Foreground="Black"
                                >
                            </TextBlock>
                        </Border>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <DataTrigger
                            Binding="{Binding IsWorking}"
                            Value="True"
                            >
                            <Setter
                                TargetName="MainContent"
                                Property="IsEnabled"
                                Value="False"
                                />
                            <Setter
                                TargetName="WorkingPanel"
                                Property="Visibility"
                                Value="Visible"
                                />
                            <DataTrigger.EnterActions>
                                <BeginStoryboard
                                    Name="StartWorking"
                                    >
                                    <Storyboard>
                                        <DoubleAnimation
                                            Storyboard.TargetName="WorkingText"
                                            Storyboard.TargetProperty="Opacity"
                                            AutoReverse="True"
                                            Duration="0:0:0.5"
                                            From="1"
                                            To="0.2"
                                            RepeatBehavior="Forever"
                                            />
                                    </Storyboard>
                                </BeginStoryboard>
                            </DataTrigger.EnterActions>
                            <DataTrigger.ExitActions>
                                <StopStoryboard BeginStoryboardName="StartWorking" />
                            </DataTrigger.ExitActions>
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style
        TargetType="{x:Type TextBlock}"
        BasedOn="{StaticResource {x:Type TextBlock}}">
        <Setter 
            Property="Foreground"
            Value="White"
            />            
    </Style>
    
    <SolidColorBrush x:Key="ApplicationBackgroundBrush" Color="Transparent"/>

    <DataTemplate x:Key="ClosableTabItemTemplate">
        <DockPanel>
            <Button            
                    Content="X"                    
                    Command="{Binding Call}"
                    CommandParameter="Close"
                    Cursor="Hand"                    
                    DockPanel.Dock="Right"
                    Focusable="False"
                    FontFamily="Courier"
                    FontSize="9"
                    FontWeight="Bold"                    
                    Margin="10,0,0,0"
                    VerticalContentAlignment="Bottom"
                    Height="18">
                <Button.Style>
                    <Style
                        TargetType="{x:Type Button}"
                        BasedOn="{StaticResource {x:Type Button}}">
                        <Style.Triggers>
                            <DataTrigger
                                Binding="{Binding IsWorking}"
                                Value="True"
                                >
                                <Setter 
                                    Property="IsEnabled"
                                    Value="False"
                                    />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>  
            <TextBlock 
                Text="{Binding DisplayName}"
                VerticalAlignment="Center">
                <TextBlock.Style>
                  <Style
                      TargetType="{x:Type TextBlock}">
                      <Style.Triggers>
                          <DataTrigger
                              Binding="{Binding IsSelected}"
                              Value="True">
                              <Setter
                                  Property="Foreground"
                                  Value="Black"
                                  />
                          </DataTrigger>
                      </Style.Triggers>
                  </Style>
                </TextBlock.Style>
            </TextBlock>
        </DockPanel>
    </DataTemplate>

    <Style
            x:Key="WorkspaceTabItemStyle"
            TargetType="{x:Type TabItem}"
            BasedOn="{StaticResource {x:Type TabItem}}"
            >
        <Setter 
                Property="Background"
                Value="{StaticResource ApplicationBackgroundBrush}"
                />
        <Setter
                Property="ToolTip"
                Value="{Binding DisplayName}"
                />
        <Setter
                Property="IsSelected"
                Value="{Binding IsSelected}"
                />
    </Style>

    <Style 
            x:Key="WorkspaceTabControlStyle"
            TargetType="{x:Type TabControl}"
            BasedOn="{StaticResource {x:Type TabControl}}"
            >
        <Setter
                Property="ItemContainerStyle"
                Value="{StaticResource WorkspaceTabItemStyle}"
                />
        <Style.Triggers>
            <DataTrigger 
                    Binding="{Binding RelativeSource={RelativeSource Self}, Path=Items.Count}" 
                    Value="0">
                <Setter Property="Visibility" Value="Hidden" />
            </DataTrigger>
        </Style.Triggers>
    </Style>

    <DataTemplate x:Key="WorkspacesTemplate">
        <TabControl
                Background="{StaticResource ApplicationBackgroundBrush}"
                ItemsSource="{Binding}"
                ItemTemplate="{StaticResource ClosableTabItemTemplate}"
                Margin="4"
                Style="{StaticResource WorkspaceTabControlStyle}"/>
    </DataTemplate>

    <DataTemplate x:Key="NavigationMenuTemplate">
        <ItemsControl 
                IsTabStop="False"
                ItemsSource="{Binding}" 
                Margin="6,2">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button 
                            Content="{Binding DisplayName}"
                            Command="{Binding Call}"
                            CommandParameter="ExecuteAction"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </DataTemplate>   

    <Style x:Key="MainHCCStyle" TargetType="{x:Type HeaderedContentControl}">
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border 
                            BorderBrush="LightGray" 
                            BorderThickness="1"  
                            CornerRadius="2"
                            Margin="4" 
                            Padding="4" 
                            SnapsToDevicePixels="True">
                        <TextBlock 
                                FontSize="14"
                                FontWeight="Bold"                                
                                HorizontalAlignment="Center"
                                Text="{TemplateBinding Content}"/>
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type HeaderedContentControl}">
                    <DockPanel>
                        <ContentPresenter 
                                DockPanel.Dock="Top"
                                ContentSource="Header"
                                ContentTemplate="{TemplateBinding HeaderTemplate}"/>
                        <ContentPresenter 
                                ContentSource="Content"
                                ContentTemplate="{TemplateBinding ContentTemplate}"/>
                    </DockPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Brazil Brazil
Software developer specialized in the .NET framework

Comments and Discussions