An application was developed using WPF.

The customer uses the application on the tablet and the interface is too small for fast work, it is required to increase all the elements, let's say, by 50%.

How to do it quickly and at lower cost? In each Window apply Scale to RenderTransform to the layout container? I tried to do it on the example of one of the Window - the window and does not know that the content has increased and it does not fit into the window ...

How is it right to do this? What to pay attention to? And maybe there is a way to make scaling dynamic with the ability to change the coefficient during operation (when working with a mouse, an increase is not required)?

    1 answer 1

    Well, if you solve the problem the way you want (by scaling the interface), then the following idea will do. Let you increase everything by k times (you have k = 1.5 ). We write this:

     <Window ...> <Grid> <!-- внешний контейнер --> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="0.5*"/> <!-- 0.5 = k - 1 --> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="0.5*"/> <!-- 0.5 = k - 1 --> </Grid.RowDefinitions> <Grid Grid.Row="0" Grid.Column="0"> <Grid.RenderTransform> <!-- ScaleX/Y = k --> <ScaleTransform CenterX="0" CenterY="0" ScaleX="1.5" ScaleY="1.5"/> </Grid.RenderTransform> <!-- ну и тут ваш контент --> <Button HorizontalAlignment="Center" VerticalAlignment="Center" Click="OnClick"> GO </Button> </Grid> </Grid> </Window> 

    (I was surprised to find that the RenderTransform moves the hit test area.)


    However, it seems to me that this is not an ideal solution. The fact is that simple interface scaling does not help. Microsoft tried scaling desktop interfaces in earlier versions of Windows Phone, and refused it: this approach suffers from usability.

    When you have little space on the screen, you want not to scale everything, but arrange the elements in a different way. Therefore, it is better to follow the experience of Microsoft, and make a separate interface for tablets, similar to the main one, but “sharpened” for a smaller screen size and touch control. It will look much more professional.


    Addition: If you need to change the size depending on different circumstances, the easiest way is to make it a parameter. This is done like this:

    1. In the MainWindow put a double type DependencyProperty , let's call it ScalseFactor . The default is 1.0 .

       public double ScaleFactor { get { return (double)GetValue(ScaleFactorProperty); } set { SetValue(ScaleFactorProperty, value); } } public static readonly DependencyProperty ScaleFactorProperty = DependencyProperty.Register( "ScaleFactor", typeof(double), typeof(MainWindow), new PropertyMetadata(1.0)); 
    2. Instead of the 1.5 constant in ScaleY prescribe a binding:

       {Binding ScaleFactor, ElementName=Main} 

      (we give the window the name Main to make it easier to tie).

    3. To bind ColumnDefinition we need to subtract one and go from double to GridLength type, so we use a converter. First we define it:

       class RestGridLengthConverter : IValueConverter { public object Convert(object value, Type tt, object parameter, CultureInfo ci) { return new GridLength((double)value - 1, GridUnitType.Star); } public object ConvertBack(object value, Type tt, object parameter, CultureInfo ci) { throw new NotImplementedException(); } } 

      We put in resources and we tie:

       <ColumnDefinition Width="{Binding ScaleFactor, ElementName=Main, Converter={StaticResource RestGridLengthConverter}}"/> 
    4. Everything, now we can adjust the increase at the start of the program (or anytime at all) using ScaleFactor .

    For example, you can tie a slider to it. Here is a complete example:

     <Window x:Class="Example.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Example" Title="Test" Height="350" Width="525" Name="Main"> <Window.Resources> <local:RestGridLengthConverter x:Key="RestGridLengthConverter"/> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="{Binding ScaleFactor, ElementName=Main, Converter={StaticResource RestGridLengthConverter}}"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="{Binding ScaleFactor, ElementName=Main, Converter={StaticResource RestGridLengthConverter}}"/> </Grid.RowDefinitions> <Grid Grid.Row="0" Grid.Column="0"> <Grid.RenderTransform> <ScaleTransform CenterX="0" CenterY="0" ScaleX="{Binding ScaleFactor, ElementName=Main}" ScaleY="{Binding ScaleFactor, ElementName=Main}"/> </Grid.RenderTransform> <Button HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="75"> GO </Button> </Grid> <Slider Grid.RowSpan="2" Grid.ColumnSpan="2" VerticalAlignment="Bottom" Minimum="1" Maximum="5" Value="{Binding ScaleFactor, ElementName=Main}"/> </Grid> </Window> 
     namespace Example { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } public double ScaleFactor { get { return (double)GetValue(ScaleFactorProperty); } set { SetValue(ScaleFactorProperty, value); } } public static readonly DependencyProperty ScaleFactorProperty = DependencyProperty.Register( "ScaleFactor", typeof(double), typeof(MainWindow), new PropertyMetadata(1.0)); } } 
     namespace Example { class RestGridLengthConverter : IValueConverter { public object Convert(object value, Type tt, object parameter, CultureInfo ci) { return new GridLength((double)value - 1, GridUnitType.Star); } public object ConvertBack(object value, Type tt, object parameter, CultureInfo ci) { throw new NotImplementedException(); } } } 

    Result:

    animated cartoon

    • Thanks for the answer. Actually, for now, as a temporary solution, I changed the elements / elements in the xaml-markup margin / padding / fontsize, but on the PC it looks disgusting. How then to make 2 independent markup with the possibility of their change during the work? - Andrey NOP
    • @Andrey: Well, create two classes MainWindowDesktop and MainWindowTablet , and instantiate the desired one. To do this, you will need to create the main window not implicitly through StartupUri , but obviously, like this . - VladD
    • I continue to study WPF, I got to learning styles :). Maybe there is some solution using them? Make 2 sets of styles for elements, select the right one when launching the application ... - Andrew NOP
    • one
      @Andrey: Better not through style, but simply to parameterize through a property. See the answer update. - VladD