以前總覺得動態布局是個很麻煩的問題,是個很需要功力的問題。但是貌似在.NET中,在WPF中卻不是那麼的麻煩。下面介紹我現在實現的一個動態布局的執行個體。
因為有需求,所以困難得克服!而我們的需求表名,不同的使用者需要的介面元素是不一樣的,我們總不能每次都去修改代碼吧!所以,需要完成動態布局。
這裡主要完成這樣一個功能:
1、動態畫線
2、動態new控制項
3、線和控制項都是可拖拽並隨意置放位置的
4、線和控制項是可刪除的
5、控制項是可綁定屬性和事件的
要完成這樣的功能,我們首先得定義三個滑鼠事件,即:左鍵down、move、up,右鍵刪除(不能只增加不刪除啊)。
例如我要畫一條線,那麼左鍵down的時候,我就需要記錄當前滑鼠的位置。左鍵down並且move的時候,要即時顯示畫出來的線。左鍵已經down並且左鍵up的時候記錄位置並且完成畫線。就是這樣一個過程我們就完成了動態畫一條線。
動態產生控制項就相對簡單了,有了線,有了控制項,連在一起,不就完成布局了嗎?當然是要把位置記錄下來的。
代碼上:
void Canvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //true表示當前是拖拽模式 if (currentPattern == "0") { //判斷是否選的是主表單 if (e.Source == mainCanvas) { } else { _isDown = true; _startPoint = e.GetPosition(mainCanvas); _originalElement = e.Source as UIElement; } } else if (currentPattern == "1") { _isDragging = true; Canvas board = sender as Canvas; _startPoint = e.GetPosition(board); insertShape = CreateShape(); insertShape.Opacity = opacity / 2; Canvas.SetLeft(insertShape, e.GetPosition(board).X); //插入線條的起點x1/y1 Canvas.SetTop(insertShape, e.GetPosition(board).Y); board.Children.Add(insertShape); board.RegisterName(insertShape.Name, insertShape); } } void Canvas_PreviewMouseMove(object sender, MouseEventArgs e) { //true表示當前是拖拽模式 if (currentPattern == "0") { if (_isDown) { //如果沒有拖拽或者超出了介面 if ((_isDragging == false) && ((Math.Abs(e.GetPosition(mainCanvas).X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance) || (Math.Abs(e.GetPosition(mainCanvas).Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance))) { _isDragging = true; _originalLeft = Canvas.GetLeft(_originalElement); //獲得原元素的位置 _originalTop = Canvas.GetTop(_originalElement); _overlayElement = new Rectangle() { Width = _originalElement.RenderSize.Width, Height = _originalElement.RenderSize.Height, Fill = new VisualBrush(_originalElement), Opacity = 0.8 //陰影的不透明性 }; Canvas.SetLeft(_overlayElement, _originalLeft); Canvas.SetTop(_overlayElement, _originalTop); mainCanvas.Children.Add(_overlayElement); } //如果正在移動中,顯示即時位置 if (_isDragging) { Point CurrentPosition = Mouse.GetPosition(mainCanvas); //設定浮動物件的位置 Canvas.SetLeft(_overlayElement, _originalLeft + CurrentPosition.X - _startPoint.X); Canvas.SetTop(_overlayElement, _originalTop + CurrentPosition.Y - _startPoint.Y); } } } else if (currentPattern == "1") { Canvas board = sender as Canvas; if (_isDragging && insertShape != null) { if (insertShape is Line) { (insertShape as Line).X1 = 0; (insertShape as Line).X2 = e.GetPosition(board).X - _startPoint.X; //設定線條的X1/Y1/X2/Y2 (insertShape as Line).Y1 = 0; (insertShape as Line).Y2 = e.GetPosition(board).Y - _startPoint.Y; } } } } void Canvas_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { //true表示當前是拖拽模式 if (currentPattern == "0") { if (_isDown) { if (_isDragging) { //將陰影位置設定為當前 Canvas.SetLeft(_originalElement, Canvas.GetLeft(_overlayElement)); Canvas.SetTop(_originalElement, Canvas.GetTop(_overlayElement)); Point _positionInOverlayElement = Mouse.GetPosition(_overlayElement); mainCanvas.Children.Remove(_overlayElement); _overlayElement = null; } //將移動標識設定為 false _isDragging = false; _isDown = false; } } else if (currentPattern == "1") { //如果是畫線模式,則將拖拽設定為false,將透明度還原 _isDragging = false; if (insertShape != null) insertShape.Opacity = opacity; } }
有了這三個主要的事件,你就可以很輕鬆的完成動態布局了。如何儲存的呢?我是把各個控制項的位置放在了資料庫中,載入的時候將位置資訊讀出來。
private void btnSave_Click(object sender, RoutedEventArgs e) { //遍曆所有的介面控制項,拿到他們的位置資訊,儲存。 List<A> listAConfig = new List<A>(); //獲得介面上所有的Line元素 List<Line> listLine = GetElementFormUI.GetChildObjects<Line>(mainCanvas); for (int i = 0; i < listLine.Count; i++) { Line l = listLine[i] ; A enAConfig = new A(); enAConfig .S_ID = DateTime.Now.ToFileTime().ToString(); enAConfig .S_NAME = l.Name; enAConfig .S_SHAPETYPE = "Line"; enAConfig .I_LEFT =decimal.Parse(Canvas.GetLeft(l as UIElement).ToString()); enAConfig .I_TOP = decimal.Parse(Canvas.GetTop(l as UIElement).ToString()); enAConfig .I_X2 = decimal.Parse(l.X2.ToString()); enAConfig .I_Y2 = decimal.Parse(l.Y2.ToString()); listAConfig.Add(enAConfig ); } //判斷是否儲存成功 if (ServiceFactory.GetAConifgService().AddAConfig(listAConfig)) { MessageBox.Show("儲存成功!", "恭喜!", MessageBoxButton.OK); } else { MessageBox.Show("儲存失敗!", "警告!", MessageBoxButton.OK); } }
至此,我們完成了動態布局的設定和儲存,嘗試一下吧!