1

我有一个案例,稍微复杂一点,但我尝试说明并进行一些修改,以简单的方式说明这一点。

假设我有一个 Window1 作为视图,一个 Window1ViewModel 作为它的视图模型。我还有一个 SubMenuViewModel 类来表示窗口中的子菜单。我想在 Window1 中创建一个 ItemsControl,其中包含许多子菜单。每次用户单击其中一个子菜单时,CurrentSubMenu 属性都会更新为相应的子菜单。这就是问题所在,我无法更新Window1ViewModel中的 CurrentSubMenu 。

.

子菜单视图模型:

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

菜单定义:

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"),
                        .................
                        .................
                        .................
                    };                        
            }
        }
4

2 回答 2

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

并且输出会有所不同。

于 2013-10-03T11:52:27.383 回答
0

我相信你的绑定属性应该这样写。

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

确保 viewmodel 实现 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);
        }
    }
于 2013-10-03T00:25:44.220 回答