Skip to main content
Home Forums General Silverlight Getting Started Unexpected behavior after ScaleTransform
5 replies. Latest Post by rleclerc on July 6, 2009.
(0)
rleclerc
Member
10 points
15 Posts
07-01-2009 4:50 PM |
I have created a user control that has drag and drop mouse capabilities. To this I planned to add a minimize button which would downscale the control box with an annimation. Testing this I just reduce the scale by 50%. Before I click the minimize button drag and drop works perfectly, however, after I click the minimize button, subsequent mouse clicks on the usercontrol fail to register mouse click events. I can toggle the minimize button so that it returns to full scale, but even then mouse clicks on the control fail to register. Is there some magic property I need to set after scaling?
Thanks,
RDL
vincracker
Contributor
3114 points
521 Posts
07-02-2009 7:39 AM |
Without seeing your code it is hard to locate error, but I don't understand why make a control which is freely available, try this thread for Drag and Drop Model Popup window.
07-02-2009 10:03 AM |
Why add an external library that may give you less control over the UI and which bloats your XAP, when drag and drop can be implemented in a few lines of code which can be cut and pasted where you need it or implemented in a base class? Anyways, it still doesn't address the problem I am having, because I want to annimate the collapse by scaling the window as it moves toward a taskbar.
It is easy to rerpdice this bug (feature?) with a simple example so I am sure the other libraries would have the problem as well
1. Create a new Silverlight Application called TestDragDropResize
2. Create a UserControl called MyWindow
3. Set its code behind to:
public partial class MyWindow: UserControl{ private bool isMouseCapture = false; private Point clickPosition; private bool minimized; public MyWindow() { InitializeComponent(); SetupMouseHandlers(); } public void SetupMouseHandlers() { this.LayoutRoot.MouseLeftButtonDown += (x, y) => { this.LayoutRoot.CaptureMouse(); clickPosition = y.GetPosition(LayoutRoot); this.LayoutRoot.CaptureMouse(); isMouseCapture = true; }; this.LayoutRoot.MouseLeftButtonUp += (x, y) => { this.LayoutRoot.ReleaseMouseCapture(); isMouseCapture = false; }; this.LayoutRoot.MouseMove += (x, y) => { if (isMouseCapture) { this.layoutTranslateTransform.X = y.GetPosition(this).X - clickPosition.X; this.layoutTranslateTransform.Y = y.GetPosition(this).Y - clickPosition.Y; } }; } private void MinMaxButton_Click(object sender, RoutedEventArgs e) { if (false == minimized) (Resources["Minimize"] as Storyboard).Begin(); else (Resources["Maximize"] as Storyboard).Begin(); minimized = !minimized; } }
public partial class MyWindow: UserControl{ private bool isMouseCapture = false; private Point clickPosition; private bool minimized;
public MyWindow() { InitializeComponent(); SetupMouseHandlers(); }
public void SetupMouseHandlers() { this.LayoutRoot.MouseLeftButtonDown += (x, y) => { this.LayoutRoot.CaptureMouse(); clickPosition = y.GetPosition(LayoutRoot); this.LayoutRoot.CaptureMouse(); isMouseCapture = true; };
this.LayoutRoot.MouseLeftButtonUp += (x, y) => { this.LayoutRoot.ReleaseMouseCapture(); isMouseCapture = false; }; this.LayoutRoot.MouseMove += (x, y) => { if (isMouseCapture) { this.layoutTranslateTransform.X = y.GetPosition(this).X - clickPosition.X; this.layoutTranslateTransform.Y = y.GetPosition(this).Y - clickPosition.Y; } }; } private void MinMaxButton_Click(object sender, RoutedEventArgs e) { if (false == minimized) (Resources["Minimize"] as Storyboard).Begin(); else (Resources["Maximize"] as Storyboard).Begin(); minimized = !minimized; }
}
4. And set its XAML to:
<UserControl x:Class="TestDragDropResize.MyWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" > <UserControl.Resources> <Storyboard x:Name="Minimize"> <DoubleAnimation x:Name="ScaleDownX" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" To="0.5" Duration="0:0:1" /> <DoubleAnimation x:Name="ScaleDownY" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" To="0.5" Duration="0:0:1" /> </Storyboard> <Storyboard x:Name="Maximize"> <DoubleAnimation x:Name="ScaleUpX" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" To="1" Duration="0:0:1" /> <DoubleAnimation x:Name="ScaleUpY" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" To="1" Duration="0:0:1" /> </Storyboard> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="Black" Width="100" Height="100"> <Grid.RenderTransform> <TransformGroup> <ScaleTransform x:Name="layoutScaleTransform" ScaleX="1" ScaleY="1" /> <SkewTransform /> <RotateTransform /> <TranslateTransform x:Name="layoutTranslateTransform" X="0" Y="0" /> </TransformGroup> </Grid.RenderTransform> <Button x:Name="MinMax" Click="MinMaxButton_Click" Width="20" Height="20" /> </Grid> </UserControl>
<UserControl x:Class="TestDragDropResize.MyWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<UserControl.Resources> <Storyboard x:Name="Minimize"> <DoubleAnimation x:Name="ScaleDownX" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" To="0.5" Duration="0:0:1" /> <DoubleAnimation x:Name="ScaleDownY" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" To="0.5" Duration="0:0:1" /> </Storyboard>
<Storyboard x:Name="Maximize"> <DoubleAnimation x:Name="ScaleUpX" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" To="1" Duration="0:0:1" /> <DoubleAnimation x:Name="ScaleUpY" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Border.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" To="1" Duration="0:0:1" /> </Storyboard> </UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="Black" Width="100" Height="100"> <Grid.RenderTransform> <TransformGroup> <ScaleTransform x:Name="layoutScaleTransform" ScaleX="1" ScaleY="1" /> <SkewTransform /> <RotateTransform /> <TranslateTransform x:Name="layoutTranslateTransform" X="0" Y="0" /> </TransformGroup> </Grid.RenderTransform> <Button x:Name="MinMax" Click="MinMaxButton_Click" Width="20" Height="20" /> </Grid>
</UserControl>
5. Add the "MyWindow" to to Page.xaml
6. Compile and Run.
UI TEST: Click on the black square and drag it around in your browser (This is just a proof, ignore the jump on the mouse capture). This demonstrates that Drag and drop works. Now click the button which scales MyWindow in half. Try to drag and drop (It will fail, but shouldn't). Click the button again to scale the Window back to normal size. Try again to move the Window (It will fail but shouldn't). I've tried this with IE8 and Chrome.
Note that if you put a break point in the labda expression for mousemove after the resize, you will see that the event fires. However, MouseLeftButtonDown will no longer fire after the resize. Also it doesn't seem like it matters what kind of container you use for MyWindow.
07-03-2009 10:45 AM |
Did anyone find this issue as well? I may not be the cause but I am running Windows 7 RC and VS 2008.
07-04-2009 4:21 AM |
Yes, it is a bug. I don't know why this happens but I can reproduce it. One thing that you expected wrong here is the MouseLeftButtonDown being not fired after the scaling. I can see all the events fired even after the scaling and dragging. So we have some other problem. To resolve this I go around. I used storyboard created in code. Code will look like below.
public partial class MyWindow : UserControl { private bool isMouseCapture = false; private Point clickPosition; private bool minimized; public Storyboard s = new Storyboard(); public static double counter; public MyWindow() { InitializeComponent(); SetupMouseHandlers(); s.Duration = TimeSpan.FromSeconds(0.05); s.Completed += (sender, e) => { if ((layoutScaleTransform.ScaleX >= 0.5 && minimized) || (layoutScaleTransform.ScaleX <= 1 && !minimized)) { layoutScaleTransform.ScaleX += counter; layoutScaleTransform.ScaleY += counter; lblMsg.Text = "Storyboard"; s.Begin(); } }; } public void SetupMouseHandlers() { this.LayoutRoot.MouseLeftButtonDown += (x, y) => { this.LayoutRoot.CaptureMouse(); clickPosition = y.GetPosition(LayoutRoot); this.LayoutRoot.CaptureMouse(); isMouseCapture = true; lblMsg.Text = "mouse captured"; }; this.LayoutRoot.MouseLeftButtonUp += (x, y) => { this.LayoutRoot.ReleaseMouseCapture(); isMouseCapture = false; lblMsg.Text = "mouse released"; }; this.LayoutRoot.MouseMove += (x, y) => { if (isMouseCapture) { this.layoutTranslateTransform.X = y.GetPosition(this).X - clickPosition.X; this.layoutTranslateTransform.Y = y.GetPosition(this).Y - clickPosition.Y; lblMsg.Text = y.GetPosition(this).X.ToString() + " " + y.GetPosition(this).Y.ToString(); } }; } private void MinMaxButton_Click(object sender, RoutedEventArgs e) { lblMsg.Text = Convert.ToString((int)layoutTranslateTransform.X) + " " + Convert.ToString((int)layoutTranslateTransform.Y); if (false == minimized) counter = -0.1; //(Resources["Minimize"] as Storyboard).Begin(); else counter = 0.1; //(Resources["Maximize"] as Storyboard).Begin(); s.Begin(); minimized = !minimized; } }
This will work for sure. And if anyone know what happened in former code let us know the reason.
07-06-2009 10:00 AM |
You are right, it is firing the MouseLeftButtonDown event in this "HelloBug" code example. It's too bad I overwrote the other code already.
Nice work around. You could also use a DispatcherTimer here since the Storyboard isn't really doing anything for you.