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

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

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

這篇介紹在wpf設計時集合項屬性新增項的定義和自定義控制元件右鍵選單的方法

集合項屬性設計時支援

 

1.為集合屬性設計器識別具體項型別

wpf設計器允許定義集合項的型別,如新發布的WPF的DataGrid控制元件,其中的Columns包括一下幾種型別,Columns集合屬性是以下幾個型別的抽象類集合.要在設計器識別以下型別,就必須用到wpf設計時的擴充套件功能

image

 

實現這個功能很簡單,只需要給該集合屬性附上NewItemTypesAttribute元資料就好了.如下程式碼

NewItemTypesAttribute attr = new 
NewItemTypesAttribute( typeof(DataGridTextColumn), typeof(DataGridCheckBoxColumn), typeof(DataGridHyperlinkColumn), typeof(DataGridComboBoxColumn), typeof
(DataGridTemplateColumn)); builder.AddCustomAttributes("Columns", attr);

這裡通過把元資料新增到元資料儲存區的方式來實現,當然你也可以直接在屬性上掛元資料,兩種方法都可以,具體可以看第一篇的介紹.

2.格式化集合項屬性

如上圖,每個型別都配有不同的圖示,這一功能需要NewItemFactory 來完成,稱之為建立項的工廠,我理解為是格式化項.

image

NewItemFactory是一個抽象類,有三個虛方法

CreateInstance方法會在建立新例項時對該物件做一些業務邏輯的變更

GetDisplayName方法則獲取顯示的名稱,如下圖的DataGridTextColumn

GetImage方法則是獲取顯示的物件圖示了,如下圖左側圖示.

image

可以根據需要重寫這三個方法.我們來看下DataGridColumnFactory是如何實現的.

internal class DataGridColumnFactory : NewItemFactory 
{
    public override object CreateInstance(Type type) 
    {
        DataGridColumn gridColumn = null;

        if (type.IsAssignableFrom(typeof(DataGridTemplateColumn)))
        { 
            gridColumn = CreateTemplateColumn();
        } 
        else 
        {
            gridColumn = Activator.CreateInstance(type) as DataGridColumn;
        }

        if (gridColumn != null) 
        {
            gridColumn.Header = "Header";
        }

        return gridColumn;
    }

    /// <summary>
    ///     Create a Template column with a default cell and editing template 
    /// </summary>
    private static DataGridTemplateColumn CreateTemplateColumn() 
    {
        DataGridTemplateColumn gridColumn = new DataGridTemplateColumn();
        gridColumn.CellTemplate = new DataTemplate();
        gridColumn.CellEditingTemplate = new DataTemplate();

        return gridColumn;
    }

    public override object GetImage(Type type, Size desiredSize) 
    {
        object image = base.GetImage(type, desiredSize);
        if (typeof(DataGridTextColumn).IsAssignableFrom(type)) 
        { 
            image = Util.GetImage("DataGridTextColumn.png", desiredSize);
        } 
        else if (typeof(DataGridHyperlinkColumn).IsAssignableFrom(type)) 
        {
            image = Util.GetImage("DataGridHyperlinkColumn.png", desiredSize);
        } 
        else if (typeof(DataGridComboBoxColumn).IsAssignableFrom(type)) 
        {
            image = Util.GetImage("DataGridComboBoxColumn.png", desiredSize);
        } 
        else if (typeof(DataGridCheckBoxColumn).IsAssignableFrom(type)) 
        {
            image = Util.GetImage("DataGridCheckBoxColumn.png", desiredSize);
        } 
        else if (typeof(DataGridTemplateColumn).IsAssignableFrom(type)) 
        {
            image = Util.GetImage("DataGridTemplateColumn.png", desiredSize);
        }

        return image;
    }
}

以上程式碼應該很容易理解.定義好這個工廠類以後則需要用NewItemTypesAttribute中的FactoryType屬性指定這個型別.現在剛開始的程式碼變更如下

NewItemTypesAttribute attr = new NewItemTypesAttribute(
                                    typeof(DataGridTextColumn),
                                    typeof(DataGridCheckBoxColumn),
                                    typeof(DataGridHyperlinkColumn),
                                    typeof(DataGridComboBoxColumn),
                                    typeof(DataGridTemplateColumn));
attr.FactoryType = typeof(DataGridColumnFactory);
builder.AddCustomAttributes("Columns", attr);

上下文選單項

 

在我們使用wpf的datagird時候,在選中DataGrid控制元件時,點選右鍵的話,會有一個自定義的DataGrid選單,如下圖

image

 

wpf設計器允許對控制元件提供自定義選單項,這是通過繼承一個名為PrimarySelectionContextMenuProvider的類實現的,上圖的右鍵選單由DataGridMenuProvider來實現,我們來看一下具體實現方法.如下

1.宣告一個MenuGroup類,表明一個選單項組,一個選單則是一個MenuAction類.

通過MenuGroup的Items集合新增MenuAction.

2.更新選單項狀態UpdateItemStatus ,該事件會都目前的選單進行判斷,做出狀態變更,如初始化並未顯示Remove Columns這個選單.

 

public DataGridMenuProvider()
{
    // Set up the MenuGroup which holds the MenuAction items.
    MenuGroup dataOperationsGroup = new MenuGroup("DataGroup", "DataGrid");

    isDatasourceSetMenuAction = new MenuAction("You need to set ItemsSource to enable some column operations.");

    generateStockColumnsMenuAction = new MenuAction("Generate Columns");
    generateStockColumnsMenuAction.Execute += new EventHandler<MenuActionEventArgs>(GenerateStockColumnsMenuAction_Execute);

    addColumnsMenuAction = new MenuAction("Add/Edit Columns...");
    addColumnsMenuAction.Execute += new EventHandler<MenuActionEventArgs>(AddColumnsMenuAction_Execute);

    removeColumnsMenuAction = new MenuAction("Remove Columns");
    removeColumnsMenuAction.Execute += new EventHandler<MenuActionEventArgs>(RemoveColumnsMenuAction_Execute);

    dataOperationsGroup.HasDropDown = true;
    dataOperationsGroup.Items.Add(isDatasourceSetMenuAction);
    dataOperationsGroup.Items.Add(generateStockColumnsMenuAction);
    dataOperationsGroup.Items.Add(addColumnsMenuAction);
    dataOperationsGroup.Items.Add(removeColumnsMenuAction);

    this.Items.Add(dataOperationsGroup);        // Can have groups - show up as sub menus
    
    // The UpdateItemStatus event is raised immediately before 
    // the menu show, which provides the opportunity to set states.
    UpdateItemStatus += new EventHandler<MenuActionEventArgs>(DataGridMenuProvider_UpdateItemStatus);
}

 

MenuAction可以通過Execute事件觸發點選事件.這就可以使得執行時控制元件與設計器之間進行互動,這裡涉及到一個wpf設計時的編輯模型放到下篇細講.這篇就介紹集合項屬性和自定義控制元件右鍵選單的方法.下篇將會整理一個原始碼一起放上.