WPF for LCD screen Full HD
Asked Answered
M

2

3

I am developing a WPF application that will be displayed in a Full-HD LCD screen (42 inch). In addition, I need to accommodate the controls in absolute positions. In the development environment I can not see a window in length 1920x1080 (this is the fixed resolution of the targeted screen).

What is the best practice to accomplish this task?

Mcdonough answered 13/9, 2012 at 17:58 Comment(5)
There is a zoom bar in the top left corner of the designer. Do you mean this?Splurge
No. When the application start (Maximized) in the target LCD screen I want to preserve the absolute positions of the controlsMcdonough
Then you should specify absolute positions for the controls. Show some code that visualizes your problem.Splurge
If you use a canvas then you can position elements on it using DIP (device independent pixel....1 DIP = 1 pixel when you screen DPI is set to 96dpi)...the tricky thing is what to do when someone isn't running at 96dpi....you have to scale your canvas if you want to maintain pixel positioning.Departed
suppose that we are in 96dpi, so how to scale the positions of the controls in terms of canvas properties(left,top)? you helpMcdonough
D
9

WPF uses Device Independent Units for specifying width/heights/positions/thicknesses, etc.

1 DIU/DIP = 1 physical pixel when your screen DPI is set to 96dpi.....but 1 DIU = a different number of physical pixels when the DPI is not 96dpi.

If you use a Canvas then it positions elements using DIUs.

Now you imply that you want to position absolutely in terms of pixel coordinates.

So to do this with the Canvas no matter what the current DPI setting is, you have to use a scaling trick (you can do this with a ViewBox, or a LayoutTransform).

The example below shows one way to achieve it (my screen is 1366x768....you can change it to Full HD).

It looks at the DPI of the system and gets the Canvas scaled down whenever the DPI goes up. This allows you to use Canvas coordinates that really mean pixel coords.

If you are able to change the users screen to 96dpi then there is no need to do the scaling trick because 1 DIU = 1 physical pixel at 96dpi...no rescaling needed.

<Window x:Class="WpfApplication12.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStyle="None"
        AllowsTransparency="True" Background="White"
        SizeToContent="WidthAndHeight"
        Title="MainWindow" Loaded="Window_Loaded">
    <Viewbox x:Name="viewbox">
    <Canvas x:Name="canvas">
        <Rectangle x:Name="rect" Canvas.Top="10" Canvas.Left="10" Stroke="Red" StrokeThickness="1"/>
        <Button Canvas.Top="20" Canvas.Left="20">Test Button</Button>
            <Ellipse Canvas.Top="100" Canvas.Left="100" Width="100" Height="100" Stroke="Red" StrokeThickness="10"/>
            <TextBlock Canvas.Top="100" Canvas.Left="100" FontSize="15">Some Text</TextBlock>
        </Canvas>
    </Viewbox>
</Window>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication12
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // HD
        const int screenwidth = 1366;
        const int screenheight = 768;

        // FULL HD
        //const int screenwidth = 1920;
        //const int screenheight = 1080;

        public MainWindow()
        {
            InitializeComponent();

            Top = 0;
            Left = 0;

            canvas.Width = screenwidth;
            canvas.Height = screenheight;

            rect.Width = screenwidth - 20;
            rect.Height = screenheight - 20;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            bool bScaleBackToPixels = true;

            if (bScaleBackToPixels)
            {
                PresentationSource presentationsource = PresentationSource.FromVisual(this);
                Matrix m = presentationsource.CompositionTarget.TransformToDevice;

                double DpiWidthFactor = m.M11;
                double DpiHeightFactor = m.M22;

                viewbox.Width = screenwidth / DpiWidthFactor;
                viewbox.Height = screenheight / DpiHeightFactor;
            }
            else
            {
                viewbox.Width = screenwidth;
                viewbox.Height = screenheight;
            }
        }
    }
}

<Window x:Class="WpfApplication12.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStyle="None"
        AllowsTransparency="True" Background="White"
        SizeToContent="WidthAndHeight"
        Title="MainWindow" Loaded="Window_Loaded">
    <Canvas x:Name="canvas">
        <Rectangle x:Name="rect" Canvas.Top="10" Canvas.Left="10" Stroke="Red" StrokeThickness="1"/>
        <Button Canvas.Top="20" Canvas.Left="20">Test Button</Button>
            <Ellipse Canvas.Top="100" Canvas.Left="100" Width="100" Height="100" Stroke="Red" StrokeThickness="10"/>
            <TextBlock Canvas.Top="100" Canvas.Left="100" FontSize="15">Some Text</TextBlock>
        </Canvas>
</Window>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication12
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // HD
        const int screenwidth = 1366;
        const int screenheight = 768;

        // FULL HD
        //const int screenwidth = 1920;
        //const int screenheight = 1080;

        public MainWindow()
        {
            InitializeComponent();

            Top = 0;
            Left = 0;

            canvas.Width = screenwidth;
            canvas.Height = screenheight;

            rect.Width = screenwidth - 20;
            rect.Height = screenheight - 20;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            bool bScaleBackToPixels = true;

            if (bScaleBackToPixels)
            {
                PresentationSource presentationsource = PresentationSource.FromVisual(this);
                Matrix m = presentationsource.CompositionTarget.TransformToDevice;

                double DpiWidthFactor = m.M11;
                double DpiHeightFactor = m.M22;

                double scalex = 1 / DpiWidthFactor;
                double scaley = 1 / DpiHeightFactor;

                canvas.LayoutTransform = new ScaleTransform(scalex, scaley);
            }
        }
    }
}

At the 96 DPI setting (Smaller - 100%) the screen looks like this:

enter image description here

At the 120 DPI setting (Medium - 125%) (i.e. 96 x 1.25 = 120DPI) the screen looks like this when using my ScaleBackToPixels technique above (i.e. it looks the same as the first screen).

enter image description here

At the 120 DPI setting (Medium - 125%) (i.e. 96 x 1.25 = 120DPI) the screen looks like this when you don't do any adjustments at all (notice how the circle is bigger, and the font and size of the Button).

enter image description here

All 3 images side by side for comparison:

enter image description here

Departed answered 13/9, 2012 at 20:39 Comment(4)
Thanks for your greet answer. But its not working in my scenario. I am using a Canvas with background of Full-HD(1920x1080), and my screen resolution is 1366x768. In my working machine I can not see the controls positioned correctly. I think we missed some transformation (may be TranslateTransform)Mcdonough
Uncomment these lines for Full HD resolution ... //const int screenwidth = 1920;//const int screenheight = 1080; ....if you want a proper Window with Title then remove the WindowStyle="None", and AllowsTransparency="True" properties on the Window.Departed
I still can not see the controlsMcdonough
Hi, sorry it's hard to know what you want....but try this...this assumes you are using a 96dpi graphics mode......put the Full HD width and height on the Canvas.....put the Half HD width and size on the ViewBox.....to cater for different DPI screens...then use the ScaleTransform scaling adjustment codeDeparted
M
0

Here is the transformation that makes the screen resolution 1920x1080 (FullHD) visible in my laptop screen resolution 1366x768:

XAML

        <ContentControl  Canvas.Left="1630" Canvas.Top="400" Content="{Binding Time}" />
        <ContentControl  Canvas.Left="1630" Canvas.Top="590" Content="{Binding NextPrayTime}" />
        <ContentControl  Canvas.Left="1650" Canvas.Top="700" Content="{Binding Today}" />
        <ContentControl  Canvas.Right="520" Canvas.Top="120" Content="{Binding Content}" />
        <ContentControl  Canvas.Left="0" Canvas.Top="965" Content="{Binding PrayTimes}">

        </ContentControl>
    </Canvas>
</Viewbox>

C#

static public class HD
{
    static public float Width { get { return 1366.0f; } }
    static public float Height { get { return 768.0f; } }
}

static public class FHD
{
    static public float Width { get { return 1920.0f; } }
    static public float Height { get { return 1080.0f; } }
}

static public class HDRatios
{
    static public double Width
    {
        get
        {
#if (DEBUG)
            return double.Parse((HD.Width / FHD.Width).ToString("0.0"));
#else
            return 1;
#endif
        }
    }
    static public double Height
    {
        get
        {
#if (DEBUG)
            return double.Parse((HD.Height / FHD.Height).ToString("0.0"));
#else
            return 1;
#endif
        }
    }

The code demonstrates that in development environment (DEBUG flag) the transformation will be applied and in the release version the transformation will not be applied since the Canvas.Left and Canvas.Top are according to the resolution of Full HD.

I hope that this experience will assist others that encounter displaying controls in WPF within a Canvas in absolute metrics.

Mcdonough answered 15/9, 2012 at 21:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.