-1

I am developing first app using MVVM. I have followed this link for navigation. In answer from Lawrence A. Contreras I used the first approach for navigation but I receive Command not found error. My code is

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

and cs is

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;

and my View Model is

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

Where I'm making mistakes? I am not using any library and don't want to so I'm trying to avoid implementing INavigation service. So if not possible this way I will welcome any other suggestions.

Error I'm receiving is

BindingExpression path error: 'SelectedOrderCommand' property not found on 'App.ViewModels.OrdersVM, App, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. BindingExpression: Path='SelectedOrderCommand' DataItem='App.ViewModels.OrdersVM, ShopkeeperApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'; target element is 'Microsoft.Xaml.Interactions.Core.InvokeCommandAction' (Name='null'); target property is 'Command' (type 'ICommand')

Community
  • 1
  • 1
Rohit
  • 552
  • 3
  • 15
  • What is the _exact_ text of the error message? Where _exactly_ do you get the error? Please provide a good [mcve] that reliably reproduces the problem. – Peter Duniho Dec 11 '15 at 05:35

2 Answers2

0

I'm assuming that you have a page with a list of orders and when you select from that list you want to navigate to an order details page.

I see in your example that you used EventtriggerBehavior for SelectionChanged event. That is valid but there's a better way of handling the selection changed. I would rather bind a property to the ListView's 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}">

Now on the VM, I'm assuming that your item is an instance of "Order" class. For simplicity, I will just use an action, which we'll be calling _NavigateAction to allow the viewmodel to navigate if it needs to. You will need to pass that action to the viewmodel's constructor.

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

You might be wondering I subscribed to the PropertyChanged event instead of calling OnSelectedOrderChanged() in the SelectedOrder's setter. The reasonbehind that is that if you plan to call an async method, you can't do it in the setter. If you're in the OrdersVM_PropertyChanged you can easily make it an async function.

Let's go to the code behind. We will instantiate the the viewmodel passing in an action. Here we will first define what the action will do. We want it to navigate to the OrderDetailsPage and we want to pass in the selected order as a navigation parameter.

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

Now on the OrderDetails code behind you can override the OnNavigateTo method and get the instance of the order passed from the previous page.

  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);
    }
  }
Lance
  • 2,774
  • 4
  • 37
  • 57
-1

I resolved this problem by creating a property of type Frame in my ViewModel which returns the current frame. So I was able to navigate and perform operations as required also it allowed me to separate code.

Frame currentFrame{get{return Window.Current.Content as Frame;}}



   public RelayCommand<OOrderM> SelectedOrderCommand{
get
    {
return _slectedOrderCommand??new RelayCommand<object>((itemParam)=>
{
    currentFrame.Navigate(typeof(myPage));
})
};
}
Rohit
  • 552
  • 3
  • 15
  • Your viewmodel shouldn't have a Frame. Frame is a UI object and should not be part of the viewModel – Lance Apr 12 '17 at 18:26