WPF 附加屬性提供某個元素擁有拖拽窗口的功能

我需要窗口內的某個元素擁有拖動整個窗口的功能,也就是這個元素在拖動的時候是拖動整個窗口。而且我還開出一個有趣的方法,這個作爲窗口的拖拽的元素如果是用戶在元素上拖動,那麼將會拖動窗口,如果用戶是點擊,將會觸發點擊事件

附加屬性可以給某個元素附加有趣的功能,本文的功能需要拖動元素的時候實際上是拖動窗口,第二個是元素是支持點擊的

拖動窗口使用的是窗口的 DragMove 方法

元素支持點擊用的是 WPF 給任意控件通過按下移動擡起封裝點擊事件 方法

因此本文需要引入 WPF 給任意控件通過按下移動擡起封裝點擊事件 的 InputHelper 類作爲輔助

用法如下,寫一個簡單的界面,放一個元素作爲拖動的元素

<Border x:Name="DraggingElement" Width="100" Height="100" Background="Gray">
 

    <TextBlock x:Name="TextBlock" Margin="10,10,10,10" HorizontalAlignment="Center"></TextBlock>
</Border>

上面代碼的 DraggingElement 就是用來拖動窗口的元素

接下來在元素放一個 WindowDraggingExtension.DragWindow 附加屬性

<Border x:Name="DraggingElement" Width="100" Height="100" Background="Gray">

   <framework:WindowDraggingExtension.DragWindow>
        <framework:WindowDraggingExtension />
    </framework:WindowDraggingExtension.DragWindow> 

    <TextBlock x:Name="TextBlock" Margin="10,10,10,10" HorizontalAlignment="Center"></TextBlock>
</Border>

注意 framework: 是我的命名空間,請按照自己的代碼修改爲你的命名空間

此時嘗試運行代碼,拖動一下 DraggingElement 這個元素,可以看到拖動的是窗口。這個方法支持觸摸拖動

這個附加屬性能做到的功能類似 QQ 寵物,可以拖動,可以點擊提示更多內容

本文用到的這個附加屬性代碼如下

    /// <summary>
    /// 窗口拖拽的附加方法
    /// </summary>
    public class WindowDraggingExtension
    {
        /// <summary>
        /// 表示元素作爲附加某個窗口提供拖拽的功能
        /// </summary>
        public static readonly DependencyProperty DragWindowProperty = DependencyProperty.RegisterAttached(
            "DragWindow", typeof(WindowDraggingExtension), typeof(WindowDraggingExtension),
            new PropertyMetadata(default(WindowDraggingExtension),
                new PropertyChangedCallback(OnDragWindowPropertyChanged)));

        private static void OnDragWindowPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // 僅有設置,不會存在多次設置,也沒有反過來
            if (e.NewValue is WindowDraggingExtension windowDragging && d is UIElement element)
            {
                InputHelper.AttachMouseDownMoveUpToClick(element,
                    delegate { windowDragging.DraggingElementClicked?.Invoke(null, EventArgs.Empty); }, delegate
                    {
                        if (Mouse.LeftButton == MouseButtonState.Pressed)
                        {
                            var targetWindow = windowDragging.TargetWindow
                                               ?? Window.GetWindow(element);

                            targetWindow?.DragMove();
                        }
                    });
            }
        }

        /// <summary>
        /// 設置元素作爲窗口的拖拽元素
        /// </summary>
        /// <param name="element"></param>
        /// <param name="value"></param>
        public static void SetDragWindow(DependencyObject element, WindowDraggingExtension value)
        {
            element.SetValue(DragWindowProperty, value);
        }

        /// <summary>
        /// 獲取元素作爲窗口拖拽屬性
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static WindowDraggingExtension GetDragWindow(DependencyObject element)
        {
            return (WindowDraggingExtension) element.GetValue(DragWindowProperty);
        }

        /// <summary>
        /// 附加的拖動的窗口,提供此屬性僅僅是爲了提升性能,可以不設置。如不設置將使用 Window.GetWindow 方法獲取當前元素所在窗口
        /// </summary>
        public Window TargetWindow { set; get; }

        /// <summary>
        /// 拖動的元素實際是被點擊時觸發
        /// </summary>
        public event EventHandler DraggingElementClicked;
    }

上面代碼 InputHelper 需要從 WPF 給任意控件通過按下移動擡起封裝點擊事件 複製

通過閱讀上面代碼,可以看到還有兩個可以設置的屬性,一個是 TargetWindow 屬性,一個是元素被點擊的事件

設置 TargetWindow 屬性主要是爲了提升一點性能,通過 TargetWindow 獲取窗口,而不需要通過 Window.GetWindow 方法獲取當前元素所在窗口,使用方法如下

<Window x:Name="CurrentWindow" 忽略元素>

  <Border x:Name="DraggingElement" Width="100" Height="100" Background="Gray">

     <framework:WindowDraggingExtension.DragWindow>
          <framework:WindowDraggingExtension TargetWindow="{x:Reference CurrentWindow}" DraggingElementClicked="WindowDraggingExtension_OnDraggingElementClicked"/>
      </framework:WindowDraggingExtension.DragWindow> 

      <TextBlock x:Name="TextBlock" Margin="10,10,10,10" HorizontalAlignment="Center"></TextBlock>
  </Border>
</Window>

上面代碼還使用方法拿到元素點擊的事件,後臺代碼如下

        private void WindowDraggingExtension_OnDraggingElementClicked(object sender, EventArgs e)
        {
            TextBlock.Text = "林德熙是逗比";
        }

我搭建了自己的博客 https://blog.lindexi.com/ 歡迎大家訪問,裏面有很多新的博客。只有在我看到博客寫成熟之後纔會放在csdn或博客園,但是一旦發佈了就不再更新

如果在博客看到有任何不懂的,歡迎交流,我搭建了 dotnet 職業技術學院 歡迎大家加入

如有不方便在博客評論的問題,可以加我 QQ 2844808902 交流

知識共享許可協議
本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名林德熙(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我聯繫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章