窗口拖动的动态余量

时间:2012-07-04 10:37:41

标签: c# wpf math coordinates parent-child

好的,因为没有回复,完全重写了这个问题。我想要一个可拖动的窗口但是当它被拖动时,改变边距以延伸到窗口的旧位置。即窗口向右移动X,向左延伸边缘X.现在我遇到了一些障碍,例如窗口由于某种原因被切断了边缘。这是我的代码,请告诉我你是否能发现任何东西!

private void Window_LocationChanged(object sender, EventArgs e)
        {
            double TmpLeft = Math.Abs(this.Left - WinLeft);
            double TmpTop = Math.Abs(this.Top - WinTop);

        if (this.IsLoaded)
        {//depending on whether the window is moved left, right
            if (this.Left > WinLeft)
            {//depending on whether the window is moved up, down
                if (this.Top > WinTop)
                    bdr.Margin = new Thickness(TmpLeft, TmpTop, 0, 0);
                else
                    bdr.Margin = new Thickness(TmpLeft, 0, 0, TmpTop);
            }
            else
            {
                if (this.Top > WinTop)
                    bdr.Margin = new Thickness(0, TmpTop, TmpLeft+ 40, 0);
                else
                    bdr.Margin = new Thickness(0, 0, TmpLeft, TmpTop);
            }
        }
    }

private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            WinLeft = this.Left;
            WinTop = this.Top;
            bdr.Height = this.ActualHeight;//I set these because they are auto
            bdr.Width = this.ActualWidth;  //before the window opens
        }

此时整个窗口(将窗口背景设置为黄色以便我可以看到边距)正在移动,我希望边缘的左上角保持在原位。我也注意到我点击拖动窗口的区域(border)也会移动,所以当我移动窗口时,不再是我的点击。希望清楚,再评论任何进一步的问题。

老 - 只读了解我在做什么

所以我正在尝试创建一个具有弹出窗口的应用程序,其中指针/行从子窗口到父窗口中的特定位置。我是这样做的;

<Border Name="brdr" Margin="40,0,0,0" >
    //Content
</Border>

<Line
        Name="Pointer"
        X1="0"
        X2="40"
        Y1="55"
        Y2="50"
        StrokeThickness="2"
        Stroke="Black"
></Line>

注意边框上的40 Margin左侧使窗口大于显示的窗口,以便Polygon向左伸出并指向父窗口(如果有更好/更冷/这样做的更优雅的方式,我都是耳朵)。

所以这很好但现在我希望指针是动态的。如同,如果拖动子窗口,指针必须相对于父窗口的位置缩放。即它必须看起来好像是通过线路连接两个窗口。现在我的计划是记录子窗口打开的点(因为它相对于父窗口打开,初始化时它是正确的)然后使用它与新位置点之间的差异(拖动后)来查找新点这条线应该去。我的代码可能说它比我以前更好......

    private void Window_LocationChanged(object sender, EventArgs e)
    {
        if (this.IsLoaded)
        {
            brdr.Margin = new Thickness(Math.Abs(this.Left - WinLeft) + 40, Math.Abs(this.Top - WinTop), 0, 0);
            Pointer.X1 = Math.Abs(this.Left - WinLeft);
            Pointer.Y1 = Math.Abs(this.Top - WinTop) + 55;
            Pointer.X2 = Math.Abs(this.Left - WinLeft) + 40;
            Pointer.Y2 = Math.Abs(this.Top - WinTop) + 50;
        }
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        WinLeft = this.Left;
        WinTop = this.Top;
    }

正如你所看到的,我必须设置窗口边距,使其延伸到旧位置。然后我将Line坐标重置为新值。正如我所说,所有这些值都是通过比较开口窗口坐标和当前坐标来计算的。

我的问题是,这不对。看到有人能够解决这个问题会非常深刻。

3 个答案:

答案 0 :(得分:0)

我很惊讶没有代码可以从窗口内坐标转换到屏幕坐标。 在我的一个项目中,我不得不在Control下面放置一个窗口。我用它来获取控件中间点的屏幕坐标:

    Point point = MyControl.PointToScreen(new Point((MyControl.ActualWidth / 2)
                                                          , MyControl.ActualHeight));
    PresentationSource source = PresentationSource.FromVisual(MyControl);
    double dpiX = (96 * source.CompositionTarget.TransformToDevice.M11);
    double dpiY = (96 * source.CompositionTarget.TransformToDevice.M22);
    XInScreenCoordinates = ((point.X * 96 / dpiX));
    YInScreenCoordinates = ((point.Y * 96 / dpiY));

如果我没有这样做,则放置时会出错,右侧越多,错误就越多。

答案 1 :(得分:0)

确定我做的小应用程序:
还有MainWindow,主窗口内容非常简单,一行 和一个按钮:

<Grid>
    <Line x:Name="MyLine"  Stroke="Black" StrokeThickness="4" />
    <Button Name="MyButton"                Margin="248,101,0,0"
            HorizontalAlignment="Left"   VerticalAlignment="Top"
            Content="Button" />
</Grid>
然后我做了另一个名为TestWindow的小尺寸(300 * 300)窗口。 TestWindow没有任何内容或代码。

MainWindow背后的代码:

public partial class MainWindow : Window
{
    public TestWindow MyTestWindow;

    public MainWindow()
    {
        InitializeComponent();
        MyTestWindow = new TestWindow();
        MyTestWindow.Show();

        MyTestWindow.LocationChanged += new EventHandler(WinLocationChanged);
        MyTestWindow.SizeChanged += new SizeChangedEventHandler    (   WinSizeChanged);
        this.LocationChanged += new EventHandler(WinLocationChanged);
        this.SizeChanged += new SizeChangedEventHandler(WinSizeChanged);
    }

    void WinSizeChanged(object sender,  SizeChangedEventArgs e)  {
         UpdateLine();         }

    void WinLocationChanged(object sender, EventArgs e)        {            
         UpdateLine();         }

    void UpdateLine()
    {
        // 1. get Window's center in in this window coordinates
        double CX_sc =0.0, CY_sc = 0.0;
          GetWindowCoordinatesInCurrentWindow(MyTestWindow, ref CX_sc, ref CY_sc);
        // 2. Get Center of target Control coordinates in this window coordinates
        Point CenterButtonPoint = MyButton.TransformToAncestor(this).Transform(new Point(MyButton.ActualWidth / 2.0, MyButton.ActualHeight / 2.0));
        //3. Change line's coord.
        MyLine.X1 = CX_sc;
        MyLine.Y1 = CY_sc;
        MyLine.X2 = CenterButtonPoint.X;
        MyLine.Y2 = CenterButtonPoint.Y;
    }

    void GetWindowCoordinatesInCurrentWindow(Window ChildWindow, ref double X, ref double Y)
    {
        Point CenterOfChildWindow = ChildWindow.PointToScreen(new Point((ChildWindow.ActualWidth / 2)
                                                    , ChildWindow.ActualHeight/2));
        Point UpperLeftOfCurrentWindow = this.PointToScreen(new Point(0, 0));
          PresentationSource source = PresentationSource.FromVisual(this);
        double dpiX = ( source.CompositionTarget.TransformToDevice.M11);
        double dpiY = (source.CompositionTarget.TransformToDevice.M22);
        X = (( CenterOfChildWindow.X -UpperLeftOfCurrentWindow.X ) /dpiX);
        Y = ( (CenterOfChildWindow.Y-UpperLeftOfCurrentWindow.Y   ) / dpiY );
    }


}

它的作用是,无论何时移动或调整其中一个窗口,它都将绘制一个 进入MainWindow,将Button“链接”到TestWindow的中间。

好的我知道这不是你想要的:=),因为该行不能超出MainWindow。但我们的想法是拥有一个透明的Popup,它覆盖整个屏幕,你可以在其中做同样的事情。

答案 2 :(得分:0)

实际上找到了一个很好的方法。我做的是我设置子窗口WindowState="Maximized",然后将除Line之外的所有内容放在Canvas中,然后按照http://denismorozov.blogspot.ie/2008/01/drag-controls-in-wpf-using.html(好文章)我可以做到这一点可以在我的窗户周围移动。我对该线进行了硬编码,以便在窗口打开时它处于正确的位置。由于Line的其中一个点不应移动,因此只需更新Canvas_MouseMove事件中的其他点就可以了;

Point p = border.TransformToAncestor(this).Transform(new Point(0, 0));
Line.X2 = p.X;
Line.Y2 = p.Y + 50;

如果您想要一条连接两者的线,让窗口相对于父窗口显示的非常简单的方法。它给出了移动窗口的外观,但实际上是围绕最大化的透明窗口移动控件。