It is a common problem to fix resolution related issues. Here I will demonstrate, how your UI will fix itself automatically using few tricks.
Introduction
It is very important to keep track of Operating System Resolution while
building one application. We do lots of things to make our application
work the same way in various ranges of Operating System Resolutions.
For WPF developers, it is quite obvious to miss out the
Anchor and
Dock properties,
which is present in Windows Applications but quite annoyingly absent
here. The result of this is, when we change the Resolution of the
Display, the UI of the application gets waked up abruptly.
"Oh god, how can I solve the same problem once again" --- This
is what I thought after I built a brand new application altogether
tested it in various Resolutions that is supported in my machine, and
saw that it just didn't worked in a machine of one of my colleague.
Well, even I thought of changing the machine resolution to something
that suits my application and revert it when application closes ( Just
like what DirectX games does).
The idea was good, but this would slow down performance, and also make
other programs running in the windows unusable. I was very worried for
the last couple of days, until today, I found a way of eliminating the
problem using ViewBox.
While development of UI, I always liked to avoid ViewBox, as ViewBox
generally changes the normal behavior of the UI elements. But strangely
enough, I found that is the only way to make the UI look the same in
all other Resolution possible.
Using the ViewBox
ViewBox actually stretches or shrinks the User Interface totally based on the size it provided to. Inherited from Decorator, it actually stretch the control with the available space. Now there are few considerations that you need to keep in mind while using ViewBox. ViewBox actually stretches its control without considering the normal behavior as I said earlier. Thus if you have placed a ScrollViewer, you must make sure that it has its height / width specified correctly. If you dont, the whole content of the ScrollViewer will be stretched to the available space. If there is no space, it will shrink the contents of the ScrollViewer and show it within the specified area.
Another example, if you are using WrapPanel. Generally, a WrapPanel wraps the content after certain width is reached. But if placed within a ViewBox, it doesnt, it actually puts all the controls in a single line and shrinks itself.
In our case, you should take care of defining the height and width of each of the controls you specify, so that it doesnt goes with the default behavior of ViewBox control.
<viewbox stretch="Fill">
<grid width="600" Height="800">
</grid>
</viewbox>
There are few properties of ViewBox, which you might look into. One of the important property is Stretch. When Stretch is specified to Fill, it will fill the content exactly with the screen resolution. You can also specify Uniform or UniformToFill based on your requirement, if you want the Ratio of resolution being intact.
Here in the above snippet, I added a grid with Width=600 Height=800, which means the actual size of the Grid is 800/600. But as HorizontalAlignment and VerticalAlignment of any control is Stretch, and there is nothing specified with ViewBox, so the ViewBox will stretch itself, and as a result the Grid will also stretch itself accordingly. Now, you can check the UI in different Resolution, and I bet, it will look the same way in all.
Therefore, the choice should be very accurate. Always think of building your application in a layout which most of your users will have. If you think that your users will generally use 1024 x 768 rather than 1400 x 900, it is smart to build application in 1024 x 768. Its because, even though ViewBox zooms itself according to the size of the Resolution, it actually produces irregular edges, blur textual data etc.
How about SnapsToDevicePixel
WPF actually generates device independent pixels. Thus it does not depends on the actual device pixels. The pixels generally scales itself with the actual DPI settings when its being rendered. This might create blurry effect when the control edge goes in between the pixels. To fix this issue, you can choose the SnapToDevicePixel property to true for the entire Visual Tree to render the controls just using the actual device pixels and results in Transparent edges and anti - aliasing.
In case of building the application, you need to also use SnapToDevicePixel = true to enhance the UI look and feel. You need to consider a few important tips while declaring your controls and maintain the SnapToDevicePixel = true for the entire VisualTree.
- While declaring your control, it is better to wrap the control around a Border and set the SnapToDevicePixel of it to true.
- If you are building a Custom ControlTemplate for a control, and also using a ScrollViewer/ ItemPresenter/ ContentPresenter, put its SnapToDevicePixed bound to TemplatedParent using TemplateBinding.
Other than that, setting SnapToDevicePixel for any control will not visually change anything.
<ComboBox >
<ControlTemplate>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ControlTemplate>
</ComboBox>
In this sample code, you can see, for my ComboBox, I added a ContentPresenter, of course it will look odd, as I didn't defined the entire control, ,but it is just to show how we can use it in ContentPresenter.
Conclusion
It is always said not to use ViewBox for your application, as it might affect performance of your application. ViewBox is very resource hungry, so do not use it much. Design your layout avoiding the ViewBox. If it is possible for you, it is always better to design the application to work on every resolution. But for quick fix, ViewBox is the only option. I think using one ViewBox in a page, will not affect much.
Hoping this would help you in long run. Try out the sample application in different Resolutions and see if it works well or not. Also you can try putting UniformToFill or Uniform to the stretch and see how it differs when resolution Ratio changes.
Thank you for reading.