如何在WPF中移动无边框子窗口/对话框

时间:2014-05-20 09:11:27

标签: wpf windows user-interface borderless

我有一个带有Border的MainWindow和一个没有Border的Dialog的ChildWindow。当子窗口打开时,无法移动主窗口或调整其大小。

我希望应用程序表现得像只有一个Window。

我试图使用以下链接中的行为,但这只是在主窗口内移动我的子窗口。

DragBahvior

3 个答案:

答案 0 :(得分:3)

有一种更简单的方法可以启用拖动或移动无边框Window。有关详细信息,请参阅MSDN上的Window.DragMove Method页面,但简而言之,您只需将此行添加到您的代码中的一个鼠标按下事件处理程序中:

public YourWindow()
{
    InitializeComponent();
    MouseLeftButtonDown += YourWindow_MouseLeftButtonDown;
}

...

private void YourWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    DragMove(); // <-- this is all you need to add
}

然后,用户可以点击Window的任何区域(取决于您放入其中的内容)并将其拖动到屏幕上。

更新&gt;&gt;&gt;

因此,您的要求似乎比我第一次注意到的更多。要实现您想要的目标,您必须做很多事情。首先,您需要将孩子Window放在相对于MainWindow.xaml Window 的特定地点中。当你打开它时,做这样的事情:

Window window = new Window();
window.Top = this.Top;
window.Left = this.Left;
window.LocationChanged += Window_LocationChanged;
window.ShowDialog();

Window位置可能会被某个设定金额抵消:

Window window = new Window();
window.Top = this.Top + someHorizontalOffsetAmount;
window.Left = this.Left + someVerticalOffsetAmount;
window.LocationChanged += Window_LocationChanged;
window.ShowDialog();

然后你需要Window.LocationChanged事件的处理程序(在移动子Window时引发):

private void Window_LocationChanged(object sender, EventArgs e)
{
    Window window = (Window)sender;
    this.Top = window.Top;
    this.Left = window.Left;
}

那就是它!现在两个Window将一起移动。显然,如果在第一个示例中使用偏移量,那么您需要在Window_LocationChanged处理程序中使用相同的偏移量。

答案 1 :(得分:1)

听起来你的对话框是模态,即它是用ShowDialog()调用的,并停止使用应用程序的其余部分直到它被解除,包括移动主窗口。

如果这不是您想要的行为,那么您需要通过调用Show()来建立对话无模式,或者更好,因为您似乎希望它表现为一个窗口,为什么不按原样使用WPF并完全摆脱对话?

答案 2 :(得分:0)

所以我终于找到了解决方案。我写了一个Windows类的扩展,它很复杂:)

namespace MultiWindowWPF
{
  using System;
  using System.Drawing;
  using System.Linq;
  using System.Threading;
  using System.Windows;
  using System.Windows.Forms;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Threading;

  using Application = System.Windows.Application;

  public static class WindowExtensions
  {
    /// <summary>
    /// Shows the Dialog Modal.
    /// </summary>
    /// <param name="dialogWindow">The dialog window.</param>
    public static void ShowModal(this Window dialogWindow)
    {
      Window window = Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w.IsKeyboardFocusWithin) ?? Application.Current.MainWindow;
      IInputElement lastFocused = FocusManager.GetFocusedElement(window);
      IInputElement lastKeyboardSelected = Keyboard.FocusedElement;
      EventHandler locationChanged = (sender, args) => ParentWndMove(dialogWindow);
      SizeChangedEventHandler sizeChanged = (sender, args) => ParentWndMove(dialogWindow);
      EventHandler stateChanged = (sender, args) => ParentWndStateChanged(dialogWindow);

      window.LocationChanged += locationChanged;
      window.SizeChanged += sizeChanged;
      window.StateChanged += stateChanged;

      EventHandler close = (sender, args) =>
      {

        if (dialogWindow.Dispatcher.CheckAccess())
        {
          dialogWindow.Close();
        }
        else
        {
          dialogWindow.Dispatcher.Invoke(dialogWindow.Close);
        }

        window.LocationChanged -= locationChanged;
        window.SizeChanged -= sizeChanged;
        window.StateChanged -= stateChanged;
      };

      EventHandler closed = (sender, args) =>
      {
        Window self = sender as Window;
        Enable();
        if (self != null)
        {
          self.Owner = null;
        }
      };

      ExitEventHandler exit = (sender, args) => close(sender, args);

      DependencyPropertyChangedEventHandler isEnabledChanged = null;
      isEnabledChanged = (o, eventArgs) =>
        {
          window.Dispatcher.BeginInvoke(
            DispatcherPriority.ApplicationIdle,
            new Action(
              () =>
                {
                  FocusManager.SetFocusedElement(window, lastFocused);
          Keyboard.Focus(lastKeyboardSelected);
        }));

        ((Window)o).IsEnabledChanged -= isEnabledChanged;
      };
      window.IsEnabledChanged += isEnabledChanged;
      dialogWindow.Closed += closed;
      Application.Current.Exit += exit;

      dialogWindow.Show();
      ParentWndMove(dialogWindow);

      while (Application.Current != null)
      {
        DoEvents();
      }
    }

    private static void DoEvents()
    {
      DispatcherFrame frame = new DispatcherFrame();
      Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(ExitFrame), frame);
      Dispatcher.PushFrame(frame);
      Thread.Sleep(10);
    }

    private static void Enable()
    {
      foreach (Window window in Application.Current.Windows.OfType<Window>().Where(window => !window.OwnedWindows.OfType<Window>().Any()))
      {
        window.IsEnabled = true;
      }
    }

    /// <summary>
    /// Exits the frame.
    /// </summary>
    /// <param name="f">The f.</param>
    /// <returns></returns>
    public static object ExitFrame(object f)
    {
      ((DispatcherFrame)f).Continue = false;
      return null;
    }

    /// <summary>
    /// Parents the WND state changed.
    /// </summary>
    /// <param name="dialogWindow">The dialog window.</param>
    public static void ParentWndStateChanged(Window dialogWindow)
    {
      Window owner = dialogWindow.Owner;
      if (owner.WindowState != WindowState.Maximized)
      {
        dialogWindow.WindowState = owner.WindowState;
      }
      ParentWndMove(dialogWindow);
    }

    /// <summary>
    /// Parents the WND move.
    /// </summary>
    /// <param name="dialogWindow">The dialog window.</param>
    public static void ParentWndMove(Window dialogWindow)
    {
      Window owner = dialogWindow.Owner;
      PresentationSource presentationsource = PresentationSource.FromVisual(dialogWindow);
      Matrix m = presentationsource.CompositionTarget.TransformToDevice;

      double centerWidth = owner.Left + owner.ActualWidth / 2;
      double centerHeight = owner.Top + owner.ActualHeight / 2;
      if (owner.WindowState == WindowState.Normal)
      {
        dialogWindow.Top = centerHeight - dialogWindow.ActualHeight / 2;
        dialogWindow.Left = centerWidth - dialogWindow.ActualWidth / 2;
      }
      if (owner.WindowState == WindowState.Maximized)
      {
        //there is no current main window position to use, center on working screen
        Rectangle frame = Screen.FromPoint(new System.Drawing.Point((int)(dialogWindow.Left * m.M11), (int)(dialogWindow.Top * m.M22))).Bounds;

        dialogWindow.Left = frame.X / m.M11 + (frame.Width / m.M11 - dialogWindow.ActualWidth) / 2;
        dialogWindow.Top = frame.Y / m.M22 + (frame.Height / m.M22 - dialogWindow.ActualHeight) / 2;
      }
    }
  }
}