2013-03-06 48 views
0

我使用Caliburn Micro創建WPF MVVM應用程序。我在菜單(Ribbon)中有一組按鈕,它們位於視圖中,是我的外殼視圖模型的視圖,它是一個ScreenConductor。基於當前活動的屏幕視圖模型,如果可用於活動屏幕並且在活動屏幕上調用動作或命令,我希望禁用/啓用功能區按鈕。從父菜單綁定子ViewModel命令的模式

這似乎是一種常見的情況。有沒有創建這種行爲的模式?

+0

綁定您的按鈕你的視圖模型內relaycommand,基於當前設置canexecute前場景。 – 2013-03-06 23:29:19

+0

那將造成的影響,但我希望的東西多了幾分動感,少蠻力。也許屏幕視圖模型可以定義哪些命令它支持,所以附加的屏幕可以不爲在ScreenConductor視圖模型的每個按鈕和屏幕顯式佈線被加入。 – grimus 2013-03-06 23:40:15

回答

0

爲您的shell視圖模型上的每個命令創建方法和伴隨的布爾屬性。 (請參閱下面的代碼示例。)Caliburn.Micro的約定會自動將它們連接到按鈕。然後,當您更改視圖以重新評估它們時,只需爲布爾屬性引發屬性已更改的事件。

例如,假設您有一個保存按鈕。 xaml中該按鈕的名稱將爲Save,並且在您的視圖模型中,您將有一個Save方法以及一個CanSave布爾屬性。請看下圖:

public void Save() 
{ 
    var viewModelWithSave = ActiveItem as ISave; 
    if (viewModelWithSave != null) viewModelWithSave.Save(); 
} 

public bool CanSave { get { return ActivateItem is ISave; } } 

然後,在你的指揮,只要你改變你的活動畫面,你會打電話NotifyOfPropertyChange(() => CanSave);。這樣做會導致您的按鈕被禁用或啓用,具體取決於活動屏幕是否能夠處理該命令。在這個例子中,如果活動屏幕沒有執行ISave,那麼保存按鈕將被禁用。

0

我會用Caliburn.Micro事件聚集在這種情況下,如下所示:

  • 有一堆布爾屬性(例如CanSaveCanLoad等)
  • 創建創建一個名爲ScreenCapabilities類帶式ScreenCapabilities
  • 的屬性命名ScreenActivatedMessage消息爲您的色帶表示贊同(句柄)的ScreenActivatedMessage
012視圖模型

在功能區視圖模型的Handle方法中,根據提供的ScreenCapabilities設置本地CanXXX屬性。

這將是這個樣子(手工輸入代碼,未測試):

public class ScreenCapabilities 
{ 
    public bool CanSave { get; set; } 
    // ... 
} 

public class ScreenActivatedMessage 
{ 
    public ScreenCapabilities ScreenCapabilities { get; set; } 
    // ... 
} 

public class RibbonViewModel : PropertyChangedBase, IHandle<ScreenActivatedMessage> 
{ 
    private bool _canSave; 
    public bool CanSave 
    { 
    get { return _canSave; } 
    set { _canSave = value; NotifyPropertyChanged(() => CanSave); } 
    } 

    // ... 

    public void Handle(ScreenActivatedMessage message) 
    { 
    CanSave = message.ScreenCapabilities.CanSave; 
    // ... 
    } 
} 

然後,適當的地方,當畫面切換,發佈消息。有關更多信息,請參見see Caliburn.Micro wiki

0

爲shell視圖模型中的活動屏幕定義屬性(假設ActiveScreen)。 讓我們假設你有每個按鈕的屬性,例如DeleteButton,AddButton。 屏幕是屏幕的視圖模型。

private Screen activeScreen; 

    public Screen ActiveScreen 
    { 
     get 
     { 
      return activeScreen; 
     } 
     set 
     { 
      activeScreen= value; 

      if (activeScreen.Name.equals("Screen1")) 
      { 
       this.AddButton.IsEnabled = true; 
       this.DeleteButton.IsEnabled = false; 
      } 
      if else (activeScreen.Name.equals("Screen2")) 
      { 
       this.AddButton.IsEnabled = true; 
       this.DeleteButton.IsEnabled = true; 
      } 

      NotifyPropertyChanged("ActiveScreen"); 
     } 
    } 
1

你爲什麼不這樣做相反的事情,而不是檢查當前活動的屏幕都支持哪些命令,讓活動的屏幕填充所有的控制菜單或功能區選項卡,它支持,(我會讓它注入自己的用戶控件,這可能只是一個完整的菜單或功能區選項卡),這也將增強用戶體驗,因爲它只會向用戶顯示他可以用於當前活動屏幕的控件。

1

編輯:只是你的問題看一次我在想,這是簡單得多比它看起來

我可以看到你遇到的唯一問題是缺乏一個處理程序(和保護)方法的子VM將意味着在當前活動的虛擬機上沒有實現的按鈕仍將被啓用。

爲CM的默認策略是試圖找到一個匹配的方法名(解析動作文本後),如果沒有找到一個,獨自離開的按鈕。如果要定製該行爲以便默認禁用按鈕,則只需在shell中執行命令按鈕即可輕鬆實現該功能,並確保將命令目標設置爲活動項目:

在shell定義按鈕,確保他們有一個指向活動子目標VM

<Button cal:Message.Attach="Command1" cal:Action.TargetWithoutContext="{Binding ActiveItem}" /> 

然後,只需實現你的子虛擬機的方法,按通常

public void Command1() { } 

和可選的CanXX後衛

public bool CanCommand1 
{ 
    get 
    { 
     if(someCondition) return false; 

     return true; 
    } 
} 

假設你沒有得到比這要複雜得多,它應該爲你工作

我將有一個快速瀏覽一下CM源,看看我能拿出的東西這適用於本

編輯:

好吧,你可以自定義ActionMessage.ApplyAvailabilityEffect FUNC得到你想要的效果 - 在你的bootstrapper.Configure()方法(或地方在啓動時)使用方法:

 ActionMessage.ApplyAvailabilityEffect = context => 
     { 
      var source = context.Source; 

      if (ConventionManager.HasBinding(source, UIElement.IsEnabledProperty)) 
      { 
       return source.IsEnabled; 
      } 

      if (context.CanExecute != null) 
      { 
       source.IsEnabled = context.CanExecute(); 
      } 
      // Added these 3 lines to get the effect you want 
      else if (context.Target == null) 
      { 
       source.IsEnabled = false; 
      } 
      // EDIT: Bugfix - need this to ensure the button is activated if it has a target but no guard 
      else 
      { 
       source.IsEnabled = true; 
      } 

      return source.IsEnabled; 
     }; 

這似乎爲我工作 - 有沒有目標,這可能不會被綁定到一個命令的方法,所以在這種情況下,我只設置IsEnabled爲false。這將激活按鈕只有在具有匹配簽名的方法是在活動子VM發現 - 顯然給它一個很好的測試,你使用它:)

+0

嗯認爲這是不完全正確的,我不必提供CanXX後衛它的工作 - 有再看看... – Charleh 2013-03-12 01:52:00

+0

好吧,我調整了,只是需要*當目標,以確保按鈕不*呆着被發現,但沒有CanXX警衛(相反,它假定你想要的按鈕沒有防範,但有一個處理程序被啓用) – Charleh 2013-03-12 01:54:47

相關問題