<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          真?WPF 按鈕拖動(dòng)和調(diào)整大小

          共 7779字,需瀏覽 16分鐘

           ·

          2020-09-01 10:17

          真?WPF?按鈕拖動(dòng)和調(diào)整大小

          獨(dú)立觀察員 2020 年 8 月 29 日

          手頭有個(gè) Winform 程序,是使用動(dòng)態(tài)生成按鈕,然后拖動(dòng)、調(diào)整大小,以此來記錄一些坐標(biāo)數(shù)據(jù),最后保存坐標(biāo)數(shù)據(jù)的。

          在數(shù)據(jù)量(按鈕數(shù)量)比較小的時(shí)候是使用得挺愉快的,但是,當(dāng)按鈕數(shù)上去之后,比如達(dá)到四五百個(gè)按鈕,那就比較痛苦了。具體來說就是,無論是移動(dòng)窗口,還是拖動(dòng)滾動(dòng)條,或者是最小化窗口再還原,都會(huì)引起界面重繪,表現(xiàn)為按鈕一個(gè)接一個(gè)地出現(xiàn)。

          經(jīng)過實(shí)測(cè),與電腦的性能和 GPU 都沒有關(guān)系,網(wǎng)上針對(duì) Winform 這個(gè)問題的解決方案,比如開啟雙緩沖等,都大致嘗試了,并無任何起色,反而可能更糟。所以就像網(wǎng)友所說,這個(gè)要么不要在同一個(gè)界面上放置太多控件;要么使用 WPF,畢竟 WPF 采用的是 DirectX 作為底層繪圖引擎,而 Winform 則采用傳統(tǒng)的 GDI 。由于業(yè)務(wù)需求,不讓在界面上放置過多控件的方案不太可行,或者說暫未想到有什么變通的辦法,所以決定改版為 WPF 試試。

          ?

          經(jīng)過幾天的改造,原 Winform 版軟件的一小部分功能已改版為 WPF 版,而且成果喜人,同樣的按鈕數(shù)量,現(xiàn)在無論怎樣折騰,這幾百個(gè)按鈕就如同釘在了界面上一樣,不再能看到他們載入的過程了。在這個(gè)改造的過程中,我是將 Winform 版軟件中關(guān)于按鈕拖動(dòng)和調(diào)整大小的代碼改造為 WPF 版的,聽上去挺簡(jiǎn)單的,但是還是碰到了一些問題,比如 WPF 屏蔽了鼠標(biāo)左鍵的一些事件,需要額外處理一下,還有的就是關(guān)于坐標(biāo)定位的一些問題了,下面將給出一些關(guān)鍵代碼,和大家相互交流學(xué)習(xí)一下。

          ?

          首先,先上一道小菜,解決一下 WPF 按鈕控件(Button)中文字自動(dòng)換行的問題。

          不對(duì),還是先看看 Demo 的界面結(jié)構(gòu)吧:

          ?

          其它控件和布局就不說了(最后會(huì)給出 Demo 地址),關(guān)鍵的是中間這個(gè) ScrollViewer 包裹的 Canvas,我們生成的按鈕都是在這個(gè) Canvas 上的,拖動(dòng)和調(diào)整大小也是。Winform 的布局是依賴于坐標(biāo)的,WPF 的布局控件則基本是不使用坐標(biāo)定位的,甚至都不推薦指定大小,而只有 Canvas 布局控件保留了以坐標(biāo)定位的模式,正好適合我們的需求(之前 Winform 版使用的是 Panel 控件)。

          可以看到里面我還注釋了一個(gè)?Button?,這個(gè)就是用來演示我們的 “小菜” 問題(按鈕文字自動(dòng)換行)的。我們先把注釋放開,并且只保留其寬和高的設(shè)置:

          ?

          可以看到當(dāng)按鈕寬度窄于文本內(nèi)容時(shí),文本內(nèi)容并不能進(jìn)行自動(dòng)換行,且 Button 控件并沒有相關(guān)屬性進(jìn)行設(shè)置。解決方法就是在按鈕中添加 TextBlock 控件,然后設(shè)置其 TextWrapping 屬性,當(dāng)然,這里我們不直接這樣寫,而是使用內(nèi)容模板:

          <Button Width="38" Height="75" ContentTemplate="{DynamicResource DataTemplateButtonWrap}">1A005Button>

          ?

          這個(gè)模板的資源放在 App.xaml 中:

          <Application.Resources>    <DataTemplate x:Key="DataTemplateButtonWrap" DataType="Button">        <Grid>            <TextBlock TextWrapping="Wrap" Text="{TemplateBinding Content}">TextBlock>        Grid>    DataTemplate>Application.Resources>

          ?

          TextBlock 中使用了 TemplateBinding 將 Button 的 Content “綁架” 到了自己的 Text 中,哈哈??纯葱Ч?/p>

          ?

          至于后臺(tái)動(dòng)態(tài)綁定資源則是使用 SetResourceReference 方法,后面代碼里也有體現(xiàn)。

          ?

          好了,小菜吃完了,開始吃主菜吧:

          #region 成員
          private Control _control;private int _btnNum = 0;
          #endregion
          /// /// 設(shè)置控件在 Canvas 容器中的位置;/// private void SetControlLocation(Control control, Point point){ Canvas.SetLeft(control, point.X); Canvas.SetTop(control, point.Y);}
          /// /// 添加按鈕/// private void AddBtnHandler(){ string btnContent = GetBtnContent();
          Button btn = new Button { Name = "btn" + btnContent, Content = "btn" + btnContent, Width = 80, Height = 20, };
          _control = btn; AddContorlToCanvas(_control); SetControlLocation(_control, new Point(163, 55));}
          /// /// 添加控件到界面;/// /// private void AddContorlToCanvas(Control control){ control.MouseDown += MyMouseDown; control.MouseLeave += MyMouseLeave; //_control.MouseMove += MyMouseMove; control.KeyDown += MyKeyDown;
          // 解決鼠標(biāo)左鍵無法觸發(fā) MouseDown 的問題; control.AddHandler(Button.MouseLeftButtonDownEvent, new MouseButtonEventHandler(MyMouseDown), true); control.AddHandler(Button.MouseMoveEvent, new MouseEventHandler(MyMouseMove), true);
          CanvasMain.Children.Add(control);
          if (control is Button) { // 模板中設(shè)置按鈕文字換行 (模板資源在 App.xaml 中); control.SetResourceReference(ContentTemplateProperty, "DataTemplateButtonWrap"); _btnNum++; }}
          /// /// 生成按鈕內(nèi)容/// /// private string GetBtnContent(){ return (_btnNum + 1).ToString().PadLeft(3, '0');}
          /// /// 刪除按鈕/// private void DelBtnHandler(){ CanvasMain.Children.Remove(_control);}

          ?

          上面代碼是對(duì)按鈕生成、添加到界面的一些操作邏輯,每個(gè)方法都有注釋,具體的大家自己看看,這里就不在贅述了。其中?添加控件到界面 的方法 AddContorlToCanvas 中,給控件(本文指的是按鈕)添加了 MouseDown、MouseLeave、MouseMove、KeyDown 等鼠標(biāo)鍵盤事件,然后開頭說過,WPF 屏蔽了 Button 的鼠標(biāo)左鍵的一些事件,所以需要使用 AddHandler 進(jìn)行處理。

          ?

          下面來看看主菜中的精華:

          #region 實(shí)現(xiàn)窗體內(nèi)的控件拖動(dòng)
          const int Band = 5;const int BtnMinWidth = 10;const int BtnMinHeight = 10;private EnumMousePointPosition _enumMousePointPosition;private Point _point; // 記錄鼠標(biāo)上次位置;
          #region btn 按鈕拖動(dòng)
          /// /// 鼠標(biāo)按下/// private void MyMouseDown(object sender, MouseEventArgs e){ // 選擇當(dāng)前的按鈕 Button button = (Button)sender; _control = button; //Point point = e.GetPosition(CanvasMain);
          // 左鍵點(diǎn)擊按鈕后可按 WSAD 進(jìn)行上下左右移動(dòng); if (e.LeftButton == MouseButtonState.Pressed) { button.KeyDown += new KeyEventHandler(MyKeyDown); }
          double left = Canvas.GetLeft(_control); double top = Canvas.GetTop(_control);
          // 右鍵點(diǎn)擊按鈕可向選定方向生成新按鈕; if (e.RightButton == MouseButtonState.Pressed) { Button btn = new Button { Name = "btn" + GetBtnContent(), Content = GetStrEndNumAddOne(button.Content.ToString()) };
          CheckRepeat(btn.Content.ToString());
          btn.Width = _control.Width; btn.Height = _control.Height;
          if (rbUpper.IsChecked == true)// 上 { int h = txtUpper.Text.Trim() == "" ? 0 : Convert.ToInt32(txtUpper.Text.Trim()); SetControlLocation(btn, new Point(left, top - _control.Height - h)); } if (rbLower.IsChecked == true)// 下 { int h = txtLower.Text.Trim() == "" ? 0 : Convert.ToInt32(txtLower.Text.Trim()); SetControlLocation(btn, new Point(left, top + _control.Height + h)); } if (rbLeft.IsChecked == true)// 左 { int w = txtLeft.Text.Trim() == "" ? 0 : Convert.ToInt32(txtLeft.Text.Trim()); SetControlLocation(btn, new Point(left - _control.Width - w, top)); } if (rbRight.IsChecked == true)// 右 { int w = txtRight.Text.Trim() == "" ? 0 : Convert.ToInt32(txtRight.Text.Trim()); SetControlLocation(btn, new Point(left + _control.Width + w, top)); }
          _control = btn; AddContorlToCanvas(_control); } //TODO 中鍵點(diǎn)擊按鈕可進(jìn)行信息編輯;}
          /// /// 檢查重復(fù)內(nèi)容按鈕/// /// private void CheckRepeat(string content){ foreach (Control c in CanvasMain.Children) { if (c is Button btn) { if (content == btn.Content.ToString()) { MessageBox.Show("出現(xiàn)重復(fù)按鈕內(nèi)容:" + content, "提示"); return; } } }}
          /// /// 獲取非純數(shù)字字符串的數(shù)值加一結(jié)果;/// private string GetStrEndNumAddOne(string str){ int numberIndex = 0; // 數(shù)字部分的起始位置; int charIndex = 0; foreach (char tempchar in str.ToCharArray()) { charIndex++; if (!char.IsNumber(tempchar)) { numberIndex = charIndex; } }
          string prefix = str.Substring(0, numberIndex); string numberStrOrigin = str.Remove(0, numberIndex); string numberStrTemp = "";
          if (numberStrOrigin != "") { numberStrTemp = (Convert.ToInt32(numberStrOrigin) + 1).ToString(); }
          string result = ""; if (numberStrOrigin.Length <= numberStrTemp.Length) { result = prefix + numberStrTemp; } else { result = prefix + numberStrTemp.PadLeft(numberStrOrigin.Length, '0'); }
          return result;}
          /// /// 鼠標(biāo)離開/// private void MyMouseLeave(object sender, EventArgs e){ _enumMousePointPosition = EnumMousePointPosition.MouseSizeNone; _control.Cursor = Cursors.Arrow;}
          /// /// 鼠標(biāo)移動(dòng)/// private void MyMouseMove(object sender, MouseEventArgs e){ _control = (Control)sender; double left = Canvas.GetLeft(_control); double top = Canvas.GetTop(_control); Point point = e.GetPosition(CanvasMain); double height = _control.Height; double width = _control.Width;
          if (e.LeftButton == MouseButtonState.Pressed) { switch (_enumMousePointPosition) { case EnumMousePointPosition.MouseDrag:
          SetControlLocation(_control, new Point(left + point.X - _point.X, top + point.Y - _point.Y));
          break;
          case EnumMousePointPosition.MouseSizeBottom:
          height += point.Y - _point.Y;
          break;
          case EnumMousePointPosition.MouseSizeBottomRight:
          width += point.X - _point.X; height += point.Y - _point.Y;
          break;
          case EnumMousePointPosition.MouseSizeRight:
          width += point.X - _point.X;
          break;
          case EnumMousePointPosition.MouseSizeTop:
          SetControlLocation(_control, new Point(left, top + point.Y - _point.Y)); height -= (point.Y - _point.Y);
          break;
          case EnumMousePointPosition.MouseSizeLeft:
          SetControlLocation(_control, new Point(left + point.X - _point.X, top)); width -= (point.X - _point.X);
          break;
          case EnumMousePointPosition.MouseSizeBottomLeft:
          SetControlLocation(_control, new Point(left + point.X - _point.X, top)); width -= (point.X - _point.X); height += point.Y - _point.Y;
          break;
          case EnumMousePointPosition.MouseSizeTopRight:
          SetControlLocation(_control, new Point(left, top + point.Y - _point.Y)); width += (point.X - _point.X); height -= (point.Y - _point.Y);
          break;
          case EnumMousePointPosition.MouseSizeTopLeft:
          SetControlLocation(_control, new Point(left + point.X - _point.X, top + point.Y - _point.Y)); width -= (point.X - _point.X); height -= (point.Y - _point.Y);
          break;
          default:
          break; }
          // 記錄光標(biāo)拖動(dòng)到的當(dāng)前點(diǎn) _point.X = point.X; _point.Y = point.Y;
          if (width < BtnMinWidth) width = BtnMinWidth; if (height < BtnMinHeight) height = BtnMinHeight; _control.Width = width; _control.Height = height; } else { _enumMousePointPosition = GetMousePointPosition(_control, e); //' 判斷光標(biāo)的位置狀態(tài)
          switch (_enumMousePointPosition) //' 改變光標(biāo) { case EnumMousePointPosition.MouseSizeNone: _control.Cursor = Cursors.Arrow; //' 箭頭 break;
          case EnumMousePointPosition.MouseDrag: _control.Cursor = Cursors.SizeAll; //' 四方向 break;
          case EnumMousePointPosition.MouseSizeBottom: _control.Cursor = Cursors.SizeNS; //' 南北 break;
          case EnumMousePointPosition.MouseSizeTop: _control.Cursor = Cursors.SizeNS; //' 南北 break;
          case EnumMousePointPosition.MouseSizeLeft: _control.Cursor = Cursors.SizeWE; //' 東西 break;
          case EnumMousePointPosition.MouseSizeRight: _control.Cursor = Cursors.SizeWE; //' 東西 break;
          case EnumMousePointPosition.MouseSizeBottomLeft: _control.Cursor = Cursors.SizeNESW; //' 東北到南西 break;
          case EnumMousePointPosition.MouseSizeBottomRight: _control.Cursor = Cursors.SizeNWSE; //' 東南到西北 break;
          case EnumMousePointPosition.MouseSizeTopLeft: _control.Cursor = Cursors.SizeNWSE; //' 東南到西北 break;
          case EnumMousePointPosition.MouseSizeTopRight: _control.Cursor = Cursors.SizeNESW; //' 東北到南西 break;
          default: break; } }}
          /// /// 按鍵 WSAD (上下左右)/// /// /// private void MyKeyDown(object sender, KeyEventArgs e){ double left = Canvas.GetLeft(_control); double top = Canvas.GetTop(_control);
          switch (e.Key) { case Key.W:// 上 { SetControlLocation(_control, new Point(left, top-1)); break; } case Key.S:// 下 { SetControlLocation(_control, new Point(left, top+1)); break; } case Key.A:// 左 { SetControlLocation(_control, new Point(left-1, top)); break; } case Key.D:// 右 { SetControlLocation(_control, new Point(left+1, top)); break; } }}
          #endregion 按鈕拖動(dòng)
          #region 鼠標(biāo)位置
          /// /// 鼠標(biāo)指針位置枚舉;/// private enum EnumMousePointPosition{ /// /// /// MouseSizeNone = 0,
          /// /// 拉伸右邊框 /// MouseSizeRight = 1,
          /// /// 拉伸左邊框 /// MouseSizeLeft = 2,
          /// /// 拉伸下邊框 /// MouseSizeBottom = 3,
          /// /// 拉伸上邊框 /// MouseSizeTop = 4,
          /// /// 拉伸左上角 /// MouseSizeTopLeft = 5,
          /// /// 拉伸右上角 /// MouseSizeTopRight = 6,
          /// /// 拉伸左下角 /// MouseSizeBottomLeft = 7,
          /// /// 拉伸右下角 /// MouseSizeBottomRight = 8,
          /// /// 鼠標(biāo)拖動(dòng) /// MouseDrag = 9}
          /// /// 獲取鼠標(biāo)指針位置;/// /// /// /// private EnumMousePointPosition GetMousePointPosition(Control control, MouseEventArgs e){ Size size = control.RenderSize; Point point = e.GetPosition(control);
          Point pointCanvas = e.GetPosition(CanvasMain); _point.X = pointCanvas.X; _point.Y = pointCanvas.Y;
          if ((point.X >= -1 * Band) | (point.X <= size.Width) | (point.Y >= -1 * Band) | (point.Y <= size.Height)) { if (point.X < Band) { if (point.Y < Band) { return EnumMousePointPosition.MouseSizeTopLeft; } else { if (point.Y > -1 * Band + size.Height) { return EnumMousePointPosition.MouseSizeBottomLeft; } else { return EnumMousePointPosition.MouseSizeLeft; } } } else { if (point.X > -1 * Band + size.Width) { if (point.Y < Band) { return EnumMousePointPosition.MouseSizeTopRight; } else { if (point.Y > -1 * Band + size.Height) { return EnumMousePointPosition.MouseSizeBottomRight; } else { return EnumMousePointPosition.MouseSizeRight; } } } else { if (point.Y < Band) { return EnumMousePointPosition.MouseSizeTop; } else { if (point.Y > -1 * Band + size.Height) { return EnumMousePointPosition.MouseSizeBottom; } else { return EnumMousePointPosition.MouseDrag; } } } } } else { return EnumMousePointPosition.MouseSizeNone; }}
          #endregion 鼠標(biāo)位置
          #endregion 實(shí)現(xiàn)窗體內(nèi)的控件拖動(dòng)

          ?

          俗話說,Talk is cheap,show me the code。那么既然代碼已給出,大家就直接批評(píng)指正唄,我也沒什么說的了(主要是肚子餓了)。

          給個(gè)效果圖吧:

          ?

          動(dòng)圖:

          ?

          最后給出 Demo 地址:

          https://gitee.com/dlgcy/Practice/tree/master/WPFPractice?

          ?


          瀏覽 46
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚州sese | 无码免费观看 | 国产一级免费在线 | 亚洲超级高清无码第一在线视频观看 | 黄片网站进入口 |