Quite simply, I want to create some resize/rescale adorners to attach to a FrameworkElement that will allow the user to resize the element if they use the adorners normally and will allow them to rescale the element (not necessarily uniformly) if they use the bottom-right adorner and hold the SHIFT button whilst doing so.
I've tried various ways of achieving this, but I always end up with the adorners themselves being scaled, so they end up huge, or with massive borders. I've since started using positions relative to the window to position them and ignored the RenderTransform applied to the AdornedElement, however I get some very unusual behavior.
Firstly, when I scale the element more than (roughly) by 2x, the rescale behaviour breaks down and starts jumping all over the place.
Obviously this behaviour is easier to see than describe, hence why I have attached a sample solution (VS 2010) that demonstrates the issue and the code that causes it.
Example VS 2010 solution
If anyone can give me any pointers in the right direction, please feel free to tell me I'm doing it all wrong! lol.
Also, to keep in mind that this adorner will eventually also have to display correctly if the underlying adorned element is rotated, which at present it will not.
Update: Just to keep NVM happy, here's the solution doing it his way: NVM's way
Assuming you have Thumbs inside the adorner for dragging/rotating etc, you will first want to stop them from scaling so you do it in the GetDesiredTransform override. Apply an inverse of the scale you have applied on the framework element. This makes your thumbs not scale when you resize.
public override GeneralTransform GetDesiredTransform(GeneralTransform transform)
{
double scaleFactor = GetCurrentScaleFactor(this._parent);
if (this._visualChildren != null)
{
foreach (var thumb in this._visualChildren.OfType<Thumb>())
{
thumb.RenderTransform
= new ScaleTransform(1 / scaleFactor , 1 / scaleFactor );
thumb.RenderTransformOrigin = new Point(0.5, 0.5);
}
}
return base.GetDesiredTransform(transform);
}
Next problem will be arranging the thumbs so that they end up at the correct places after scaling/rotating etc. Since you've changed the Render transform for the thumb you must now also manually arrange it using the ArrangeOverride.
For this keep a list of all your thumbs and what positions they should be in. If you are dealing only with square elements your work is half done because you only need to deal with corners and sides.
protected override Size ArrangeOverride(Size finalSize)
{
var adornedElement = this.AdornedElement as FrameworkElement;
// Use the width/height etc of adorned element to arrange the thumbs here
// Its been a long time so either its width/height or actualwidth/actualheight
// you will need to use.
this._leftTopThumb.Arrange(Get the Rect To arrange here);
this._rightTopThumb.Arrange(Get the Rect To arrange here);
// etc
return finalSize;
}
If you don't know how to do the arrange stuff See This code project article.
If you still cant get it to work show us the relevant code (not a visual studio solution) that is likely causing problems and someone will help you along I am sure.
EDIT
First simplify your code to understand your problem.
Essentially the crux of your problem code boils down to the commented line:
void _btmRight_DragCompleted(object sender, DragCompletedEventArgs e)
{
var adornedElement = AdornedElement as FrameworkElement;
var hitThumb = sender as Thumb;
if (adornedElement == null || hitThumb == null) return;
var transformGroup = new TransformGroup();
transformGroup.Children.Add(adornedElement.RenderTransform);
//---- This is the problem line
transformGroup.Children.Add(new ScaleTransform(1 + e.HorizontalChange / adornedElement.Width, 1 + e.VerticalChange / adornedElement.Height));
//-------------------------------
adornedElement.RenderTransform = new MatrixTransform(transformGroup.Value);
}
Now its easy to figure out the problem. This piece of code works great the first time you drag and resize. That is because adornedElement.Width and adornedElement.Height are correct when you drag it the first time as no scale transforms have been applied yet. Once your drag is completed you assume that the Width and Height would now be the new width and Height. They are not! You see this is just a render transform, it does not change the width or height of the element. It just renders it bigger.
So what you need to do it first apply the existing scale transform to the Width and Height get the rendered width and heights. Then calculate the scale transform using these new values and add to the transform group. Then you will get what you want.
You will most likely still have other problems when doing this in DragDelta. But in that case you should ask a more specific question with only that small bit of relevant code and you will get the answer from someone in a few minutes I am sure.
Siyfion, the phenomenon you can see is real. The reason is that you don't compensate with the same scaling when you process the adorner dragging. In addition to NVM's answer, make sure you also have this:
double deltaX = args.HorizontalChange / CurrentDisplayScaleX;
double deltaY = args.VerticalChange / CurrentDisplayScaleX;
where you obtain the current display scale the same way. With these corrected values, the jumping around will cease. The jumping is actually double drawing, first by the system automatically, using the wrong scaling, second by using the modified, correct sizes provided by you. It appears at all scale levels, only that it becomes really obvious once the scaling starts to get bigger.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With