【问题标题】:Navigation using RelayCommand使用 RelayCommand 导航
【发布时间】:2015-12-10 13:10:30
【问题描述】:

我正在使用 MVVM 开发第一个应用程序。我关注了this link for navigation。在 Lawrence A. Contreras 的回答中,我使用了第一种导航方法,但收到 Command not found 错误。我的代码是

<ListView x:Name="lstItem" Grid.Row="1" ItemsSource="{Binding OrdersObject.data.orders}" ItemTemplate="{StaticResource DueOrderTemplate}" ItemContainerStyle="{StaticResource StretchItemStyle}">
        <Interactivity:Interaction.Behaviors>
            <Core:EventTriggerBehavior EventName="SelectionChanged">
                <Core:InvokeCommandAction CommandParameter="{Binding SelectedItem, ElementName=lstItem}" Command="{Binding SelectedOrderCommand}"/>
            </Core:EventTriggerBehavior>
        </Interactivity:Interaction.Behaviors>
    </ListView>

而cs是

var OrdersObj = new ViewModels.OrdersVM();
            OrdersObj.SelectedOrderCommand = new RelayCommand<Models.OOrderM>((itemParam) =>
            {
                if (itemParam != null)
                    this.Frame.Navigate(typeof(OrderEditP), itemParam);
            });
                        await OrdersObj.GetOrders("pending");

            this.DataContext = OrdersObj;

我的视图模型是

    class OrdersVM
{
        RelayCommand<OOrderM> _slectedOrderCommand;
        public RelayCommand<OOrderM> SelectedOrderCommand;
}

我哪里出错了?我没有使用任何库,也不想使用,所以我试图避免实现 INavigation 服务。因此,如果无法通过这种方式,我将欢迎任何其他建议。

我收到的错误是

BindingExpression 路径错误:在“App.ViewModels.OrdersVM、应用程序、版本=1.0.0.0、文化=中性、PublicKeyToken=null”上找不到“SelectedOrderCommand”属性。 BindingExpression: Path='SelectedOrderCommand' DataItem='App.ViewModels.OrdersVM, ShopkeeperApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null';目标元素是'Microsoft.Xaml.Interactions.Core.InvokeCommandAction'(名称='null');目标属性是“命令”(输入“ICommand”)

【问题讨论】:

  • 错误信息的确切文本是什么?您在哪里确切地得到错误?请提供一个好的minimal reproducible example 可靠地重现问题。

标签: c# mvvm


【解决方案1】:

我假设您有一个包含订单列表的页面,当您从该列表中选择时,您希望导航到订单详细信息页面。

我在您的示例中看到您将 EventtriggerBehavior 用于 SelectionChanged 事件。这是有效的,但有更好的方法来处理更改的选择。我宁愿将一个属性绑定到 ListView 的 SelectedValue

<ListView x:Name="lstItem" Grid.Row="1" ItemsSource="{Binding OrdersObject.data.orders}" ItemTemplate="{StaticResource DueOrderTemplate}" ItemContainerStyle="{StaticResource StretchItemStyle}" SelectedValue="{Binding SelectedOrder, UpdateSourcetrigger=PropertyChanged, Mode=TwoWay}">

现在在 VM 上,我假设您的项目是“订单”类的一个实例。为简单起见,我将只使用一个动作,我们将调用 _NavigateAction 以允许视图模型在需要时进行导航。您需要将该操作传递给视图模型的构造函数。

  public class OrdersVM : ViewModelBase
  {
    private Action<Order> _NavigateToOrderAction;

    private Order _SelectedOrder;

    public OrdersVM(Action<Order> navigateToOrderAction)
    {
      PropertyChanged += OrdersVM_PropertyChanged;
    }

    public Order SelectedOrder
    {
      get
      {
        return _SelectedOrder;
      }
      set
      {
        _SelectedOrder = value;
        OnPropertyChanged("SelectedOrder");
      }
    }

    private void OrdersVM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
      if (e.PropertyName == "SelectedOrder")
        OnSelectedOrderChanged();
    }

    private void OnSelectedOrderChanged()
    {
      //Use Selected order and do something.
      _NavigateToOrderAction(SelectedOrder);
    }
  }

您可能想知道我订阅了 PropertyChanged 事件,而不是在 SelectedOrder 的设置器中调用 OnSelectedOrderChanged()。其背后的原因是,如果您打算调用异步方法,则无法在 setter 中执行此操作。如果您在 OrdersVM_PropertyChanged 中,您可以轻松地将其设为异步函数。

让我们看看后面的代码。我们将实例化传入动作的视图模型。在这里,我们将首先定义该操作将做什么。我们希望它导航到 OrderDetailsPage,并且我们希望将所选订单作为导航参数传递。

  public sealed partial class MainPage : Page
  {
    public MainPage()
    {
      this.InitializeComponent();

      Action<Order> navigateToOrderAction = order =>
      {
        this.Frame.Navigate(typeof(OrderDetailsPage), order);
      };

      OrdersVM orderVM = new OrdersVM(navigateToOrderAction);
      this.DataContext = orderVM;
    }
  }

现在在 OrderDetails 代码后面,您可以重写 OnNavigateTo 方法并获取从上一页传递的订单实例。

  public sealed partial class OrderDetailsPage : Page
  {
    public OrderDetailsPage()
    {
      this.InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
      Order selectedOrder = e.Content as Order;
      if (selectedOrder != null)
      { //Do something with the selected order
        this.DataContext = selectedOrder;
      }
      base.OnNavigatedTo(e);
    }
  }

【讨论】:

    【解决方案2】:

    我通过在返回当前帧的 ViewModel 中创建 Frame 类型的属性解决了这个问题。所以我能够根据需要导航和执行操作,它还允许我分离代码。

    Frame currentFrame{get{return Window.Current.Content as Frame;}}
    
    
    
       public RelayCommand<OOrderM> SelectedOrderCommand{
    get
        {
    return _slectedOrderCommand??new RelayCommand<object>((itemParam)=>
    {
        currentFrame.Navigate(typeof(myPage));
    })
    };
    }
    

    【讨论】:

    • 您的视图模型不应该有框架。 Frame 是一个 UI 对象,不应该是 viewModel 的一部分
    猜你喜欢
    • 2016-02-15
    • 2015-09-20
    • 2018-06-21
    • 2012-02-23
    • 2014-03-30
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多