1
votes

I am trying to take snapshot of WPF control in various size regardless of original control size. Say if control size is 300 px width and height, i am trying to take snapshot in various size like 1500px height and width, 100px height and width and so on.

Here is snapshot snippet

        objFramework.LayoutTransform =
            new ScaleTransform(actualWidth / requiredWidth, actualHeight / requiredHeight);

            renderBitmap = new RenderTargetBitmap(requiredWidth, requiredHeight, 96d, 96d, PixelFormats.Pbgra32);

            var dv = new DrawingVisual();
            using (DrawingContext ctx = dv.RenderOpen())
            {
                var vb = new VisualBrush(objFramework);
                ctx.DrawRectangle(vb, null, new Rect(0, 0, requiredWidth, requiredHeight));
            }

            renderBitmap.Render(dv);

What i looking for :

I don't want few of child controls to be scaled. The TextBlock inside or one of Grid Row height to be constant even when scaling happen. My sample control structure

<Grid>
    <Border x:Name="brdTiles"  VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="1" BorderBrush="Black" >
        <local:GridExtension x:Name="grdTileHolder" Background="#FFFFFF" >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="25" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>


            <Grid Grid.Row="0" Grid.Column="1" x:Name="TileColumnHeader" >                        
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="100" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="25"></RowDefinition>
                </Grid.RowDefinitions>
                <ComboBox x:Name="grd1" Grid.Column="0" FontSize="10" Height="20" >
                    <ComboBoxItem Content="Item 1" />
                    <ComboBoxItem Content="Item 2" />
                    <ComboBoxItem Content="Item 3" />
                </ComboBox>
                <TextBlock x:Name="txt1" Grid.Column="1" Text="20" FontSize="10" Height="20"/>
                <TextBlock x:Name="txt2" Grid.Column="2" Text="30" FontSize="10" Height="20"/>
                <TextBlock x:Name="txt3" Grid.Column="3" Text="40" FontSize="10" Height="20"/>
            </Grid>

            <Grid Grid.Column="0" Grid.Row="1"  x:Name="TileRowHeader" >
                <Grid.RowDefinitions>
                    <RowDefinition Height="100" />
                    <RowDefinition Height="30" />
                    <RowDefinition Height="30" />
                    <RowDefinition Height="30" />
                </Grid.RowDefinitions>

                <ComboBox HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="100" Grid.Row="0" >
                    <ComboBox.LayoutTransform>
                        <RotateTransform Angle="90" />
                    </ComboBox.LayoutTransform>
                    <ComboBox.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical" IsItemsHost="True">
                                <StackPanel.LayoutTransform>
                                    <RotateTransform Angle="270" />
                                </StackPanel.LayoutTransform>
                            </StackPanel>
                        </ItemsPanelTemplate>
                    </ComboBox.ItemsPanel>
                    <ComboBox.ItemContainerStyle>
                        <Style TargetType="ComboBoxItem">
                            <Setter Property="LayoutTransform">
                                <Setter.Value>
                                    <RotateTransform Angle="0" />
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ComboBox.ItemContainerStyle>
                    <ComboBoxItem>Hello</ComboBoxItem>
                    <ComboBoxItem>World</ComboBoxItem>
                    <ComboBoxItem>Foo</ComboBoxItem>
                    <ComboBoxItem>Check</ComboBoxItem>
                    </ComboBox>


            <TextBlock Text="2" Grid.Row="1" />
                <TextBlock Text="3" Grid.Row="2" />
                <TextBlock Text="4" Grid.Row="3" />
            </Grid>
            <Grid Grid.Row="1" Grid.Column="1" Margin="2" Name="TileViewGrid" Background="#FFFFFF" ShowGridLines="False"  HorizontalAlignment="Center" VerticalAlignment="Center" />
        </local:GridExtension>
    </Border>
</Grid>

Why i want like this

When take snapshot in various size, the text inside looks blurry. So we need a quality text when re-render control.

2
When you render the image, are the constant size controls the correct size? - mrtig
@mrtig , I am not able to follow you, but take copy all child control get rendered and ends in different size. Its not constant. I want few control to be constant in size. - Mohanavel

2 Answers

0
votes

If you were to consider changing your logic to loop through (traverse) the whole display stack, and set the RenderTransform on all items instead of just the container, maybe something like this would work;

class NonScalableTextBlock : System.Windows.Controls.TextBlock
{
    public Transform RenderTransform
    {
        get 
        { 
            return base.RenderTransform; 
        }

        set 
        { 
            // do nothing
        }
    }
}

(so, you would jsut use this class in place of standard TextBlocks when you dont want it to scale)

It hides the LayoutTransform property of its parent, so you are overriding it to do nothing. For some reason, RenderTransform worked better for me than LayoutTransform, not sure why.

0
votes

You don't need to apply any transformations to your control. You can simply change the DPI value you pass to the constructor of the RenderTargetBitmap.
This way, the control will be the same logical size, but just more detailed (higher resolution).

See High-Resolution Printing of WPF 3D Visuals for an example.