用于 LCD 屏幕的 WPF 全高清
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12412092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF for LCD screen Full HD
提问by Ashraf Sayied-Ahmad
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).
我正在开发一个 WPF 应用程序,它将显示在全高清 LCD 屏幕(42 英寸)中。此外,我需要在绝对位置容纳控件。在开发环境中我看不到长度为 1920x1080 的窗口(这是目标屏幕的固定分辨率)。
What is the best practice to accomplish this task?
完成此任务的最佳实践是什么?
回答by Colin Smith
WPF uses Device Independent Units for specifying width/heights/positions/thicknesses, etc.
WPF 使用与设备无关的单位来指定宽度/高度/位置/厚度等。
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.
当您的屏幕 DPI 设置为 96dpi 时,1 DIU/DIP = 1 个物理像素......但当 DPI 不是 96dpi 时,1 DIU = 不同数量的物理像素。
If you use a Canvasthen it positions elements using DIUs.
如果使用 aCanvas则它使用 DIU 定位元素。
Now you imply that you want to position absolutely in terms of pixel coordinates.
现在您暗示您希望根据像素坐标进行绝对定位。
So to do this with the Canvasno matter what the current DPI setting is, you have to use a scaling trick (you can do this with a ViewBox, or a LayoutTransform).
因此,Canvas无论当前的 DPI 设置是什么,要做到这一点,您都必须使用缩放技巧(您可以使用 aViewBox或 a来做到这一点LayoutTransform)。
The example below shows one way to achieve it (my screen is 1366x768....you can change it to Full HD).
下面的示例显示了实现它的一种方法(我的屏幕是 1366x768....您可以将其更改为全高清)。
It looks at the DPI of the system and gets the Canvasscaled down whenever the DPI goes up. This allows you to use Canvas coordinates that really mean pixel coords.
它查看系统的 DPI,并Canvas在 DPI 上升时按比例缩小。这允许您使用真正意味着像素坐标的画布坐标。
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.
如果您能够将用户屏幕更改为 96dpi,则无需执行缩放技巧,因为 96dpi 时 1 DIU = 1 物理像素...无需重新缩放。
<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:
在 96 DPI 设置(较小 - 100%)下,屏幕如下所示:


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).
在 120 DPI 设置(中 - 125%)(即 96 x 1.25 = 120DPI)下,当使用上面的 ScaleBackToPixels 技术时,屏幕看起来像这样(即它看起来与第一个屏幕相同)。


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).
在 120 DPI 设置(中 - 125%)(即 96 x 1.25 = 120DPI)下,当您根本不进行任何调整时,屏幕看起来像这样(注意圆圈是如何变大的,以及按钮的字体和大小)。


All 3 images side by side for comparison:
所有 3 个图像并排进行比较:


回答by Ashraf Sayied-Ahmad
Here is the transformation that makes the screen resolution 1920x1080 (FullHD) visible in my laptop screen resolution 1366x768:
这是使屏幕分辨率 1920x1080(全高清)在我的笔记本电脑屏幕分辨率 1366x768 中可见的转换:
XAML
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#
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.Leftand Canvas.Topare according to the resolution of Full HD.
该代码表明,在开发环境(DEBUG 标志)中将应用转换,而在发布版本中将不应用转换,因为Canvas.Left和Canvas.Top是根据全高清的分辨率。
I hope that this experience will assist others that encounter displaying controls in WPF within a Canvasin absolute metrics.
我希望这种经验能帮助其他人在 WPF 中遇到Canvas在绝对指标中显示控件的问题。

