2010-07-07 42 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); 
相關問題