Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
141 views
in Technique[技术] by (71.8m points)

c# - tips on developing resolution independent application

Is it a good practice to find the workarea measurement and set some properties in code so that it could be bound to Control's margin or height/Width properties in xaml?

I do this so that my window would resize according to the available workarea.

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}" />

I do this for some outer containers so that the layout would not be messed in lower resolutions. Currently I work at 1600x900 res(96 dpi) in a 20". My application is gadget like and does not have the regular window.

I want to know if there are some alternative approaches.

A search of [wpf] resolution]1 gives a lot of questions addressing similar problem but still I'm stuck and not able to come to a conclusion how to achieve a good resolution-independent layout.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are two ways to deal with resolution in WPF.

One option is to design to a minimum resolution and just make sure everything is docked appropriately so that the elements get larger as the Window resolution gets larger. This is how many people did things in WinForms and still works decently well for WPF. You probably already have some concept of how to deal with this by setting HorizontalAlignment, VerticalAlignment, and margins.

The newer, trendier thing to do in WPF that was nearly impossible to do in WinForms is have your application actually just zoom in so your controls get bigger as your Window does. To do this, you'll apply a ScaleTransform on some root element in your Window and let WPF take care of the rest. It's really cool.

To show what this is like, here's what a window would look like when you start the app, make it smaller, and make it bigger: http://i.stack.imgur.com/QeoVK.png

Here's the code-behind for the small sample app I made:

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 => (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);
    }
}

And the 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>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...