WPF Canvas and DrawingVisuals disappear - wpf

I have a set of User Controls, derived from FrameworkElement. Each host one or more DrawingVisuals. These drawing visuals can represent text, graphics, progress meters etc and are used to display the states of various HMI devices.
These, appearance-wise work fine in a grid - images are rendered, text and backgrounds appear fine, dependency properties can be set. However, when I encapsulate them in a Canvas, they disappear all but for the drawing visuals representing labels. And even for these, only the text rendered by DrawingContext.DrawText is visible. Operations performed by dc.DrawImage, cd.DrawRectangle etc do not appear.
Can someone please shed some light on why this might be.
Thanks

Are you positioning your controls properly? In a grid you have margins for each item, where as in a canvas you have to set Canvas.Top and Canvas.Left for each element. Is it not that those items are hidden underneath something? Try using snoop to use if the controls are actually part of Canvas children or if they have not been added at all.
You can read more about Canvas on MSDN

Related

Why doesn't the Right and Bottom properties appears in the properties window?

I've placed an Ellipse on a Canvas. Only Canvas.Top and Canvas.Left properties are shown in Properties Window. There is no Canvas.Right or Canvas.Bottom. I'm trying to understand why some properties appear (like Top and Left) but others don't (like Bottom and Right).
PS: I know i can set Right and Bottom properties in XAML, but I'm not asking how to set those but why can't I set them in properties Window.
Thank you for reading!
The Top/Left under the layout is to adjust the position of the control in the Canvas. If you use Grid or StackPanel to contain the controls, Top/Left will disappear. In fact, BottomProperty,LeftProperty,RightProperty,TopProperty are all fields of Canvas. The Layout doesn't show all the fields, you can add it in XAML code.
You don't see them because they're not properties.
You just decided you wanted bottom and right.
That doesn't make them exist as properties.
Top and left are used as the x and y co-ordinates to position something on a canvas.
Thus they're fairly important aspects and obviously necessary.
The people building the framework added those attached properties.
The bottom and right points can be calculated using height and width.
If they thought about it at all, whoever was writing the framework must have decided they weren't necessary.

Crop WPF control

I have to crop some control to show only a half of it but the rest should be transparent and clickable so it is not enough to cover the control with something. The result should give a control with only half of the content (for example 50% of top) and the rest should be cropped (not hidden) so some other control below should be visible and not overlapped by cropped part. New control should also scale when window is scaled. How to do this in WPF?
I have finally did the trick using Border around the control and Clip property of this border was set to Multibinging that was generating Rectangle basing on ActualWidth and ActualHeight of my control
Maybe GridSplitter:
http://www.wpf-tutorial.com/panels/gridsplitter/
Can be used to split views horizontally/vertically, and can be responsive.

WPF ScrollViewer set ScrollableHeight

I have a user control which paints content in OnRender. The Height of that control grows by and by.
I added this control to a ScrollViewer. The control does only repaint the currently visible area (viewport) (+/- a view lines for smoother scrolling).
Everything works fine so far...
But since the control usualy grows up to a few hundred thousands of pixels I want to keep the Height of my control as small as possible and provide a different Height value to bind to the ScrollableHeight of the ScrollViewer (same goes for VerticalOffset). But there is no setter for ScrollableHeight. It binds automatically to the Height of my Control. Neither can I override Height.
How can I customize my ScrollViewer (or VerticalScrollbar) to keep the real Height of my control small?
I did something like this in the past. What you need to do is to write your own layout Panel and implement the IScrollInfo in it. The interface looks big, but most of it is just calling one of the main set methods. The layouter needs to set some of the IScrollInfo properties, like ExtentHeight, Offset etc. and these are your way to customize how the ScrollViewer will calculate the scroll position and the scrollable area for your "virtual" canvas size. For implementing the IScrollInfo i used this tutorial as a guidance.

WPF and Silverlight controls and layouts pan and zoom capabilities

I would like to understand the general requirements for WPF/Silverlight layout for making it possible to implement pan&zoom (drag and zoom) features. I don't mean pan&zoom for an image but for a total page (window) layout (or part of it) with some controls.
What features of the layout and what features of used custom controls make layout fixed and pan&zoom impossible?
General rule
With few exceptions, everything in WPF can be panned, zoomed, rotated, stretched, etc to your heart's content. This include single controls like Button, compound controls like ListBox, and containers like StackPanel.
The exceptions
Here are the exceptions:
If you are using Adorner and your AdornerDecorator is outside the panned/zoomed area, then the Adorners attached to your panned/zoomed area will pan but not zoom. The solution is to put an additional AdornerDecorator inside the panned/zoomed area.
If you use a Popup, it will display at the panned/zoomed location of its PlacementTarget but it will not itself be scaled. It will also not move as you pan the area containing its PlacementTarget (basically it sits in its own surface above the target control). To get around this, use a zero-size Canvas with high Z order instead when you want something to pop up within the zoom/pan area.
Any ContextMenu you define will be shown inside a popup, so the menu items will display normal size even when the area you clicked on is zoomed in or out. Because of the nature of a context menu, this is probably desirable behavior. If not, you can wrap the menu items in a ViewBox and tie the zoom to your main area's zoom.
Your ToolTips will display normal size even if the UI is panned or zoomed. Same solution as for ContextMenu.
If you used WinForms integration to integrated legacy WinForms controls and UI, they will not properly pan, zoom and clip in certain situations. There is an advanced technique for working around this, where you implement the WinForms control off-screen, then using BitBlt or similar copy the image into your window as an image, and forward mouse clicks and keystrokes to the offscreen window. This is a lot of work, though.
If you bypass WPF and directly use GDI+ or DirectX, or use Win32 hWnds to display content or UI, that content or UI will not be properly panned, zoomed or clipped to the window unless you do it yourself in your interface code.
Final notes
A good WPF UI always uses panels like Grid, DockPanel, etc to lay out controls in a flexible manner so they automatically adjust to container sizes, rather than using fixed sizes and positions. This is also true for the internal contents of your pan/zoom area as well, BUT there is an exception to this rule: the outermost element in your pan/zoom area must have a specified size. Otherwise what will define the area being panned/zoomed over?
The easy way to implement pan/zoom capabilities is to adjust the RenderTransform of the outermost control in your pan/zoom area. There are many different ways to implement controls for panning and zooming, for example you could use toolbar buttons and sliders, scroll bars, mouse wheel, spacebar+drag to pan, draggable areas of panned UI itself, or any combination of these. Whichever interface you choose, just have it update the RenderTransform appropriately from the code-behind and you're good to go.
If your chosen panning mechanism is scroll bars, you might want to use a ScrollViewer and only use the RenderTransform for the zoom.
Be sure you set clipping on the pan/zoom area. Otherwise if you zoom in or pan items off the side, they will still be visible outside the pan/zoom area.
Use a MultiScaleImage or Canvas area, and place everything you need to pan and zoom in it
<Canvas x:Name="panZoomPanel" Background="Transparent">
</Canvas>
In code use make a TranslateTransform and a ScaleTransform in a TransformGroup to pan and zoom
Check out other SO post or this example or this one
In general you can treat any composite set of UI elements the same as you would treat a single UIElement so the case of an image isn't really different than doing the same for an entire application. The best way to handle zooming based on user input (as opposed to automatic scaling that Viewbox does) is applying a ScaleTransform. This can be set on a high level parent element, like a Grid at the root of a Window layout. For panning you can combine in a TranslateTransform or in some cases use a ScrollViewer to handle moving the view of the content.
One really easy way of implementing zoom in XAML is to use a Silverlight ViewBox. This zooms the XAML not the pixels. You can specify the stretch to use and the ViewBox will scale based on this (Fill, None, Uniform etc). There are some great Viewbox blog posts on the web if you search for Silverlight+Viewbox on Google.
The panning is easily accomplished with a similar mechanism to drag and drop and there are also numerous how-to blog posts on this, available via Google. Just amounts to capturing MouseDown, MouseMove and MouseUp events.

WinForm designer and right snapline for controls in container when resizing it

Using Visual Studio 2008 WinForm designer, I have a container (form, panel, groupbox, whatever) and some controls in it.
The container is set to not automatically resize or dock in any way. When placing a control in the container I can use the snaplines to help in positioning the control.
However, the snaplines does not appear when I resize the container to the edge of the contained controls...
Is there a simple way to have the designer show me the snaplines of the contained controls when resizing the container?
The designer will only show the snap lines when moving a child control within a container. You can demonstrate it by moving a GroupBox around a Form and see that it shows snap lines when the GroupBox gets close to the edge of the Form, but if you were to resize the Form you won't see the snap lines appear.
If you're just looking to get all of the controls to line up in a uniform fashion, I'd suggest switching to SnapToGrid mode and using the grid lines to align your controls. You can set the SnapToGrid mode by going to Tools->Options->Windows Forms Designer->LayoutMode. Open your designer and you should see the grid appear, after that you can line your controls up with the grid.
After setting the layout of the form, you can also set anchoring property to all child controls appropriately, to right and bottom (or top and left), depending on the resizing you are making. Anchor property will hold child controls to same distance from the edges of the container (parent control).
In the WinForms designer, there is no support for snaplines when resizing the container control. The best way to work around this issue is to first size the container to the size you would like to use and then add controls. Optionally, you can change the Margin property of the container so that when moving controls inside the container, they will snap to the margin of the container, keeping it uniform.
Try:
container.AutoSize = true
container.AutoSizeMode = GrowAndShrink
container.Padding.All = 5

Resources