Weird lines inside window when property SizeToContent is set - wpf

When I set the SizeToContent="WidthAndHeight" property in my window, WPF renders weird lines around my window:
Is there anything I can do to avoid this?

These artifacts sometimes appear due to sizes not fitting pixel boundaries. You can mitigate the effects by setting UseLayoutRounding to true on root elements or alternatively setting SnapsToDevicePixels to child controls. From the documentation:
When the UseLayoutRounding property for an element is true, all non-integral pixel values that are calculated during the Measure and Arrange passes are rounded to whole pixel values. [...] Drawing objects on pixel boundaries eliminates the semi-transparent edges that are produced by anti-aliasing, when an edge falls in the middle of a device pixel.
In your code, you can set it to the root Window like this:
<Window ...
UseLayoutRounding="True">
Please note, that UseLayoutRounding and SnapsToDevicePixels are not exactly the same. Choose what fits your requirements best. Here is a source for further reading on the latter:
Pixel Snapping in WPF Applications

Related

Label CornerRadius

I have a dockpanel which contains an array of Label (Rectangles) inherited from Border class, which contains CornerRadius property. So, everything is good, but when I start resizing the window, or add the labels to the dockpanel, their size narrows and the Corner remains the same as it was with the bigger label size!! For example, I have a big size label 300*300 with CornerRadius 30. It looks good, but when I resize the window (make it much smaller) it turns into circle.
I tried to implement the special coefficient but nothing helps. Maybe i have made mistake.
Border is "keeping" it's corner radius regardless of it's actual size. And that's usually a good thing.
In your case, I'd use a Path (NOTE: not a Rectangle).
Using Expression Blend, you can draw a Rectangle of a certain size, set it's RadiusX and RadiusY properties and then make a path out of it (there's an option in the menus, under 'Tools', IIRC). The path will scale (and warp) it's corner radius.
Having said that, what do you need this functionality for? Maybe ViewBox will do the job without inheritance?

Scale usercontrol in wpf ? vertical and horizontal scrollbars

I implemented a usercontrol, but i have a problem with rescaling the window. I know when i make the window smaller, everything scales, and every textbox and label becomes also smaller. But this is not what i want, i just want that when i make the screen smaller, everything stays the same size, and that scrollbars appear ( vertical and horizontal ). How do i do that?
Thanks
Assumption
The behaviour you describe, is not mandatory the default layout-behaviour of WPF. It depends on the layout-controls you use. I assume, you're using a Grid with setting it's columns and rows to the Start (*)-GridLengths. This would have more or less such an effect as you describe (without scaling). Or maybe you are using a ViewBox, this control scales the whole content based on the available layout size.
Solution
I guess that wrapping your whole content into a ScrollViewer will probably do what you desire. If not, I suggest that you post some XAML-code to show us how you have built your content.
<ScrollViewer>
<YourContent>
</YourContent>
</ScrollViewer>
Update
If you really scale your window (applying a ScaleTransformation) and you want your UserControl to be the only control within that does not scale, you have to scale your UserControl in the opposite direction as you have done it with your window. Apply a ScaleTransformation and set the scale values to 1/scale. Or try to use the ViewBox to blow up the content of your UserControl, but this will not be very exact.

ScrollViewer's Viewport Height VS Actual Height [duplicate]

This question already has answers here:
WPF DataGrid : CanContentScroll property causing odd behavior
(2 answers)
Closed 9 years ago.
Both are quite general terms but I'm curious to know when these height will be different apart from the case we're using Virtualization?
One more question:
I read on MSDN:
If CanContentScroll is true, the values of the ExtentHeight, ScrollableHeight, ViewportHeight, and VerticalOffset properties are number of items. If CanContentScroll is false, the values of these properties are Device Independent Pixels.
However I'm facing an issue with ViewPort Height: I've 2 listbox in application:
1. Which have Virtualization Enabled and CanContentScroll = True.
2. Which have no virtualization and CanContentScroll = True.
In ListBox 1 while drag-drop Viewport Height comes to 4/5 (Number of elements currently visible). However in ListBox 2 i get Viewport Height equal to Actual Height of Listbox.
Why this difference?
Few more findings:
1. Scrollable Height is number of items not visible in scrollviewer
2. Viewport Height is number of items visible in scrollviewer.
Thus Viewport Height + ScrollableHeight = Extent Height
Can someone please explain what's the difference between two listboxes? I need ViewPort hieght in case of Listbox 1
the ActualHeight is the actual height of the ScrollViewer. The Viewport is what is visible from the ScrollViewers Content. So to answer your question: ViewportHeight differs from ActualHeight if the horizontal Scrollbar is visible by the Height of the Scrollbar.
so, to sum this up:
ActualHeight = ViewportHeight + HorizontalScrollbarHeight
Finally This was the root cause:
Quoting from https://stackoverflow.com/a/3062692/3195477:
You are encountering the differences between physical scrolling and
logical scrolling.
As you have discovered, each has its tradeoffs.
Physical scrolling
Physical scrolling (CanContentScroll=false) just goes by pixels, so:
The viewport always represents exactly the same portion of your scroll
extent, giving you a smooth scrolling experience, and but
The entire contents of the DataGrid must have all templates fully
applied and be measured and arranged to determine the size of the
scrollbar, leading to long delays during loading and high RAM usage,
and It doesn't really scroll items so it doesn't understand
ScrollIntoView very well Logical scrolling
Logical scrolling (CanContentScroll=true) calculates its scroll viewport and extent by items instead of pixels, so:
The viewport may show a different number of items at different times,
meaning the number of items in the viewport as compared to the number
of items in the extent varies, causing the scrollbar length to change,
and
Scrolling moves from one item to the next and never in between,
leading to "jerky" scrolling
but
As long as you're using VirtualizingStackPanel under the hood, it only
needs to apply templates and measure and arrange the items that are
actually visible at the moment, and
ScrollIntoView is much simpler since it just needs to get the right
item index into view
Choosing between them
These are the only two kinds of scrolling provided by WPF. You must
choose between them based on the above tradeoffs. Generally logical
scrolling is best for medium to large datasets, and physical scrolling
is best for small ones.
A trick to speed loading during physical scrolling is to make the
physical scrolling better is to wrap your items in a custom Decorator
that has a fixed size and sets its child's Visibility to Hidden when
it is not visible. This prevents the ApplyTemplate, Measure and
Arrange from occuring on the descendant controls of that item until
you're ready for it to happen.
A trick to make physical scrolling's ScrollIntoView more reliable is
to call it twice: Once immediately and once in a dispatcher callback
of DispatcherPriority.ApplicationIdle.
Making logical scroll scrollbar more stable
If all your items are the same height, the number of items visible in
the viewport at any time will stay the same, causing the scroll thumb
size to stay the same (because the ratio with total number if items
doesn't change).
It is also possible to modify the behavior of the ScrollBar itself so
the thumb is always calculated to be a fixed size. To do this without
any hacky code-behind:
Subclass Track to replace the calculation of Thumb position and size in MeasureOverride with your own
Change the ScrollBar template used for the logical-scrolling ScrollBar to use your subclassed Track instead of the regular
one
Change the ScrollViewer template to explicitly set your custom ScrollBar template on the logical-scrolling ScrollBar
(instead of using the default template)
Change the ListBox template to use explicitly set your custom ScrollViewer template on the ScrollViewer it creates
This means copying a lot of template code fom the built-in WPF
templates, so it is not a very elegant solution. But the alternative
to this is to use hacky code-behind to wait until all the templates
are expanded, then find the ScrollBar and just replace the ScrollBar
template with the one that uses your custom Track. This code saves two
large templates (ListBox, ScrollViewer) at the cost of some very
tricky code.
Using a different Panel would be a much larger amount of work:
VirtualizingStackPanel is the only Panel that virtualizes, and only it
and StackPanel to logical scrolling. Since you are taking advantage of
VirtualizingStackPanel's virtualization abilities you would have to
re-implement all of these plus all IScrollInfo info function plus your
regular Panel functions. I could do something like that but I would
allocate several, perhaps many, days to get it right. I recommend you
not try it.
They can differ from the point of (specified) Height being evaluated to any given time during the (ongoing) rendering process.
From MSDN:
There is a difference between the
properties of Height and Width and
ActualHeight and ActualWidth. For
example, the ActualHeight property is
a calculated value based on other
height inputs and the layout system.
The value is set by the layout system
itself, based on an actual rendering
pass, and may therefore lag slightly
behind the set value of properties,
such as Height, that are the basis of
the input change.
Because ActualHeight
is a calculated value, you should be
aware that there could be multiple or
incremental reported changes to it as
a result of various operations by the
layout system. The layout system may
be calculating required measure space
for child elements, constraints by the
parent element, and so on.

WPF Resizable Canvas

I need to implement a Canvas which scales its contents according to its size. I know there is Viewbox, which scales everything inside of it. However I cannot use that, because some elements have a fixed size and cannot be scaled.
Also how can I bind the size of the Canvas to the parent element (for example a resizable window). There is sizeToContent for windows, I want the size fitting exactly the other way round. Also the canvas uses some drawing based on the size of the hosting element, how is redraw triggered and how can I ensure that it only draws if it gets a valid (or min) size?
If you don't specify any width or height to the canvas it automatically uses all the available space. This is because the default VerticalAlignment and HorizontalAlignment are set to Stretch.
What do you mean by canvas that scales it's contents according to it's size without scaling all the contents as some have fixed size?
Update after comments
If your drawing algorithm already scales the content to the canvas' height and width then all you need to do is to resize the canvas to fit the area I believe? In that case just remove the hardcoded height/width values and the canvas will resize to fit the container.
You might need to use ActualHeight/ActualWidth instead of Height/Width in the drawing algorithm after this though. ActualHeight/ActualWidth return the values that the layout container will give your canvas so these represents the values the canvas is drawn with.
I think you can find the answers to all your questions in my London Underground demo.
I'm doing this from memory, but if I recall correctly a Window uses either a Panel or a Canvas as part of it's ControlTemplate (in which lies the ContentPresenter), which means that a Canvas placed directly in a Window will have issues resizing automatically like it might elsewhere. There are a few basic ways to address this.
1 Write a new ControlTemplate for your Window to use. :(2 Place your content directly in the Window rather than in a Canvas inside the Window. :/
3 Do a by-name binding. :)
<MyWindow x:Name="topWindow">
<Canvas x:Name="topCanvas" Width="{Binding ElementName=topWindow, Path=ActualWidth}" Height="{Binding ElementName=topWindow, Path=ActualHeight}">
...Content...
</Canvas>
</MyWindow>
(As it happens, I often bind grids inside Canvases in this fashion, so I can easily animate items moving from one grid position to another.)

Why everything in WPF is blurry?

Can someone explain why everything in WPF is blurry? Is this something that can be fixed?
The reason for this is the anti-aliasing system which spreads the line over multiple pixels if it doesn't align with physical device pixels.
WPF is resoultion independent. This means you specify the size of an user interface element in inches, not in pixels. A logical unit in WPF is 1/96 of an inch. This scale is chosen, because most screens have a resolution of 96dpi. So in most cases 1 logical unit matches to 1 physical pixel. But if the screen resolution changes, this rule is no longer valid.
All WPF controls provide a property SnapsToDevicePixels. If set to true, the control ensures the all edges are drawn excactly on physical device pixels. But unfortunately this feature is only available on control level.
Source: Draw lines excactly on physical device pixels
Quick Fix:
Use these options on every Container from root to your blurry control
UseLayoutRounding="True"
RenderOptions.BitmapScalingMode="NearestNeighbor"
SnapsToDevicePixels="True"
RenderOptions.ClearTypeHint="Enabled"
Explanation:
UseLayoutRounding=true fixes subpixel layout problems. They often occur because e.g. Effects resize controls to be something between pixels.
RenderOptions.BitmapScalingMode=NearestNeighbor fixes blurry sampling of bitmaps. Bitmaps are used when effects or other techniques are used. When they are reapplied to the container or control they might end up inbetween pixels and therefore interpolate the pixels of the bitmap.
SnapsToDevicePixels="True" fixes vertical and horizontal polygons, lines and rectangles being rendered inbetween pixels
RenderOptions.ClearTypeHint="Enabled" reenables cleartype on text. It is disabled very easily by effects or whenever the renderer does not know the exact background of a text.
You should use it on every Container because sometimes, e.g. by data templates these options are defaulted again for the sub controls.
I spent a couple of hours trying to figure out the cause of the blurriness on custom panels. On these custom panels we are using a drop shadow border effect. The drop shadow was the culprit. It actually causes blurry text if the panels are placed side by side. I don't have a high enough reputation to make a comment so I am answering the question.
UseLayoutRounding="True"
was the fix for my problems as answered by ecreif. although I did not need the other lines of code in his answer, I added them anyways.
The following worked for us when facing similar issue:-
Right Click and open the Properties Window for the executable.
Under "Compatibility" tab, click on "Change High DPI Settings" button then check the "Override High DPI scaling behavior" checkbox at "Application" drop-down selection.
Click on Apply/Ok buttons to save the settings then relaunch app.
P.S.: These settings could be deployed to User system via Windows Registry entry.

Resources