2011-08-18 57 views
3

我有一個父控件(主窗體)和一個子控件(用戶控件)。子控件有一些代碼,它決定了應用程序可以執行哪些功能(例如保存文件,寫入日誌等)。我需要顯示/隱藏,根據功能啓用/禁用主窗體的主菜單項。因爲我不能寫MainMenu.MenuItem1.Visible = false;(主菜單在子控件中不可見),所以我在子控件中觸發一個事件並在主窗體上處理這個事件。問題是我需要傳遞哪些菜單元素需要顯示/隱藏。要做到這一點,我創建了一個枚舉,展示了與從子控件訪問父控件元素的最佳方式是什麼?

public enum ItemMode 
{ 
    TRUE, FALSE, NONE 
} 

然後我創造了我的EventArgs具有ItemMode類型的6個參數的項目做(有我需要管理6菜單項)。所以,任何時候,我需要顯示的第一個項目,隱藏第二,什麼也不做,其餘的我必須寫這樣的事情

e = new ItemModeEventArgs(ItemMode.TRUE, ItemMode.FALSE, ItemMode.NONE, ItemMode.NONE, ItemMode.NONE, ItemMode.NONE); 
FireMyEvent(e); 

這似乎是太多的代碼給我,更重要的是,如果我需要什麼今後要管理10個項目?然後,我將不得不重寫所有構造函數,以添加4個NONE。

我相信有這樣做的更好的辦法,但我只是無法弄清楚它是什麼。

+1

+1對於一個有趣的問題,用代碼給出足夠的細節來了解當前的處理方式 – shelleybutterfly

回答

2

您可以創建一個EventArgs這需要一個ItemMode[]List<ItemMode>或這些項目(而不是現在的6個參數)一個Dictionary<string, ItemMode> - 這樣增加更多的物品,當你不需要太大的變化...

+0

'Dictionary'看起來很有前途,我想我會試試看。然而,我想,「List」並不適合我,因爲我需要知道顯示/隱藏哪個項目,並且如果存在List中的一個項目我怎麼知道它是用於哪個元素的。 –

+0

這就是爲什麼我在答案中包含'Dictionary' ...你甚至可以使用'Dictionary '直接引用相應的控件... – Yahia

1

鏈式child-> parent可以顛倒過來。在這種情況下,請求將從mainform傳遞給它的子控件。

控制參與的命令處理必須實現一個特殊的接口:

interface ICommandHandler 
    { 
     bool CanInvoke(int commandId); 
     void InvokeCommand(int commandId); 
     bool UpdateCommand(int commandId, MenuItem item); 
    } 

這種方法的優點是隻主動控制必須經過,不是所有的孩子們。 弱點 - UpdateCommand()方法,可以從Application.Idle事件或計時器中調用。

希望這有助於

+0

+1另一個好的模式是熟悉。總的來說,我想避免輪詢使用,但還有其他方法。例如,爲主窗體提供了另一個接口,比如'interface IUpdatableCommandForm',它具有類似'void RegisterHandler(ICommandHandler處理程序,bool enable)'的特性,以允許孩子將其可用性推送給父級。或者在另一個方向上,像'void RegisterReadyCallback(Action callback)一樣,在'ICommandHandler'上使用回調註冊方法;'孩子可以用來通知父母它的身份以及它是否處於活動狀態。 :) – shelleybutterfly

0

好了,我不能爲「最好」的方式說話,除非除非在特殊情況下,因爲經常有一些同樣好的方式。然而,我的第一個想法是創建一個父類指定其MainMenu引用的屬性的類,該類具有啓用/禁用單個菜單或項目的功能。在非常簡單的情況下,這可能是因爲通過字符串列表像"OptionsScreen=enabled"等一樣簡單,然後裏面的類手工處理的情況下,更多的東西一般喜歡通過.Name傳遞字符串,如"mnuToolsOptions=enabled",然後找到菜單項屬性。因此,在啓動時,創建菜單處理程序類的實例,然後執行類似MenuHandlerHelper.MenuToHandle = MainMenuStrip;的操作。

在孩子身邊,也許你可以有你的類,更新MainMenu衍生UserObjects,從常見的一種派生所創建具有public MyMainMenuHandlerHelper MenuHandlerHelper屬性,並設置在父窗體的構造函數,以便子控件可以打電話菜單更新功能。或者,您可以參加一個包含所有規則的List<string>事件,然後按照您現在的操作進行操作。

這是一個非常簡單的想法,並沒有處理可能的衝突事件,所以你可能要麼拋出異常(最簡單)。您可能還想要規則優先級(簡單),或嘗試鏈接功能(可能很難確定訂單等)。

如果你能限制我的問題(想要的碰撞處理等),我會很樂意實現我的想法的一些例子,而且我真的想看看一些基本代碼是什麼樣子,並嘗試或許測試一些想法,所以如果這些想法出現的話,我也會在這裏發佈代碼。

0

如果您想處理來自用戶控件的所有更改:您可以繼承自己的用戶控件類,並添加對希望能夠修改的菜單條目的表單/集合的引用。您可以將此引用傳遞給其構造函數,然後您將能夠輕鬆修改您的用戶控件中的菜單

另一方面,如果您希望在表單中以事件爲基礎進行管理,你可以實現自己的EventArgs類,但我會做這樣的:


class ItemModeEventArgs 
{ 
    MenuItemClass target; 
    EnumType change; 
} 

所以基本上一個單獨的事件上升每個菜單項。每個事件參數都知道項目菜單正在改變以及如何改變。 Ofc,如果你只有兩個菜單項的狀態,那麼'change'字段就沒用了。 這樣,您不必使用n個參數對函數進行硬編碼,其中n是菜單項的數量。

0

真的有很多方法可以做到。最簡單的方法,雖然有些人會喊「不好的做法」,但只要在創建控件時傳遞一個指向主菜單的指針即可。你的控制將有一些像這樣的代碼:

MenuStrip MainMenu; 

internal void SetMainMenu(MenuStrip mainMenu) 
{ 
    MainMenu = mainMenu; 
} 

,當你創建控件:

void CreateControl() 
{ 
    MyUserControlType MyControl = new MyUserControlType(); 
    MyControl.SetMainMenu(mainMenuStrip); //or whatever you called your main menu 
} 

這會給你的孩子形式不限訪問MainForm的菜單(這就是爲什麼它在技術上是一個壞的實踐)。從孩子形成可以按名稱訪問子菜單,例如:

if (MainMenu != null) 
{ 
    ToolStripMenuItem fileMenu = 
     (ToolStripMenuItem)MainMenu.Items["fileToolStripMenuItem"]; 
    fileMenu.DropDownItems["exportFileToolStripItem"].Visible = false; 
} 

如果你創建了設計師的控制,那麼你可以添加SetMainMenu呼叫進入。設計文件,或在窗體的負載添加它事件。

相關問題