使用RelayCommand进行导航

本文关键字:导航 RelayCommand 使用 | 更新日期: 2023-09-27 18:26:17

我正在使用MVVM开发第一个应用程序。我已通过此链接进行导航。Lawrence A.Contreras的回答是,我使用了第一种导航方法,但我收到了未发现错误的命令。我的代码是

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

我在哪里犯错误?我没有使用任何库,也不想使用,所以我尽量避免实现导航服务。因此,如果这样做不可能,我将欢迎任何其他建议。

我收到的错误是

BindingExpression路径错误:在"App.ViewModels.OrdersVM,App,Version=1.0.0.0,Culture=neutral,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"(名称="ull");目标属性为"Command"(类型为"ICommand")

使用RelayCommand进行导航

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

在您的示例中,我看到您对SelectionChanged事件使用了EventtriggerBehavior。这是有效的,但有更好的方法来处理更改的选择。我宁愿将一个属性绑定到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上,我假设您的项目是"Order"类的一个实例。为了简单起见,我将只使用一个操作,我们将调用该操作_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的setter中调用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);
    }
  }

我通过在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));
})
};
}