Does RenderTransformOrigin influence scale transforms? - wpf

I am trying to do scale transforms on an InkCanvas and some unseen force seems to be influencing how the scale works. When I try to set CenterX and CenterY they appear to be being ignored.
Update: I should note that the ink canvas is wrapped with a viewbox, I suppose that could be influencing it too...

I tried it out and it does. E.g. in order to make a control sweep from right to left I moved the RenderTransformOrigin to "1, 0" .
I am not certain about the documentation but it could be that CenterX/Y relate not to normalized proportions but to the actual size of the UIElement. If that's the case it is sort of useless.

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?

How to draw shape element faster and make them scale in wpf?

I have this problem.
So I have a bunch of data that must be visualized on a canvas (say more than 5000 items). So I draw them as a bunch of vertical rectangles over a horizontal line, some thing like this:
---|--|||||---|---|||---||----|||||||--------
Now, because the canvas is small, I only draw a different amount of rectangles at different zoom level. So if I zoom in more, the line get longer, and more rectangles I can see.
Problem is every time I zoom in, I have to clear the whole canvas, and redaw everything with the new zoom scale. And it is really suck, the drawing is slow and scaling not really nice.
So I wondering is there a way I can achieve a faster drawing, and good zooming (like those vector graph, you can zoom in unlimited)??
Have you tried ScaleTransform Class?
<Canvas.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY="2" />
</Canvas.RenderTransform>
See How to: Scale an Element too. For performance reasons:
Freeze your Freezables.
Update Rather than Replace a RenderTransform
You may be able to update a Transform rather than replacing it as the
value of a RenderTransform property. This is particularly true in
scenarios that involve animation. By updating an existing Transform,
you avoid initiating an unnecessary layout calculation.
Have you looked at the ZoomableCanvas? I haven't used it, but it looks like it's designed to do exactly what you want.

Zooming into a Canvas without modifying the size of specific child controls

So I realize that I am venturing outside of the intended use of a Canvas here and will likely have to come up with a more manual solution. However, not being overly experienced in WPF I was hoping that there may be some solution which would allow me to continue using a Canvas control and the features it gives you for free.
The issue revolves around a Canvas which is used to zoom in and out of an image and some number of child controls that belong to the Canvas. These child controls are to be placed at various positions on the image and, as such, the Canvas works nicely in that it handles all of the layout/positioning for me as I zoom in or out.
However, one drawback is that the Canvas scales these child controls up as I zoom into the image, causing them to become too large to be usable in practice. What I am looking for is a solution that allows me to zoom into an image that belongs to a canvas without also zooming up the size of the child controls, preferably handling the layout for me.
I have tried modifying the width and height of these child controls as the zoom factor increases or decreases, but there is a slight lag time and it all looks a bit 'jerky'.
If it comes down to it I will simply do all of the zooming/panning/layout myself, but I thought I would ask first just to make sure that I am not missing anything that would allow me to tell the Canvas to not scale the size of certain controls. Thanks in advance.
You can bind the children's RenderTransform to the inverse of the Canvas' transform, see my answer to this similar question on rotation.
This is more of a thought than an answer, but what if you set a transform on the element that you did not want scaled that was the opposite of the canvas itself. So for example, if the canvas had a scale transform of 2.0, set the element to have a scale transform of 0.5. You could probably accomplish this by binding the transform values together using a value converter.
You'll probably want to make sure the element has a render transform origin of 0.5,0.5 so that it scales from the center.

Strategy for implementing a complex curve editor with XAML/WPF

I want to implement a rather complex CurveEditor that has to support the usual requirements like:
freely scalable and moveable axis
different interpolation types per curve point (Linear, Cubic, Spline)
Tangents (joined and broken)
Selecting one or several points to edit (move, scale, delete) via Fence or Click
Only show handles and highlights for selected curve points
I don't want to manipulate actual WPF curves but an existing model with key/value/tangents sets and sample the precise shape of the curve from our implementation.
I already gathered some experience on implementing custom UserControls and Templates. But I want to make sure, I don't miss any apparent solution. I planned to have this general XAML-tree:
CurveEditor - Window holding all content
MainThumb : Enable dragging and scaling the editor range
XAxis : UserControl rending some scale on the left side
YAxis : UserControl rending some scale on the bottom
Curves : Canvas holding the curves
Curve : UserControl for a single curve
CurveName - Label of the curve
CurveLine - DrawingVisual that will render the actual curve by sampling the internal implementation of the spline function.
CurveEditPoints - Canvas that holds all edit points
CurveEditPoint - UserControl for a single edit point
LeftTangent - UserControl for the left tangent handle
LeftTangentThumb - For modifying the handle
RightTangent - UserControl for the right tangent handle
RightTangentThumb - For modifying the handle
CurvePointCenter - Visualisation of the actual point, select state and interpolation type.
CurvePointThumb - Thumb to select and drag point around
I know, this is quite a complex question and I am not asking for an actual implementation. I am interested in the following questions:
Can you recommend any tutorials or books that might help me (I already got Illustrated WPF, WPF Control Development Unleashed, and a couple of other)
Should minor elements like the Tangents be individual UserControls?
What container is best suited for hosting the individual "Curves", "EditPoints" and "Tangents". Right now, I use Canvas and Canvas.SetLeft/SetTop to position the children, but that feels "strange".
Should I use "Shapes" like Path or DrawingVisual-Classes to implement actual representation. Path is straight forward, but I am concerned about performance with hundreds of CurvePoints.
Should I use Transforms to rotate the tangents or is just fine to do some triangulation math in the code behind files?
Does the structure roughly make sense, or do you suggest a completely different approach?
you seem to have the right tools at hand, WPF Unleashed is excellent, but I guess you have that one already.
make individual UserControls in one of these cases:
you are using the same xaml all over the place (DRY)
you xaml file gets too big (get some components out)
you need to inherit from some class
this depends on how much codebehind you want.
you can, as you suggested in your comment, use an ItemsControl as a container for wherever you need selection between multiple items. so this could also be done on the level of Curves, not just on the level of points on the curve. Depending on how you want to handle drawing of the actual lines and curves you can even have an ItemsControl for those. (on a side note: you will not have virtualization out of the box though, as your items won't have a constant height)
Path is OK with hundreds of CurvePoints. If you have 10.000, I'd say you could get problems.
can't imagine how a transform should be used here, maybe inside an Adorner.
your structure looks good. you will be able to implement all of this. I will suggest though how I would do it:
first of all use MVVM.
CurveEditor
ListBox(Panel=Canvas)(ItemsSource=Curves)(ItemTemplate=CurveControl)
CurveControl
Canvas(Background=Transparent) <= I'm not sure if standard is white, but you don't want to overlap other Curves...
CurveName
ListBox(Panel=Canvas(Background=Transparent))(ItemsSource=CurveParts)
ListBox(Panel=Canvas(Background=Transparent))(ItemsSource=CurvePoints)(ItemTemplate=>EditPointControl)
EditPointControl
Canvas
Thumb(Template = Ellipse) (Name=CenterHandle) (with some Visualstates for Selection and hiding of Tangents)
Thumb(Template = Ellipse) (Name=LeftHandle)
Thumb(Template = Ellipse) (Name=RightHandle)
Line (Binding X/Y to Centerpoint and LeftHandlePoint)
Line (Binding X/Y to Centerpoint and RightHandlePoint)
I have stated to set ItemTemplate for the ListBox. You can however style the listbox however you want (I think the standard style includes a border, you might want to remove that or set bordersize=0) and set instead of ItemTemplate the ItemContainerStyle and bind to IsSelected so you have control over IsSelected from your ViewModel (look here for what I mean).
So the viewmodel looks like this:
- CurveEditorViewModel
- ObservableCollection<CurveViewModel> Curves
- CurveViewModel
- string Label
- (Point LabelPlacement)
- bool IsSelected
- ObservableCollection<CurvePointViewModel> CurvePoints
- ObservableCollection<CurvePartViewModel> CurveParts
- CurvePointViewModel
- Point Position
- bool IsSelected
- Point LeftHandle
- Point RightHandle
- CurvePartViewModel
- CurvePointViewModel StartPoint
- CurvePointViewModel EndPoint
- Path CurvePath
in here you can subscribe to CurvePointViewModel's PropertyChanged and recalculate the Path you're exposing.
I'd probably improve on it as I go but that'd be my first guess.
There are some details you might want to watch out for. eg: the style for the thumbs might be a visible circle in the middle and an invisible bigger one around that with background=transparent. that way you can have your visible circle small, but have the user use the tumb in an area around the small circle.
EDIT:
here is an Example for the Thumb:
<Thumb Width="8" Height="8" Cursor="Hand" Margin="-4">
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Grid>
<Ellipse Fill="Transparent" Margin="-6"/>
<Ellipse Stroke="Red" StrokeThickness="2"/>
</Grid>
</ControlTemplate>
</Thumb.Template>
</Thumb>
as you want to position this at a specific point on a canvas setting the Margin to minus half the width and height will place the center of the circle on that point. Furthermore, having that inner ellipse with a transparent fill and Margin of -6 you will get a 6px bigger radius around the inner (smaller) circle where you can drag the thumb.

WPF 3d rotation animations

I have a few 3d rectangles on my screen that I want to pivot around the Y axis.
I want to press down with the mouse, and rotate the 3d object to a max rotation, but when the user moves their mouse, I want to slightly rotate it so that it looks like a see-saw (rotating from a range of -13 to 13 degrees on the Y-Axis).
At the moment, I can do this, but my frame rate really really suffers when I move the mouse quickly. So for example, when I click the left side of the rectangle, I generate a storyboard and animation objects, then rotate the 3d object to -13 degrees. Then when I slightly move the mouse to the right, I want to rotate it to -12.5, and so on...
Again, I can do all of this, its just that the performance suffers greatly! It goes down to 5-FPS in some cases... which is not acceptable.
My question is am I doing this the best way? How else could you animate a rotation base on the users position on the screen?
Thanks for any help you can provide!
Mark
I assume you are doing the following:
Using a separate Model3D for the object you are rotating & including it in a Model3DGroup
Giving it a RotateTransform3D containing an AxisAngleRotation3D
Animating the AxisAngle3D's Axis property in the Storyboard
If my assumptions are correct I think we can conclude the problem is efficiency in rendering, since the CPU required to update a single Axis value, recompute the Transform, and update MILCore is negligible.
I can think of several ways that could improve the rendering performance:
If your Model3D being rotated is a GeometryModel3D backed by a MeshGeometry3D, do as much as you can to simplify the mesh and the materials used. It can also help to substitute a different mesh for closeups.
If the Model3D being rotated is a GeometryModel3D that uses VisualBrush brushes, during animation temporarily replace the VisualBrush with an ImageBrush containing a BitmapImage that is a snapshot of the Visual underlying the VisualBrush as of the instant the animation starts. When the animation ends, put backthe VisualBrush. The user probably won't notice that the contents of the object freeze temporarily when it rotates. (Note that this same technique can be used if your Visual3D is a Viewport2DVisual3D.)
If the Model3D being rotated is combined into a Model3DGroup with other objects but lies entirely in front of or behind the other groups, separate the model into its own separate Viewport3DVisual, appropriately layered to get the effect you want.
Simplify lighting or Material types
Monitor the actual frame rate and if it is going too low when using the storyboard, rotate the object immediately to where the mouse indicates without using an animation.
MSDN presents some tips on what impacts in WPF 3D performance. If you didn't stumble on it yet, check the items on "Performance Impact: High" list.
Edit: In march 2009, Josh Smith published an article on CodeProject that involves rotating 3D objetcs. Maybe you want to check his solution.

Resources