根据屏幕分辨率调整WPF窗口和内容大小

33

我有一个WPF应用程序,每个窗口上都有多个控件,一些控件会重叠等等,我需要的是一种根据屏幕分辨率自动调整应用程序大小的方法。

有什么想法吗?


1
为什么你需要这个?如果你只是想简单地调整窗口大小,@Fischermaen 已经给出了答案。但是如果你想改变字体大小等内容的大小,这并不需要,因为 WPF 已经处理了这个问题。所有 WPF 渲染都在虚拟坐标系中工作,并根据系统的 DPI 设置映射到物理像素。 - Vladimir Perevalov
你想让窗口的大小正好适合其内容吗?那么请阅读类似的问题 - dowhilefor
1
但是我的WPF已经设置了坐标和字体大小等。基本上,这个软件需要适用于不同的分辨率。 - Welsh King
威尔士人,你找到解决方案了吗?@Fischermaens的解决方案不起作用。 - user5346812
这与最大化窗口有何不同? - Kyle Delaney
4个回答

96

语法 Height="{Binding SystemParameters.PrimaryScreenHeight}" 提供了线索,但并不起作用。SystemParameters.PrimaryScreenHeight是静态的,因此您应该使用:

  <Window x:Class="MyApp.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:tools="clr-namespace:MyApp.Tools"
      Height="{x:Static SystemParameters.PrimaryScreenHeight}" 
      Width="{x:Static SystemParameters.PrimaryScreenWidth}" 
      Title="{Binding Path=DisplayName}"
      WindowStartupLocation="CenterScreen"
      Icon="icon.ico"
  >

它将适合整个屏幕。但是,您可能更喜欢适应屏幕大小的百分比,例如90%,在这种情况下,语法必须通过绑定规范中的转换器进行修改:

  <Window x:Class="MyApp.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:tools="clr-namespace:MyApp.Tools"
      Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight}, Converter={tools:RatioConverter}, ConverterParameter='0.9' }" 
      Width="{Binding Source={x:Static SystemParameters.PrimaryScreenWidth}, Converter={tools:RatioConverter}, ConverterParameter='0.9' }" 
      Title="{Binding Path=DisplayName}"
      WindowStartupLocation="CenterScreen"
      Icon="icon.ico"
  >

RatioConverter在MyApp.Tools命名空间中声明如下:

namespace MyApp.Tools {

    [ValueConversion(typeof(string), typeof(string))]
    public class RatioConverter : MarkupExtension, IValueConverter
    {
      private static RatioConverter _instance;

      public RatioConverter() { }

      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      { // do not let the culture default to local to prevent variable outcome re decimal syntax
        double size = System.Convert.ToDouble(value) * System.Convert.ToDouble(parameter,CultureInfo.InvariantCulture);
        return size.ToString( "G0", CultureInfo.InvariantCulture );
      }

      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      { // read only converter...
        throw new NotImplementedException();
      }

      public override object ProvideValue(IServiceProvider serviceProvider)
      {
        return _instance ?? (_instance = new RatioConverter());
      }

    }
}

转换器的定义应继承自MarkupExtension,以便可以直接在根元素中使用,而无需先声明为资源。


如何以编程方式设置此内容:Height="{Binding Source={x:Static SystemParameters.PrimaryScreenHeight}, Converter={tools:RatioConverter}, ConverterParameter='0.9' }" Width="{Binding Source={x:Static SystemParameters.PrimaryScreenWidth}, Converter={tools:RatioConverter}, ConverterParameter='0.9' }" - Vibhesh Kaul
我同意 phonetagger 的观点,这是一个非常好的答案,只需将其适应屏幕大小的百分比,这样它就可以始终适合任何分辨率/监视器大小... - AndyUK
4
如果您不希望窗口覆盖任务栏,可以使用MaximizedPrimaryScreenHeight而不是PrimaryScreenHeight。(参考链接:https://dev59.com/S1sW5IYBdhLWcg3wZmqc#35010001) - larsjr
试图理解...为什么你的转换器需要将值转换为double,然后再转回字符串?为什么不能让它成为“双向double”?参数“object value”是一个装箱对象,与你绑定的类型相同,在这种情况下是“Width”(或“Height”),它们已经是double类型了。 - dotNET

34

简单地创建一个绑定,就像这样:

<Window x:Class="YourApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="YourApplication" 
    Height="{Binding SystemParameters.PrimaryScreenHeight}" 
    Width="{Binding SystemParameters.PrimaryScreenWidth}">

1
这取决于你如何设计你的表单。你可以有一个固定的设计,或者控件会相对于它们的容器进行调整大小。 - Fischermaen
哦,有趣,我希望我在开始时知道这个,好吧,我会在一个空项目上测试一下,看看会发生什么。所以,只是为了澄清,需要使控件项的宽度和高度相对吗?我有这个<Grid><Rectangle Height="100" HorizontalAlignment="Left" Margin="110,48,0,0" Name="rectangle1" Stroke="Black" VerticalAlignment="Top" Width="200" Fill="#FFD43939" /></Grid>,如何使其与窗口大小调整? - Welsh King
2
@WelshKing: 你需要像这样声明你的网格 <Grid> <Rectangle HorizontalAlignment="Stretch" Margin="110,48,0,0" Name="rectangle1" Stroke="Black" VerticalAlignment="Stretch" Fill="#FFD43939" /> </Grid> - Fischermaen
@Fischermaen 这个解决方案对我不起作用,你知道为什么吗?我的按钮仍然超出了屏幕.. http://stackoverflow.com/questions/33847852/how-to-resize-c-sharp-wpf-program-to-fit-any-screen-resolution - user5346812
1
如果您有两个屏幕,它将使用主屏幕分辨率,因此如果软件在另一个屏幕上,则不会发生任何事情。 - ozkulah
显示剩余3条评论

1

基于berhauz的答案。但你甚至可以通过在代码后端(.xaml.cs)执行来进一步简化它:

public Window1()
{
    InitializeComponent();
    this.Height = SystemParameters.PrimaryScreenHeight * 0.95;
    this.Width = SystemParameters.PrimaryScreenWidth * 0.95;
}

0

稍微改进了@berhauz的答案。使用现代模式匹配并省略了字符串转换为双精度浮点数再转换回字符串的步骤:

[ValueConversion(typeof(double), typeof(double))]
public class RatioConverter : MarkupExtension, IValueConverter
{
  private static RatioConverter _instance;

  public RatioConverter() { }

  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    if (value == null || parameter is null)
      return null;
    else if (value is double v && parameter is double p)
      return v * p;
    else
      throw new ArgumentException("Both value and parameter must be of type double.");
}

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  { 
    throw new NotSupportedException();
  }

  public override object ProvideValue(IServiceProvider serviceProvider)
  {
    return _instance ?? (_instance = new RatioConverter());
  }
}

使用方法如下:

<Window.Width>
  <Binding Source="{x:Static SystemParameters.PrimaryScreenWidth}" Converter="{local:RatioConverter}">
    <Binding.ConverterParameter>
      <sys:Double>0.9</sys:Double>
    </Binding.ConverterParameter>
  </Binding>
</Window.MaxWidth>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接