Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

ObjectPresenter - How to Generate an Object's Testing GUI from a Given Object

, 5 Jan 2012
In this article, I explain step by step, how we can create a WPF custom control that gets an object and, generates a GUI that enables editing that object's properties and invoking that object's methods.
objectpresentation_demo.zip
ObjectPresentation_Demo
Client
ObjectPresentation.dll
ObjectPresentation.Examples.Client.exe
ObjectPresentation.Examples.Client.pdb
ObjectPresentation.Examples.Contracts.dll
ObjectPresentation.Examples.Contracts.pdb
ObjectPresentation.pdb
Server
ObjectPresentation.Examples.Contracts.dll
ObjectPresentation.Examples.Contracts.pdb
ObjectPresentation.Examples.Server.exe
ObjectPresentation.Examples.Server.pdb
ObjectPresentation.Examples.Service.dll
ObjectPresentation.Examples.Service.pdb
WcfLogPrints.dll
objectpresentation_src.zip
ObjectPresentation_src
ObjectPresentation
bin
Debug
Release
obj
Debug
Properties
Settings.settings
Styles
Themes
ObjectPresentation.Examples.Client
bin
Debug
Release
obj
x86
Debug
Properties
Settings.settings
ObjectPresentation.Examples.Contracts
bin
Debug
Release
obj
Debug
Properties
ObjectPresentation.Examples.Server
bin
Debug
Release
obj
x86
Debug
Properties
ObjectPresentation.Examples.Service
bin
Debug
obj
Debug
Properties
WcfLogPrints.dll
ObjectPresentation.suo
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:ObjectPresentation">
    
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/ObjectPresentation;component/Styles/ButtonsStyles.xaml" />
    </ResourceDictionary.MergedDictionaries>

    <DataTemplate x:Key="methodResultDataTemplate">
        <DataTemplate.Resources>
            <Storyboard x:Key="showOutputs">
                <DoubleAnimation Storyboard.TargetName="outputs"
                                 Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleX)"
                                 To="1"
                                 Duration="0:0:0.2" />
                <DoubleAnimation Storyboard.TargetName="outputs"
                                 Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)"
                                 To="1"
                                 Duration="0:0:0.2" />
            </Storyboard>
            <Storyboard x:Key="hideOutputs">
                <DoubleAnimation Storyboard.TargetName="outputs"
                                 Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleX)"
                                 To="0"
                                 Duration="0:0:0.2" />
                <DoubleAnimation Storyboard.TargetName="outputs"
                                 Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)"
                                 To="0"
                                 Duration="0:0:0.2" />
            </Storyboard>
        </DataTemplate.Resources>
        <StackPanel>
            <TextBlock Text="Current result:"
                       Foreground="DarkGreen" 
                       FontSize="14"
                       FontWeight="Bold"
                       Margin="0,0,0,5"/>                
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Method's name:" Margin="0,0,5,0" Foreground="DarkGreen" />
                <TextBlock Text="{Binding MethodName}" Foreground="DarkBlue" />
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Result's time:" Margin="0,0,5,0" Foreground="DarkGreen" />
                <TextBlock Text="{Binding ResultTime}" Foreground="Blue" />
            </StackPanel>
            <StackPanel x:Name="returnValueRegion"
                        Orientation="Horizontal"
                        Visibility="Collapsed">
                <TextBlock Text="Return value:" Margin="0,0,5,0" Foreground="DarkGreen" />
                <ScrollViewer VerticalScrollBarVisibility="Disabled"
                                              HorizontalScrollBarVisibility="Auto">
                    <ContentControl Content="{Binding MethodReturnValue}" />
                </ScrollViewer>
            </StackPanel>
            <StackPanel x:Name="outputsRegion"
                        Orientation="Horizontal"
                        Visibility="Collapsed">
                <TextBlock Text="Outputs:" Margin="0,0,5,0" Foreground="DarkGreen" />
                <StackPanel>
                    <ToggleButton x:Name="toggleOutputs"
                                  HorizontalAlignment="Left"
                                  Style="{StaticResource expandButtonStyle}"
                                  ToolTip="Expand outputs."
                                      IsChecked="True" />
                    <ScrollViewer x:Name="outputs"
                                  Margin="15,0,0,0"
                                  VerticalScrollBarVisibility="Disabled"
                                              HorizontalScrollBarVisibility="Auto">
                        <ScrollViewer.LayoutTransform>
                            <ScaleTransform ScaleX="0" ScaleY="0" />
                        </ScrollViewer.LayoutTransform>
                        <ItemsControl ItemsSource="{Binding MethodOutputs}" />
                    </ScrollViewer>
                </StackPanel>
            </StackPanel>
            <StackPanel x:Name="exceptionRegion"
                        Orientation="Horizontal"
                        Visibility="Collapsed">
                <TextBlock Text="Exception:" Margin="0,0,5,0" Foreground="DarkGreen" />
                <ScrollViewer VerticalScrollBarVisibility="Disabled"
                                              HorizontalScrollBarVisibility="Auto">
                    <ContentControl Content="{Binding MethodException}" />
                </ScrollViewer>
            </StackPanel>
        </StackPanel>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding HasReturnValue}"
                         Value="True">
                <Setter TargetName="returnValueRegion"
                        Property="Visibility"
                        Value="Visible" />
            </DataTrigger>
            <DataTrigger Binding="{Binding HasOutputs}"
                         Value="True">
                <Setter TargetName="outputsRegion"
                        Property="Visibility"
                        Value="Visible" />
            </DataTrigger>
            <DataTrigger Binding="{Binding HasException}"
                         Value="True">
                <Setter TargetName="exceptionRegion"
                        Property="Visibility"
                        Value="Visible" />
            </DataTrigger>
            <Trigger SourceName="toggleOutputs"
                         Property="IsChecked"
                         Value="True">
                <Setter TargetName="toggleOutputs"
                        Property="ToolTip"
                        Value="Collapse outputs." />
                <Trigger.EnterActions>
                    <BeginStoryboard Storyboard="{StaticResource showOutputs}"/>
                </Trigger.EnterActions>
                <Trigger.ExitActions>
                    <BeginStoryboard Storyboard="{StaticResource hideOutputs}" />
                </Trigger.ExitActions>
            </Trigger>

        </DataTemplate.Triggers>
    </DataTemplate>
    
    <Style TargetType="{x:Type local:InterfacePresenter}">
        <Setter Property="Background" Value="LightYellow" />
        <Setter Property="BorderBrush" Value="Orange" />
        <Setter Property="BorderThickness" Value="2" />
        <Setter Property="Padding" Value="10" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:InterfacePresenter}">
                    <ControlTemplate.Resources>
                        <Storyboard x:Key="currentMethodResultRegionChangedStoryboard">
                            <ColorAnimationUsingKeyFrames Storyboard.TargetName="currentMethodResultRegion"
                                                           Storyboard.TargetProperty="(Control.BorderBrush).(SolidColorBrush.Color)">
                                <SplineColorKeyFrame  KeyTime="0:0:0.3"
                                                      KeySpline="0.5,0 0.5,1"
                                                      Value="DarkOrange" />
                                <SplineColorKeyFrame  KeyTime="0:0:0.6"
                                                      KeySpline="0.5,0 0.5,1"
                                                      Value="Orange" />
                            </ColorAnimationUsingKeyFrames>
                            <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="currentMethodResultRegion"
                                                           Storyboard.TargetProperty="BorderThickness">
                                <SplineThicknessKeyFrame  KeyTime="0:0:0.3"
                                                      KeySpline="0.5,0 0.5,1"
                                                      Value="4" />
                                <SplineThicknessKeyFrame  KeyTime="0:0:0.6"
                                                      KeySpline="0.5,0 0.5,1"
                                                      Value="2" />
                            </ThicknessAnimationUsingKeyFrames>
                        </Storyboard>
                    </ControlTemplate.Resources>
                    <DockPanel>
                        <Border x:Name="currentMethodResultRegion"
                                DockPanel.Dock="Bottom"
                                Background="{TemplateBinding Background}" 
                                BorderThickness="{TemplateBinding BorderThickness}"
                                CornerRadius="15"
                                Padding="{TemplateBinding Padding}"
                                Margin="5"
                                RenderTransformOrigin="0.5,0.5">
                            <Border.BorderBrush>
                                <SolidColorBrush Color="Orange" />
                            </Border.BorderBrush>
                            <Border.RenderTransform>
                                <ScaleTransform />
                            </Border.RenderTransform>
                            <ScrollViewer HorizontalScrollBarVisibility="Auto"
                                          VerticalScrollBarVisibility="Auto">
                                <ContentControl Content="{Binding CurrentMethodResult, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                            ContentTemplate="{StaticResource methodResultDataTemplate}" />
                            </ScrollViewer>
                        </Border>

                        <Border BorderBrush="{TemplateBinding BorderBrush}" 
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}"
                                CornerRadius="15"
                                Padding="{TemplateBinding Padding}"
                                Margin="5">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition />
                                </Grid.RowDefinitions>
                                <TextBlock Text="Methods:"
                                           Foreground="DarkGreen"
                                           FontSize="14"
                                           FontWeight="Bold"
                                           Margin="0,0,0,5" />
                                <ScrollViewer Grid.Row="1"
                                              VerticalScrollBarVisibility="Auto"
                                              Margin="0,5,0,0">
                                    <ItemsControl ItemsSource="{Binding InterfaceMethods, RelativeSource={RelativeSource Mode=TemplatedParent}}"  >
                                        <ItemsControl.ItemsPanel>
                                            <ItemsPanelTemplate>
                                                <WrapPanel />
                                            </ItemsPanelTemplate>
                                        </ItemsControl.ItemsPanel>
                                        <ItemsControl.ItemTemplate>
                                            <DataTemplate>
                                                <local:MethodPresenter MethodInformation="{Binding}"
                                                                       ObjectInstance="{Binding DataContext.ObjectInstance, ElementName=templatedParentHolder}"
                                                                       StoreMethodResults="{Binding DataContext.StoreMethodResults, ElementName=templatedParentHolder}"
                                                                       KnownTypes="{Binding DataContext.KnownTypes, ElementName=templatedParentHolder}"
                                                                       AutoGenerateCompatibleTypes="{Binding DataContext.AutoGenerateCompatibleTypes, ElementName=templatedParentHolder}"
                                                                       DataTemplates="{Binding DataContext.DataTemplates, ElementName=templatedParentHolder}"
                                                                       Margin="5"/>
                                            </DataTemplate>
                                        </ItemsControl.ItemTemplate>
                                    </ItemsControl>
                                </ScrollViewer>
                                <FrameworkElement x:Name="templatedParentHolder"
                                                  DataContext="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}" 
                                                  Visibility="Collapsed" />
                            </Grid>
                        </Border>
                    </DockPanel>
                    <ControlTemplate.Triggers>
                        <EventTrigger RoutedEvent="local:InterfacePresenter.CurrentMethodResultChanged">
                            <BeginStoryboard Storyboard="{StaticResource currentMethodResultRegionChangedStoryboard}" />
                        </EventTrigger>
                    </ControlTemplate.Triggers>
                </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)

About the Author

Shmuel Zang
Software Developer
Israel Israel
No Biography provided
Follow on   LinkedIn

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 5 Jan 2012
Article Copyright 2012 by Shmuel Zang
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid