2010-07-07 62 views
18

是否找到了工作区的测量和在代码中设置一些属性,以便它可以被绑定到控制在XAML保证金或高度/宽度性能好的做法呢?提示开发与分辨率无关的应用程序

我这样做,这样我的窗口将根据现有的工作区调整。

const int w = SystemParameters.WorkArea.Width; 
const int h = SystemParameters.WorkArea.Height; 

public Thickness OuterGridMargin { get; } 

MainViewModel() 
{ 
    OuterGridMargin = new Thickness(w/5,h/6,w/5,h/4); 
} 

XAML:

<Grid Margin="{Binding OuterGridMargin}" /> 

我对一些外容器这样做,这样的布局将不会在较低的分辨率会混乱。目前我在一个20" 1600x900的解析度(96 dpi)的工作。我的应用程序是小工具等,并没有正规窗口。

我想知道,如果有一些替代方法。

一个搜索[wpf]分辨率] 1给出了很多问题来解决类似的问题,但我仍然坚持不能得出结论如何实现一个好的分辨率独立布局。

回答

42

有两种方法来处理分辨率在WPF。

一种选择是设计的最小分辨率和公正,确保前夕因为窗口分辨率变大,所以元素会适当地停靠。这就是有多少人在WinForms中做了些什么,并且仍然适合WPF。您可能已经有了一些关于如何通过设置Horizo​​ntalAlignment,VerticalAlignment和边距来处理这个问题的概念。

较新的,时髦的事情在WPF做到这一点几乎是不可能的WinForms做的是有你的应用程序实际上只是让你的控制得到作为你的窗口越做越大放大。为此,您将在窗口的某个根元素上应用ScaleTransform,并让WPF负责其余部分。这个真的很酷。

为了说明这是什么样,这里有一个窗口会看什么,当你启动应用程序,使其体积更小,并使其更大,如:http://i.stack.imgur.com/QeoVK.png

下面的代码隐藏在小样本应用程序,我做:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    #region ScaleValue Depdency Property 
    public static readonly DependencyProperty ScaleValueProperty = DependencyProperty.Register("ScaleValue", typeof(double), typeof(MainWindow), new UIPropertyMetadata(1.0, new PropertyChangedCallback(OnScaleValueChanged), new CoerceValueCallback(OnCoerceScaleValue))); 

    private static object OnCoerceScaleValue(DependencyObject o, object value) 
    { 
     MainWindow mainWindow = o as MainWindow; 
     if (mainWindow != null) 
      return mainWindow.OnCoerceScaleValue((double)value); 
     else 
      return value; 
    } 

    private static void OnScaleValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
    { 
     MainWindow mainWindow = o as MainWindow; 
     if (mainWindow != null) 
      mainWindow.OnScaleValueChanged((double)e.OldValue, (double)e.NewValue); 
    } 

    protected virtual double OnCoerceScaleValue(double value) 
    { 
     if (double.IsNaN(value)) 
      return 1.0f; 

     value = Math.Max(0.1, value); 
     return value; 
    } 

    protected virtual void OnScaleValueChanged(double oldValue, double newValue) 
    { 

    } 

    public double ScaleValue 
    {    
     get 
     { 
      return (double)GetValue(ScaleValueProperty); 
     } 
     set 
     { 
      SetValue(ScaleValueProperty, value); 
     } 
    } 
    #endregion 

    private void MainGrid_SizeChanged(object sender, EventArgs e) 
    { 
     CalculateScale(); 
    } 

    private void CalculateScale() 
    { 
     double yScale = ActualHeight/250f; 
     double xScale = ActualWidth/200f; 
     double value = Math.Min(xScale, yScale); 
     ScaleValue = (double)OnCoerceScaleValue(myMainWindow, value); 
    } 
} 

而XAML:

<Window x:Class="WpfApplication1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" 
    Name="myMainWindow" 
    Width="200" Height="250"> 
<Grid Name="MainGrid" SizeChanged="MainGrid_SizeChanged"> 
    <Grid.LayoutTransform> 
     <ScaleTransform x:Name="ApplicationScaleTransform" 
         CenterX="0" 
         CenterY="0" 
         ScaleX="{Binding ElementName=myMainWindow, Path=ScaleValue}" 
         ScaleY="{Binding ElementName=myMainWindow, Path=ScaleValue}" /> 
    </Grid.LayoutTransform> 
    <Grid VerticalAlignment="Center" HorizontalAlignment="Center" Height="150"> 
     <TextBlock FontSize="20" Text="Hello World" Margin="5" VerticalAlignment="Top" HorizontalAlignment="Center"/> 
     <Button Content="Button" VerticalAlignment="Bottom" HorizontalAlignment="Center"/> 
    </Grid> 
</Grid> 

+0

伟大的答案!很详细。 – 2011-02-18 18:50:35

+0

+1为简单,清晰和完整,似乎不公平。 – Arjang 2012-08-08 01:31:42

+0

您也可以将所有内容放在Viewbox中以达到相同的效果。 – Surfbutler 2012-10-06 17:08:09

12

JacobJ很好的答案,我试了一下,它的工作完美。

任何人谁是有兴趣的我做了一个附加的行为,做同样的事情。我还添加了从XAML中指定宽度/高度分母的选项。它可以像这样使用

<Grid Name="MainGrid" 
     inf:ScaleToWindowSizeBehavior.Denominators="1000, 700" 
     inf:ScaleToWindowSizeBehavior.ParentWindow="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}"> 
    <!--...--> 
</Grid> 

ScaleToWindowSizeBehavior

public static class ScaleToWindowSizeBehavior 
{ 
    #region ParentWindow 

    public static readonly DependencyProperty ParentWindowProperty = 
     DependencyProperty.RegisterAttached("ParentWindow", 
              typeof(Window), 
              typeof(ScaleToWindowSizeBehavior), 
              new FrameworkPropertyMetadata(null, OnParentWindowChanged)); 

    public static void SetParentWindow(FrameworkElement element, Window value) 
    { 
     element.SetValue(ParentWindowProperty, value); 
    } 

    public static Window GetParentWindow(FrameworkElement element) 
    { 
     return (Window)element.GetValue(ParentWindowProperty); 
    } 

    private static void OnParentWindowChanged(DependencyObject target, 
               DependencyPropertyChangedEventArgs e) 
    { 
     FrameworkElement mainElement = target as FrameworkElement; 
     Window window = e.NewValue as Window; 

     ScaleTransform scaleTransform = new ScaleTransform(); 
     scaleTransform.CenterX = 0; 
     scaleTransform.CenterY= 0; 
     Binding scaleValueBinding = new Binding 
     { 
      Source = window, 
      Path = new PropertyPath(ScaleValueProperty) 
     }; 
     BindingOperations.SetBinding(scaleTransform, ScaleTransform.ScaleXProperty, scaleValueBinding); 
     BindingOperations.SetBinding(scaleTransform, ScaleTransform.ScaleYProperty, scaleValueBinding); 
     mainElement.LayoutTransform = scaleTransform; 
     mainElement.SizeChanged += mainElement_SizeChanged; 
    } 

    #endregion // ParentWindow 

    #region ScaleValue 

    public static readonly DependencyProperty ScaleValueProperty = 
     DependencyProperty.RegisterAttached("ScaleValue", 
              typeof(double), 
              typeof(ScaleToWindowSizeBehavior), 
              new UIPropertyMetadata(1.0, OnScaleValueChanged, OnCoerceScaleValue)); 

    public static double GetScaleValue(DependencyObject target) 
    { 
     return (double)target.GetValue(ScaleValueProperty); 
    } 
    public static void SetScaleValue(DependencyObject target, double value) 
    { 
     target.SetValue(ScaleValueProperty, value); 
    } 

    private static void OnScaleValueChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
    { 
    } 

    private static object OnCoerceScaleValue(DependencyObject d, object baseValue) 
    { 
     if (baseValue is double) 
     { 
      double value = (double)baseValue; 
      if (double.IsNaN(value)) 
      { 
       return 1.0f; 
      } 
      value = Math.Max(0.1, value); 
      return value; 
     } 
     return 1.0f; 
    } 

    private static void mainElement_SizeChanged(object sender, SizeChangedEventArgs e) 
    { 
     FrameworkElement mainElement = sender as FrameworkElement; 
     Window window = GetParentWindow(mainElement); 
     CalculateScale(window); 
    } 

    private static void CalculateScale(Window window) 
    { 
     Size denominators = GetDenominators(window); 
     double xScale = window.ActualWidth/denominators.Width; 
     double yScale = window.ActualHeight/denominators.Height; 
     double value = Math.Min(xScale, yScale); 
     SetScaleValue(window, value); 
    } 

    #endregion // ScaleValue 

    #region Denominators 

    public static readonly DependencyProperty DenominatorsProperty = 
     DependencyProperty.RegisterAttached("Denominators", 
              typeof(Size), 
              typeof(ScaleToWindowSizeBehavior), 
              new UIPropertyMetadata(new Size(1000.0, 700.0))); 

    public static Size GetDenominators(DependencyObject target) 
    { 
     return (Size)target.GetValue(DenominatorsProperty); 
    } 
    public static void SetDenominators(DependencyObject target, Size value) 
    { 
     target.SetValue(DenominatorsProperty, value); 
    } 

    #endregion // Denominators 
} 
+0

你的答案看起来很有趣,但是在XAML和C#中我仍然太糟糕了,以至于无法工作。我错过了在它的XAML部分使用“inf:”... – 2015-03-04 18:50:08

+0

@AndreaAntonangeli'inf:'是在使用AttachedProperty之前声明的命名空间,即'xmlns:inf =“clr-namespace:My。 App.AttachedProps“'。 – jv42 2015-07-01 13:04:17

0

小修正弗雷德里克Hedblad的答案:

,因为你已经设置在网格元素的DependencyProperty “分母”:

<Grid Name="MainGrid" 
     inf:ScaleToWindowSizeBehavior.Denominators="1000, 700" 
    <!--...--> 
</Grid> 

y您必须使用网格调用GetDominator方法。 相反的:

private static void CalculateScale(Window window) 
    { 
     Size denominators = GetDenominators(window); 

必须使用这样的事情:

private static void mainElement_SizeChanged(object sender, SizeChangedEventArgs e) 
     { 
      FrameworkElement mainElement = sender as FrameworkElement; 
      Window window = GetParentWindow(mainElement); 
      CalculateScale(window, mainElement); 
     } 

private static void CalculateScale(Window window, FrameworkElement mainElement) 
     { 
      Size denominators = GetDenominators(mainElement); 
相关问题