wpf控制元件設計時支援(3)
- wpf設計時除錯
- 編輯模型
- 裝飾器
1.wpf設計時除錯
為了更好的瞭解wpf設計時框架,那麼除錯則非常重要,通過以下配置可以除錯控制元件的設計時程式碼
(1)將啟動專案配置成外部的visual studio ide啟動程式devenv.exe
(2)F5啟動除錯然後會開啟一個新的visual studio ide,這個時候要記得重新開啟你要除錯的那個專案.
以上兩個步驟就可以實現設計時除錯了
2.編輯模型體系
當選中某些控制元件出現的設計時,這個選中的控制元件便成了可編輯的物件
this.Content = "Hello";
在設計環境下,也可以獲取到處在編輯狀態的控制元件,若採取上面的做法,雖可以變更控制元件的檢視,但卻未變更控制元件在xaml的更改.
設計環境下所有控制元件的更改都封裝在ModelItem類中.做法如下
//selectedContent's Type is ModelItem selectedContent.Properties["Content"].SetValue("Hello"); //selectedContent.Properties[ContentControl.ContentProperty].SetValue("Hello");
selectedContent型別是ModelItem,其中用Properties索引值獲取屬性,有兩種方式獲取屬性,字串和靜態項屬性
在上篇介紹過控制元件上下文選單的設計時做法,我們以此為基礎做個示例,以ContentControl為例,如下圖
共有4個操作,SetHello和SetRedForeground用於測試ModelItem變更控制元件檢視的功能,
第三個和第四個選單用於測試變更時事務的操作.(即要麼全過,要麼全不過)
以下為詳細程式碼
public class ContentMenuProvider : PrimarySelectionContextMenuProvider { //略去建構函式新增MenuAcion的程式碼
void ModelEditingScopeFailMenuAction_Execute(object sender, MenuActionEventArgs e) { ModelItem selectedContent = e.Selection.PrimarySelection; using (ModelEditingScope scope = selectedContent.BeginEdit("test")) { //selectedContent's Type is ModelItem selectedContent.Properties["Content"].SetValue("TextModelEditingScope"); //wrong selectedContent.Properties["Foreground"].SetValue("Red"); scope.Complete(); } } void ModelEditingScopeMenuAction_Execute(object sender, MenuActionEventArgs e) { ModelItem selectedContent = e.Selection.PrimarySelection; using (ModelEditingScope scope = selectedContent.BeginEdit("test")) { selectedContent.Properties["Content"].SetValue("TextModelEditingScope"); selectedContent.Properties["Foreground"].SetValue(Brushes.Green); scope.Complete(); } } void SetRedForegroundMenuAction_Execute(object sender, MenuActionEventArgs e) { ModelItem selectedContent = e.Selection.PrimarySelection; selectedContent.Properties["Foreground"].SetValue(Brushes.Red); selectedContent.Properties[Control.ForegroundProperty].SetValue(Brushes.Red); } void SetHelloMenuAction_Execute(object sender, MenuActionEventArgs e) { ModelItem selectedContent = e.Selection.PrimarySelection; //ContentControl element = selectedContent.View as ContentControl; //selectedContent.Content = "hello"; selectedContent.Properties["Content"].SetValue("Hello"); } }
這裡ModelItem通過MenuActionEventArgs傳遞進來.當需要事務支援時,則需要用到ModelEditingScope物件,通過ModelItem的BeginEdit方法,當全部變更完成時,則呼叫ModelEditingScope的Complete方法.
這裡可以知道ModelItem是設計器對控制元件做出所有的變更的一個封裝,也是wpf控制元件設計器的一個基礎.上面介紹通過Properties索引值變更檢視,具體ModelItem其他的功能可以參考msdn相關文件.
3.裝飾器
上圖是asp.net裡面GridView控制元件的一個設計檢視,右側的視覺化面板到了wpf控制元件的設計時就稱為裝飾器,那麼這個裝飾器其實就是wpf的控制元件,實現視覺化介面對於使用者而言非常重要,可以瞭解該控制元件的常用功能,也省卻了一些開發時間.不過目前wpf內建控制元件似乎沒一個控制元件是具有這一功能的,只能希望下版visual studio對wpf控制元件時做的更好了,可怕的是我們自己無法擴充套件內建控制元件的設計時,只能等著微軟來做,最可怕的是visual studio 2010把wpf設計時部分的api全變掉,那麼這裡就全白寫了.
裝飾器功能由AdornerProvider提供,我們從內建提供的PrimarySelectionAdornerProvider類派生一個裝飾器.
派生類需要重寫以上兩個方法,當選中該設計器相關控制元件時,會呼叫Activate方法,離開時呼叫Deactivate方法.為了介紹裝飾器的使用方法.示例將盡量簡單,以介紹裝飾器功能.
一般情況下,裝飾器需要一下幾個步驟
(1)定義一個AdornerPanel物件,並把控制元件相關裝飾器新增到AdornerPanel中,然後將這個裝飾器容器新增到AdornerProvider的Adorners屬性中,這項操作在Activate方法中完成.
protected override void Activate(ModelItem item, DependencyObject view) { Slider opacitySlider = new Slider(); opacitySlider.Background = Brushes.Red; AdornerPanel myPanel = new AdornerPanel(); myPanel.Children.Add(opacitySlider); Adorners.Add(myPanel); base.Activate(item, view); }
注意Activate方法也將ModelItem傳遞進來,就意味著通過裝飾器的方式也可以變更控制元件檢視
(2)定位裝飾器
再來看asp.net的GridView的設計時面板,其出現在控制元件的右側,wpf設計時裝飾器體系允許變更裝飾器位置,上面做的第一個步驟並無法在檢視上看到控制元件的裝飾器,那是因為裝飾器的定位問題.這個步驟必須完成.
這項工作由AdornerPlacementCollection物件來完成,再通過AdornerPanel的靜態方法SetPlacements來設定裝飾器的位置.
我們來看一下AdornerPlacementCollection的幾個方法,初看會比較暈,無法判斷幾個方法的區別
以上8個方法可以看做4個方法,都是與高度寬度有關的.下面以圖來說明,我們定義的控制元件裝飾器是一個Slider控制元件.目前只用於演示作用,它做不了什麼其他事情.
以上是原控制元件,裝飾器建立在此基礎之上,這裡說明一下上面8個方法的引數,都是一致的,第一個是倍數因子,第二個偏移量
(1)設定容器大小
為了演示,所以裝飾器控制元件以紅色背景標記,以下程式碼新增在Activate方法後面,SizeRelativeToContentWidth && Height方法設定裝飾器容器的大小,設定寬度和高度為控制元件內容高度和寬度的1倍
相應程式碼
AdornerPlacementCollection placement = new AdornerPlacementCollection(); placement.SizeRelativeToContentWidth(1, 0); placement.SizeRelativeToContentHeight(1, 0); AdornerPanel.SetPlacements(opacitySlider, placement);
(2)變更裝飾器位置(PositionRelativeToAdornerWidth方法),倍數引數為正數則向右移,負數則向左移
程式碼變更為
AdornerPlacementCollection placement = new AdornerPlacementCollection(); placement.SizeRelativeToContentWidth(1, 0); placement.SizeRelativeToContentHeight(1, 0); placement.PositionRelativeToAdornerWidth(1, 0); AdornerPanel.SetPlacements(opacitySlider, placement);
(3)DesiredWidth和DesiredHeight,注意在設計時,控制元件與容器之間也有著間距,如下紅圈
SizeRelativeToAdornerDesiredWidth方法用於調整裝飾器的DesiredWidth.看下圖黃色紅圈的位置變更,裝飾器向右側移動一個DesiredWidth,並寬度新增一個DesiredWidth.
程式碼變更為
AdornerPlacementCollection placement = new AdornerPlacementCollection(); placement.SizeRelativeToContentWidth(1, 0); placement.SizeRelativeToContentHeight(1, 0); placement.PositionRelativeToAdornerWidth(1, 0); placement.SizeRelativeToAdornerDesiredWidth(1, 0); AdornerPanel.SetPlacements(opacitySlider, placement);
注意PositionRelativeToAdornerWidth方法變更為PositionRelativeToContentWidth方法,那麼SizeRelativeToAdornerDesiredWidth方法只會使裝飾器寬度變更,而位置則不做變更.如下圖
程式碼變更為
AdornerPlacementCollection placement = new AdornerPlacementCollection(); placement.SizeRelativeToContentWidth(1, 0); placement.SizeRelativeToContentHeight(1, 0); //placement.PositionRelativeToAdornerWidth(1, 0); placement.PositionRelativeToContentWidth(1, 0); placement.SizeRelativeToAdornerDesiredWidth(5, 0); AdornerPanel.SetPlacements(opacitySlider, placement);
一邊情況下不設定容器高度,因為控制元件的高度是不確定的,所以現在調整如下
現在最終程式碼變更為
AdornerPlacementCollection placement = new AdornerPlacementCollection(); placement.SizeRelativeToContentWidth(1, 0); placement.PositionRelativeToAdornerWidth(1, 0); placement.SizeRelativeToAdornerDesiredHeight(1, 0); AdornerPanel.SetPlacements(opacitySlider, placement);
上面方法可以做多次嘗試,便於好的理解.
過年在家寫的,比較亂,沒有全部介紹完整.接著繼續寫.