Search code examples
silverlightdraggableevent-bubbling

Event bubbling with CaptureMouse() in Silverlight


I'm writing a window program in Silverlight, meaning that the top bar of a popup has a draggable area, and within that draggable area, an "X" that closes the window. My drag function has a capturemouse() event which, when combined with the event bubbling that occurs, prevents the close function from being called. Here's the code:

private void close_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e){
            pop.IsOpen = false;
            hasFocus = true;
        }

        private void topBar_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Border item = sender as Border;
            mouseY = e.GetPosition(null).Y;
            mouseX = e.GetPosition(null).X;
            draggable = true;
            item.CaptureMouse();

        }

        private void topBar_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if(draggable){
                double changeY = e.GetPosition(null).Y - mouseY;
                double changeX = e.GetPosition(null).X - mouseX;
                double top = changeY + (double)pop.GetValue(Canvas.TopProperty);
                double left = changeX + (double)pop.GetValue(Canvas.LeftProperty);
                if(top<0){
                    top = 0;
                }
                if(left<0){
                    left = 0;
                }
                if(left>670){
                    left = 670;
                }
                if(top>450){
                    top = 450;
                }
                pop.SetValue(Canvas.TopProperty, top);
                pop.SetValue(Canvas.LeftProperty, left);
                mouseY = e.GetPosition(null).Y;
                mouseX = e.GetPosition(null).X;
            }
        }

        private void topBar_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Border item = sender as Border;
            draggable = false;
            mouseY = -1;
            mouseX = -1;
            item.ReleaseMouseCapture();
        }

EDIT: here is the XAML for the entire popup:

<Popup x:Name="pop" Height="200" Width="200" VerticalAlignment="Center" HorizontalAlignment="Center">
                    <Border CornerRadius="5" Width="200" Height="200" Background="#FFFAFCFF" BorderThickness="1">
                        <Border.BorderBrush>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#99666666" Offset="0" />
                                <GradientStop Color="#99F5F5F5" Offset="0.5"/>
                                <GradientStop Color="#99666666" Offset="1"/>
                            </LinearGradientBrush>
                        </Border.BorderBrush>
                        <StackPanel>
                            <Border x:Name="topBar" CornerRadius="4,4,0,0" BorderBrush="Silver" BorderThickness="0,0,0,1" Background="Crimson" Width="198" Height="20" MouseLeftButtonDown="topBar_MouseLeftButtonDown" MouseMove="topBar_MouseMove" MouseLeftButtonUp="topBar_MouseLeftButtonUp">
                                <Image x:Name="close" Source="X.png" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,7,0" Height="11" Width="11" MouseLeftButtonUp="close_MouseLeftButtonUp" />
                            </Border>
                            <StackPanel Margin="10">
                                <TextBlock Text="Printer info goes here..." />
                            </StackPanel>
                        </StackPanel>
                    </Border>
                </Popup>

Solution

  • The problem occurs because of your MouseCapture calls. When you set the mousecapture, the border is the only control that will be allowed to initiate mouse events. This means the image, while the mouse button is down, no longer triggers mouseevents. Without the mousecapture it should work fine. Just for my curiosity, why do you set and release it?

    I hope this helps.

    Edit:

    You can get the position of the mouseEvent and see if it falls in the image:

            var x = e.GetPosition(close).X;
            var y = e.GetPosition(close).Y;
            if (0 <= x && x <= 11 && 0 <= y && y <= 11)
            {
                //do the close call
            }
    

    I haven't tested this code but it should be close to what you want to do.