Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to obtain the scaled size of a WPF Visual element

Tags:

wpf

I am rendering a WPF Visual (UserControl) to a bitmap but the problem is that the rendered image is the size of the UserControl before it is scaled/transformed. So let's say the UserControl was designed at 200x200 pixels. When I render to BMP I'm using the UserControl's ActualWidth and ActualHeightt which report 200 and 200 respectively. Problem is the UserControl is in a Canvas and is auto sized (set to scale/fill with the Window size) to something closer to 1200 x 1200 (it changes)

I've done some reading and searching and so far can't figure out how to determine the effective size, that is the size the control is being painted on screen.

I came across this question which sounded hopeful but the Transform returned does not contain scaling data. Well it does, but they are both 1. Get element position after transform

Any suggestions on where to look for the render scaling would be great!

[UPDATE] As suggested, I'm including the relevant code:

public static Bitmap PngBitmap(this Visual visual)
{
    // Get height and width
    int width = (int)(double)visual.GetValue(
        FrameworkElement.ActualWidthProperty);
    int height = (int)(double)visual.GetValue(
        FrameworkElement.ActualHeightProperty);

    // Render
    RenderTargetBitmap rtb =
        new RenderTargetBitmap(
            width,
            height,
            96,
            96,
            PixelFormats.Default);
    rtb.Render(visual);

    // Encode
    PngBitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(rtb));
    System.IO.MemoryStream stream = new System.IO.MemoryStream();
    encoder.Save(stream);

    // Create Bitmap
    Bitmap bmp = new Bitmap(stream);
    stream.Close();

    return bmp;
}

public static BitmapSource BitmapSource(this Visual visual)
{
    Bitmap bmp = visual.PngBitmap();
    IntPtr hBitmap = bmp.GetHbitmap();
    BitmapSizeOptions sizeOptions = BitmapSizeOptions.FromEmptyOptions();
    return Imaging.CreateBitmapSourceFromHBitmap(
                        hBitmap,
                        IntPtr.Zero,
                        Int32Rect.Empty,
                        sizeOptions);
}

[Update #2] Added the XAML - The Grid element was removed because it was HUGE and from my reading of the XAML the Canvas containing the keyboard UserControl was NOT part of the Grid element.

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:PMD.HECAT.DashboardModule" 
    xmlns:PMD_HECAT_DashboardModule_VirtualKeyboard="clr-namespace:PMD.HECAT.DashboardModule.VirtualKeyboard" 
    xmlns:System_Windows_Controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit" 
    xmlns:PMD_HECAT_DashboardModule_Input="clr-namespace:PMD.HECAT.DashboardModule.Input"
    xmlns:control="clr-namespace:PMD.HECAT.DashboardModule.Controls"    
    x:Class="PMD.HECAT.DashboardModule.CandidateElectrodeView"             
    x:Name="UserControl"
    mc:Ignorable="d"
    d:DesignWidth="1024" d:DesignHeight="768" Width="640" Height="360">
    <UserControl.Resources>
         <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="../Themes/DashboardStyles.xaml" />
                <ResourceDictionary Source="../Themes/ImageButtons.xaml" />
                <ResourceDictionary Source="CandidateViewResources.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>        
    </UserControl.Resources>
    <UserControl.Triggers>
        <EventTrigger RoutedEvent="PMD_HECAT_DashboardModule_VirtualKeyboard:VirtualKeyboardView.KeyboardClose" SourceName="virtualKeyboardView">
            <BeginStoryboard Storyboard="{StaticResource OnKeyboardClose1}"/>
        </EventTrigger>
    </UserControl.Triggers>
    <Canvas Width="100" HorizontalAlignment="Left">

        <PMD_HECAT_DashboardModule_VirtualKeyboard:VirtualKeyboardView x:Name="virtualKeyboardView" Height="222" Width="550" RenderTransformOrigin="0.5,0.5" Opacity="0" Active="False">
            <PMD_HECAT_DashboardModule_VirtualKeyboard:VirtualKeyboardView.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform/>
                    <RotateTransform/>
                    <TranslateTransform X="40" Y="400"/>
                </TransformGroup>
            </PMD_HECAT_DashboardModule_VirtualKeyboard:VirtualKeyboardView.RenderTransform>
        </PMD_HECAT_DashboardModule_VirtualKeyboard:VirtualKeyboardView>
        <Rectangle Stroke="White" Opacity="0.7" Fill="White" Height="370" Width="654.851" Canvas.Left="687" Canvas.Top="0" />
    </Canvas>
</UserControl>
like image 909
scubasteve Avatar asked Oct 10 '11 08:10

scubasteve


2 Answers

I know lots of time passed since the question was asked but it doesn't hurt to post some more info :)

I use this code to find size (scale) of visuals with applied render transform(s).

GeneralTransform t = transformedVisual.TransformToVisual(parentVisual);

Vector topLeft = (Vector) t.Transform(new Point(0,0));
Vector topRight = (Vector) t.Transform(new Point(originalWidthOfTransformedVisual, 0));

double renderedWidth = (topRight-topLeft).Length;
double widthScale = renderedWidth / originalWidthOfTransformedVisual;
like image 115
bor Avatar answered Sep 26 '22 13:09

bor


Hi i had a similar problem if the visual wasn't displayed before to force this rendering

        uiElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        uiElement.Arrange(new Rect(new Point(0, 0), uiElement.DesiredSize));
        Size _size = uiElement.DesiredSize;

this works at least in my case to fore the UIElement to Render it Size

like image 21
WiiMaxx Avatar answered Sep 25 '22 13:09

WiiMaxx