【问题标题】:Dynamic Margin on Window Drag窗口拖动的动态边距
【发布时间】:2012-07-04 10:37:40
【问题描述】:

好的,由于缺乏回复,所以完全重写了问题。我想要一个可拖动的窗口,但在拖动它时,更改边距以延伸到窗口的旧位置。 IE。窗口向右移动 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 突出到左侧并指向父窗口(如果有更好/更酷/更优雅的方式这样做,我全神贯注)。

所以效果很好,但现在我希望指针是动态的。例如,如果子窗口被拖动,则指针必须相对于父窗口的位置进行缩放。 IE。它必须看起来好像两个窗口通过线连接。现在我的计划是记录子窗口打开的点(因为它相对于父窗口打开,初始化时是正确的),然后使用这个和新位置点之间的差异(拖动后)找到新点该行应该去。我的代码可能比以往任何时候都说得更好......

    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 坐标重置为新值。正如我所说,所有这些值都是通过将打开窗口坐标与当前坐标进行比较来计算的。

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

【问题讨论】:

  • 在您的 Update2 中,“它仍然不是很好”是什么意思?您的子窗口应该始终位于父窗口的左侧?
  • 我已经重写了我的问题,现在更清楚了吗?
  • 如果您的子窗口指向父窗口,它必须向用户显示一些有用的信息。您不应该允许用户移动子窗口。
  • 它必须能够移动,因为用户可能还希望看到孩子可能掩盖的主窗口的不同部分。
  • 如果:1) 子窗口正好位于箭头应显示的信息上? 2)子窗口在该信息的右侧?

标签: c# wpf math coordinates parent-child


【解决方案1】:

我很惊讶没有代码可以从窗口内坐标切换到屏幕坐标。 在我的一个项目中,我必须在控件下方放置一个窗口。我用这个来获取控件中间点的屏幕坐标:

    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));

如果我不这样做,放置会有错误,越靠右越错误。

【讨论】:

  • 我在其他地方做过类似的事情Point Point = btn.TransformToAncestor(this).Transform(new Point(0, 0)); double double = relativePoint.Y + this.Top + SystemParameters.CaptionHeight 96 是关于什么的?
【解决方案2】:

好的,我做了一个小应用程序:
还有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 覆盖整个屏幕,您可以在其中执行相同的操作。

【讨论】:

  • 是的,我明白你的意思。看起来很不错,我现在就在我的应用中试试看!
【解决方案3】:

实际上找到了一个很好的方法。我所做的是我设置了子窗口的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;

如果您想要一条连接这两者的线,那么让您的窗口相对于父窗口显示的非常简单的方法。它看起来像是在移动窗口,但实际上是在一个最大化的透明窗口周围移动控件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    • 2016-07-03
    • 1970-01-01
    • 2014-09-22
    • 2014-10-06
    • 2015-03-05
    相关资源
    最近更新 更多