使用UserControls进行导航

时间:2016-01-14 02:10:49

标签: c# wpf user-controls

我有一个CateringMenuView,我通过点击一个菜单在UserControls之间导航,它工作正常。

我使用以下模式:

https://rachel53461.wordpress.com/2011/05/08/simplemvvmexample/

在其中一个usercontrol(NewRegularOrderView)中有一个按钮。通过单击此按钮,我想导航到另一个usercontrol。为了做到这一点,我使用了我在这里的答案:

Navigate between UserControls with Event Aggegator

但是当我点击按钮时没有任何反应。

你能帮忙找到原因吗?

CateringMenuView

  <UserControl.Resources>
        <DataTemplate DataType="{x:Type cvm:NewDeliveryComOrderViewModel}">
            <cv:NewDeliveryComOrderView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type cvm:NewRegularOrderViewModel}">
            <cv:NewRegularOrderView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type cvm:FillOrderViewModel}">
           <cv:FillOrderView/>
        </DataTemplate>
        <cvm:CateringMenuViewModel x:Key="menu"/>
    </UserControl.Resources>

    <Grid DataContext="{Binding Source={StaticResource menu}}">
        <StackPanel>
           <Menu>
              <MenuItem Header="New Order">
                 <ItemsControl ItemsSource="{Binding PageViewModels}" >
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                           <TextBlock>
                              <Hyperlink Command="{Binding ChangePageCommand, Mode=OneWay, Source={StaticResource menu}}" CommandParameter="{Binding}" TextDecorations="{x:Null}">
                                 <InlineUIContainer>
                                    <TextBlock Text="{Binding Name}"/>
                                 </InlineUIContainer>
                              </Hyperlink>
                            </TextBlock>
                          </DataTemplate>
                       </ItemsControl.ItemTemplate>
                   </ItemsControl>
                 </MenuItem>
              </Menu>
         </StackPanel>


        <Border Grid.Row="1" BorderThickness="1" CornerRadius="8" >
            <ContentControl Content="{Binding CurrentUserControl}" Margin="0,0,-1,0"/>
        </Border>
    </Grid>

CateringMenuViewModel

public class MainViewModel : ViewModelBase
{
        public MainViewModel()
        {
            PageViewModels.Add(new NewRegularOrderViewModel());
            PageViewModels.Add(new NewDeliveryComOrderViewModel());
            PageViewModels.Add(new FillOrderViewModel());

            // Set starting page
            CurrentUserControl = PageViewModels[0];
        }

        #region Fields

        private List<IUserContentViewModel> _pageViewModels;
        public List<IUserContentViewModel> PageViewModels
        {
            get
            {
                if (_pageViewModels == null)
                    _pageViewModels = new List<IUserContentViewModel>();

                return _pageViewModels;
            }
        }

        private IUserContentViewModel _currentUserControl;
        public IUserContentViewModel CurrentUserControl
        {
            get { return _currentUserControl; }
            set
            {
                if (value != _currentUserControl)
                {
                    _currentUserControl = value;
                    OnPropertyChanged("CurrentUserControl");
                }
            }
        }

        #region Methods

        private void ChangeViewModel(IUserContentViewModel viewModel)
        {
            if (!PageViewModels.Contains(viewModel))
                PageViewModels.Add(viewModel);

            CurrentUserControl = PageViewModels
                .FirstOrDefault(vm => vm == viewModel);


        }

        #endregion

        private ICommand _changePageCommand;
        #endregion
        public ICommand ChangePageCommand
        {
            get
            {
                if (_changePageCommand == null)
                {
                    _changePageCommand = new RelayCommand(
                        p => ChangeViewModel((IUserContentViewModel)p),
                        p => p is IUserContentViewModel);
                }

                return _changePageCommand;
            }
        }
    }

现在,当我在NewRegularOrderView上时,我想点击一个按钮导航到FillOrderView。

在ChangeViewModel(IUserContentViewModel viewModel)中改变了视图 但它没有在RelayCommand中执行

NewRegularOrderView

<UserControl.Resources>
  <cvm:CateringMenuViewModel x:Key="menu"/>
</UserControl.Resources>

<Border Grid.Row="2" Margin="10, 5" BorderBrush="Black" CornerRadius="8" BorderThickness="2">
            <Button DataContext="{Binding Source={StaticResource menu}}"
                    Command="{Binding ChangePageCommand}" 
                    CommandParameter ="{Binding PageViewModels[2]}"/>
</Border>

FillOrderView和ViewModel

public class FillOrderViewModel : ViewModelBase, IUserContentViewModel
    {
        public FillOrderViewModel() {}

        public string Name
        {
            get
            {
                return "Fill Order";
            }
        }
    }

<UserControl.Resources>
        <cvm:FillOrderViewModel x:Key="fill"/>
    </UserControl.Resources>
    <Grid DataContext="{Binding Source={StaticResource fill}}">
        <DataGrid Margin="405,100,395,110" >

        </DataGrid>

    </Grid>

更新

轻松回答here

2 个答案:

答案 0 :(得分:2)

Kirenenko's answer您有两个独立的CateringMenuViewModel

实例是正确的

键入

<cvm:CateringMenuViewModel x:Key="menu"/>

您告诉WPF创建CateringMenuViewModel的新实例并为其指定&#34; menu&#34;的键/名称/标识符,因此您在CateringMenuView中创建了一个副本,在NewRegularOrderView中创建的第二个副本。当然,更改一个CurrentUserControl属性不会影响另一个。

这种情况有两种常见的解决方案。

  1. 使用某种形式的事件系统让NewRegularOrderViewModel广播某种消息,让CateringMenuViewModel侦听这些类型的消息,并在CurrentUserControl时更改CateringMenuViewModel听到一个。

  2. NewRegularOrderViewModel(或方法委托)传递给ChangePageCommand,以便它可以直接调用{{1}}。 Korenenko的回答是试图向您展示一个解决方案。

  3. 就个人而言,在大多数情况下,如果可能的话,我更喜欢#1这样的东西,尽管#2在大多数情况下也是可以接受的。

    我发现我的大多数WPF应用程序都使用了某种消息传递系统,因此在这种情况下使用它是有意义的,你希望一个ViewModel改变另一个ViewModel它没有任何直接的引用至。如果您有兴趣,我会写一些关于herehere的例子。

答案 1 :(得分:1)

问题在于您正在调用CateringMenuViewModel的两个不同实例。您必须为NewRegularOrderViewModel提供其父viewModel(在您的情况下为CateringViewModel)的实例,以使用相同的DataContext实例来调用相同的命令。

CateringMenuViewModel

PageViewModels.Add(new NewRegularOrderViewModel(this)); <- add this 
PageViewModels.Add(new NewDeliveryComOrderViewModel());
PageViewModels.Add(new FillOrderViewModel());

NewRegularOrderViewModel

public CateringMenuViewModel Parent;
public NewRegularOrderView(): this(null)
{
}

public NewRegularOrderView(CateringMenuViewModel _Parent) {
    Parent = _Parent;
}

private ICommand _changePageCommand; 

public ICommand ChangePageCommand
{
    get {
        if (_changePageCommand == null)
        {
            _changePageCommand = new RelayCommand(
                p => ChangeViewModel((IUserContentViewModel)p),
                p => this.CanChangePageCommand);
        }

        return _changePageCommand;
    }
}

bool CanChangePageCommand
    {
        get { return true; }
    }

private void ChangeViewModel(IUserContentViewModel viewModel)
{
     Parent.CurrentUserControl = viewModel;   
}

NewRegularOrderView

<Button Command="{Binding ChangePageCommand}" 
        CommandParameter ="{Binding Parent.PageViewModels[2]}"/>

Datacontext在这里被压制,因为它指向你的NewRegularOrderViewModel。

我没有任何编辑就完成了这项工作,如果您有任何疑问或失败,请告诉我。