【问题标题】:Navigation with UserControls使用用户控件导航
【发布时间】:2016-01-27 12:03:42
【问题描述】:

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

我正在使用以下模式:

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

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

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

【问题讨论】:

  • 我想我现在知道你的问题是什么了,但是之前的一个问题,你想换成NewDeliveryComOrderView或者FillOrderView
  • @Kirenenko NewRegularOrderView 到 FillOrderView
  • 我认为问题与上一个问题相同...您必须将此代码添加到您的CateringMenuView UserControl.Resources:&lt;DataTemplate DataType="{x:Type cvm:FillOrderViewModel}"&gt; &lt;cv:FillOrderView/&gt; &lt;/DataTemplate&gt;。如果这不是失败,至少这是失败的“一部分”。
  • @Kirenenko 不,我添加了它。
  • 尝试在NewRegularOrderView 命令中使用与CateringMenuView 命令中相同的参数:Command="{Binding ChangePageCommand, Mode=OneWay, Source={StaticResource menu}}"。如果这不起作用,请检查您的 FillOrderViewModel 构造函数是否被调用。

标签: c# wpf user-controls


【解决方案1】:

Kirenenko's answer 是正确的,您有两个单独的 CateringMenuViewModel 实例

当你输入时

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

您告诉 WPF 创建CateringMenuViewModel 的新实例并为其分配“菜单”的键/名称/标识符,因此您在CateringMenuView 中创建了一个副本,在NewRegularOrderView 中创建了第二个副本。当然,更改其中一个的 CurrentUserControl 属性不会影响另一个。

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

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

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

就个人而言,如果可能的话,在大多数情况下,我更喜欢使用#1 来处理类似的事情,尽管在大多数情况下,#2 也是可以接受的。

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

【讨论】:

  • 我尝试使用您的 Simplifying PRISM 的 EventAggregator,但现在只有 Prism 6.0 可用,并且找不到“CompositePresentationEvent GetEvent()”。
  • @Cantinou 我不确定微软是否改变了他们的命名空间,但它应该在Microsoft.Practices.Composite.Presentation.Events。您是否确保为该库包含 using 声明?
  • 找到它,CompositePresentationEvent&lt;TEvent&gt; 已被PubSubEvent&lt;TEvent&gt; 取代。
  • @Cantinou 很高兴知道! :)
  • 我已经解决了事件聚合器的问题。但它产生了另一个问题。你能看看这个问题吗?非常感谢您的宝贵建议。 stackoverflow.com/questions/34987514/…
【解决方案2】:

问题是您正在调用CateringMenuViewModel 的两个不同实例。您必须为您的 NewRegularOrderViewModel 提供其 Parent 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。

我在没有任何编辑器的情况下完成了这项工作,所以如果您有任何疑问或有什么失败,请告诉我。

【讨论】:

  • 但是没有绑定到ChangePageCommand(NewRegularOrderViewModel)?该按钮处于禁用模式。
  • 我在Parent.CurrentUserControl = viewModel; 行将对象引用未设置为对象错误的实例
  • IUserContentViewModel viewModel 为空
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多