1. 程式人生 > >wpf控制元件設計時支援(3)

wpf控制元件設計時支援(3)

原文: wpf控制元件設計時支援(3)

 

 

  1. wpf設計時除錯
  2. 編輯模型
  3. 裝飾器

1.wpf設計時除錯

 

為了更好的瞭解wpf設計時框架,那麼除錯則非常重要,通過以下配置可以除錯控制元件的設計時程式碼

(1)將啟動專案配置成外部的visual studio ide啟動程式devenv.exe

image

(2)F5啟動除錯然後會開啟一個新的visual studio ide,這個時候要記得重新開啟你要除錯的那個專案.

以上兩個步驟就可以實現設計時除錯了

2.編輯模型體系

 

當選中某些控制元件出現的設計時,這個選中的控制元件便成了可編輯的物件

. 設計環境會傳回一個ModelItem的類,這個類可以幫助你更改控制元件檢視,用於互動.這裡的做法與直接更改wpf控制元件有些不同,如直接改變wpf一個控制元件的一個屬性

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為例,如下圖

image

 

 

共有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.裝飾器

 

image

上圖是asp.net裡面GridView控制元件的一個設計檢視,右側的視覺化面板到了wpf控制元件的設計時就稱為裝飾器,那麼這個裝飾器其實就是wpf的控制元件,實現視覺化介面對於使用者而言非常重要,可以瞭解該控制元件的常用功能,也省卻了一些開發時間.不過目前wpf內建控制元件似乎沒一個控制元件是具有這一功能的,只能希望下版visual studio對wpf控制元件時做的更好了,可怕的是我們自己無法擴充套件內建控制元件的設計時,只能等著微軟來做,最可怕的是visual studio 2010把wpf設計時部分的api全變掉,那麼這裡就全白寫了.

裝飾器功能由AdornerProvider提供,我們從內建提供的PrimarySelectionAdornerProvider類派生一個裝飾器.

image

派生類需要重寫以上兩個方法,當選中該設計器相關控制元件時,會呼叫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的幾個方法,初看會比較暈,無法判斷幾個方法的區別

image

以上8個方法可以看做4個方法,都是與高度寬度有關的.下面以圖來說明,我們定義的控制元件裝飾器是一個Slider控制元件.目前只用於演示作用,它做不了什麼其他事情.

image

以上是原控制元件,裝飾器建立在此基礎之上,這裡說明一下上面8個方法的引數,都是一致的,第一個是倍數因子,第二個偏移量

(1)設定容器大小

為了演示,所以裝飾器控制元件以紅色背景標記,以下程式碼新增在Activate方法後面,SizeRelativeToContentWidth && Height方法設定裝飾器容器的大小,設定寬度和高度為控制元件內容高度和寬度的1倍

image

相應程式碼

AdornerPlacementCollection placement = new AdornerPlacementCollection();
placement.SizeRelativeToContentWidth(1, 0);
placement.SizeRelativeToContentHeight(1, 0);

AdornerPanel.SetPlacements(opacitySlider, placement);


(2)變更裝飾器位置(PositionRelativeToAdornerWidth方法),倍數引數為正數則向右移,負數則向左移

image

程式碼變更為

AdornerPlacementCollection placement = new AdornerPlacementCollection();
placement.SizeRelativeToContentWidth(1, 0);
placement.SizeRelativeToContentHeight(1, 0);
placement.PositionRelativeToAdornerWidth(1, 0);
AdornerPanel.SetPlacements(opacitySlider, placement);

 

(3)DesiredWidth和DesiredHeight,注意在設計時,控制元件與容器之間也有著間距,如下紅圈

   image

SizeRelativeToAdornerDesiredWidth方法用於調整裝飾器的DesiredWidth.看下圖黃色紅圈的位置變更,裝飾器向右側移動一個DesiredWidth,並寬度新增一個DesiredWidth.

image

程式碼變更為

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方法只會使裝飾器寬度變更,而位置則不做變更.如下圖

image

程式碼變更為

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);


一邊情況下不設定容器高度,因為控制元件的高度是不確定的,所以現在調整如下

image

 

現在最終程式碼變更為

AdornerPlacementCollection placement = new AdornerPlacementCollection();
placement.SizeRelativeToContentWidth(1, 0);
placement.PositionRelativeToAdornerWidth(1, 0);
placement.SizeRelativeToAdornerDesiredHeight(1, 0);
AdornerPanel.SetPlacements(opacitySlider, placement);


上面方法可以做多次嘗試,便於好的理解.

 

demo下載

過年在家寫的,比較亂,沒有全部介紹完整.接著繼續寫.