2013-10-03 86 views
0

我有一個案例,有點複雜,但我試圖說明和做一些修改,以簡單的方式顯示點。WPF MVVM案例:ItemsControl包含超鏈接和命令來更新ViewModel屬性

比方說,我有一個Window1作爲視圖,Window1ViewModel作爲它的視圖模型。我也有一個SubMenuViewModel類來表示窗口中的子菜單。我想在Window1中製作一個包含許多子菜單的ItemsControl。每次用戶單擊其中一個子菜單時,CurrentSubMenu屬性都會更新到相應的子菜單。這是問題所在,我無法設法更新Window1ViewModel中的CurrentSubMenu。

SubMenuViewModel:

public class SubMenuViewModel : INPC 
    { 
     private string _submenuname; 
     public string SubMenuName 
     { 
      get 
      { return _submenuname; } 
      set 
      { 
       _submenuname = value; 
       RaisePropertyChanged("SubMenuName"); 
      } 
     } 
     private string _displayname; 
     public string DisplayName 
     { 
      get 
      { return _displayname; } 
      set 
      { 
       _displayname = value; 
       RaisePropertyChanged("DisplayName"); 
      } 
     } 

     // Command for Hyperlink in ItemsControl // 
     private RelayCommand _commandSubmenu; 
     public RelayCommand CommandSubMenu 
     { 
      get 
      { return _commandSubmenu; } 
      set 
      { 
       _commandSubmenu = value; 
       RaisePropertyChanged("CommandSubMenu"); 
      } 
     } 
     // end of command 

     public SubMenuViewModel(string Submenu_name, string Display_name) 
     { 
      _submenuname = Submenu_name; 
      _displayname = Display_name; 
     } 
    } 

窗口1:

<Window x:Class="SomeProject.Window1" 
     xmlns:vm="clr-namespace:SomeProject.ViewModel" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="This is Some Project" WindowState="Maximized"> 
    <Window.DataContext> 
     <vm:Window1ViewModel/> 
    </Window.DataContext> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="250" /> 
      <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 

     <Border Name="SubMenuPanelBorder" 
       Grid.Column="0" 
       Grid.Row="1" 
       HorizontalAlignment="Stretch" 
       VerticalAlignment="Stretch" 
       Margin="15 0 15 0" 
       BorderThickness="2" 
       BorderBrush="Black" 
       Padding="10 10"> 

      <HeaderedContentControl Content="{Binding Path=SubMenus}" Header="Panel Submenu :"> 
       <HeaderedContentControl.ContentTemplate> 
        <DataTemplate> 
         <ItemsControl ItemsSource="{Binding}" Foreground="White" Background="Transparent" Margin="0 15"> 
          <ItemsControl.ItemTemplate> 
           <DataTemplate> 
            <TextBlock> 
             <Hyperlink Command="{Binding Path=CommandSubMenu}"> 
              <TextBlock Margin="0 5" Text="{Binding Path=DisplayName}"/> 
             </Hyperlink> 
            </TextBlock> 
           </DataTemplate> 
          </ItemsControl.ItemTemplate> 
         </ItemsControl> 
        </DataTemplate> 
       </HeaderedContentControl.ContentTemplate> 
      </HeaderedContentControl> 

     </Border> 

     ....... 
     ....... 

    </Grid> 
</Window> 

Window1ViewModel:

class Window1ViewModel : INPC 
    { 
     private List<SubMenuViewModel> _submenus; 
     public List<SubMenuViewModel> SubMenus 
     { 
      get 
      { return _submenus; } 
      set 
      { 
       _submenus = value; 
       RaisePropertyChanged("SubMenus"); 
      } 
     } 
     private SubMenuViewModel _currentSubMenu; 
     public SubMenuViewModel CurrentSubMenu 
     { 
      get 
      { return _currentSubMenu; } 
      set 
      { 
       _currentSubMenu = value; 
       RaisePropertyChanged("CurrentSubMenu"); 
      } 
     } 

     public Window1ViewModel() 
     { 
      SubMenus = MenuDefinition.GetSubMenus(); 

      /*** 
      Set the SubMenus's command to update the CurrentSubMenu, 
      and == HERE IS WHERE I GOT LOST ==. 
      The CurrentSubMenu is always point to the last submenu in the loop when clicked. 

      By the way, the reason I use loop is because the submenu in the Menu definition sometimes changed and there are many number of submenus there, and there are some other reasons (I use Menu-submenu mechanism, but it's not essential to show it here because it's not the main point I want to show). So, finally I use loop instead of specifying each command one by one. 
      ***/ 

      foreach(SubMenuViewModel submenu in SubMenus){ 
       submenu.CommandSubMenu=new RelayCommand(()=>clickedSubMenu(submenu.SubMenuName)); 
      } 
     } 

     public void clickedSubMenu(string submenu_name) 
     { 
      CurrentSubMenu = SubMenus.Find(sub => sub.SubMenuName == submenu_name); 
     } 
    } 

MenuDefinition:

public static List<SubMenuViewModel> GetSubMenus() 
     { 
      return new List<SubMenuViewModel> 
        { 
         new SubMenuViewModel("overview_product", "Overview Products"), 
         new SubMenuViewModel("search_product","Search Products"), 
         new SubMenuViewModel("update_product","Update Data Products"), 
         new SubMenuViewModel("order_product","Order Products"), 
         new SubMenuViewModel("supplier_product","Products Supplier"), 
         ................. 
         ................. 
         ................. 
        };       
      } 
     } 

回答

0

的解決方案是簡單的事情,但不知何故,它需要一點點的時間,我發現這一點。在傳遞給RelayCommand的委託操作之前,我必須添加一個臨時變量。有了這種方式,RelayCommand的委託「Action的execute」將採取正確的參數,並指向正確的子菜單。當然並不總是最後一個子菜單。

早在Window1ViewModel

這樣的,而不是直接使用submenu.SubMenuName財產這樣

// This way, when clicked, the command will always point to the last submenu from the loop 
public Window1ViewModel() 
     { 
      SubMenus = MenuDefinition.GetSubMenus(); 

      foreach(SubMenuViewModel submenu in SubMenus){ 
       submenu.CommandSubMenu=new RelayCommand(()=>clickedSubMenu(submenu.SubMenuName)); 
      } 
     } 

我們必須添加一些臨時變量這樣。

// This way, when clicked, the command will point to the correct submenu 
public Window1ViewModel() 
     { 
      SubMenus = MenuDefinition.GetSubMenus(); 

      foreach(SubMenuViewModel submenu in SubMenus){ 
       string Temp=submenu.SubMenuName 
       submenu.CommandSubMenu=new RelayCommand(()=>clickedSubMenu(Temp)); 
      } 
     } 

而且輸出會有所不同。

0

我相信你的綁定屬性應該這樣寫。

private string _Terminal; 
    public string Terminal 
    { 
     get 
     { 
      return _Terminal; 
     } 
     set 
     { 
      _Terminal = value; 
      OnPropertyChanged("Terminal"); 
     } 
    } 

確保視圖模型執行INotifyPropertyChanged

public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable 
{ 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     PropertyChangedEventHandler propertyChanged = this.PropertyChanged; 
     if (propertyChanged != null) 
     { 
      PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName); 
      propertyChanged(this, e); 
     } 
    } 
+0

什麼是終端?你的意思是ViewModel中的CurrentSubMenu? –

+0

是啊,我只是堅持從一些代碼,我有 –

+0

一個例子,我已經在視圖模型每二傳手加入RaisePropertyChange(),但仍然是相同的。 –