Question

I have a GridView and the IsItemClickEnabled is set to true. In this case, the ItemClick event is fired, and it calls a delegate with a sender and an ItemClickEventArgs. I'm using MVVM (Caliburn.Micro), and my view models are all sitting in a portable class library (PCL). All command routing, etc., is done by Reactive-UI. The View's data context is set to the view model, as you might expect.

The problem is ItemClickEventArgs is not available in a PCL configuration as far as I can tell. So I am currently at a loss as how to sink that event in my view model. Heck - even without using a reactive ui command.

Here is my grid view defined:

        <GridView x:Name="PaperList" Margin="0" Grid.Column="1" IsItemClickEnabled="True" ItemClick="whatgoeshere?"/>

My simplest idea is to replace "whatgoeshere?" with a method in the view's code-behind, for example:

    public void ForkItUp(object sender, ItemClickEventArgs args)
    {
        // How do I get this information back to the view model?
    }

And of course, that works, that method gets called. But once I'm there, how the heck do I get the information back into my View Model? As far as I know the view knows nothing about the view model.

The only thing I can think of is I need to create some property that contains the PCL object that was clicked on. This method would stuff the item into that property, and through some magic of data-binding that would be sent back to the view model. If so, I have no idea how to participate in the data-binding process to get that right! Ack! :-)

I don't know if this makes a difference yet, but I'm not using universal apps! And I'm using a nasty hybrid of Caliburn.Micro to hook up my views, and Reactive-ui and rx to run all my commands. I don't like making anything easy!

Was it helpful?

Solution

Here's how I would do it

ReactiveCommand ItemClicked { get; protected set; }

public MyCoolViewModel()
{
    ItemClicked = new ReactiveCommand();
}

// In My View
gridView.ItemClicked += (o,e) => ViewModel.ItemClicked.Execute(e.Item);

As far as I know the view knows nothing about the view model.

This isn't how MVVM works - the View can know all kinds of stuff about the ViewModel, that's the whole idea! However, the ViewModel can know nothing about any Views.

OTHER TIPS

I found two different approaches worked, based on the answer that Paul gave. I ended up using the second. In the first approach I added a public method to my MyViewModel:

public void ClickOnTile(PaperTileViewModel pt)
{
    code to run;
}

Then, in my View I added the following:

public void ForkItUp(object sender, ItemClickEventArgs args)
{
    var obj = DataContext as MyViewModel;
    obj.ClickOnTile(args.ClickedItem as PaperTileViewModel);
}

And the XAML for my view for the grid view:

<GridView x:Name="PaperList" Margin="0" Grid.Column="1" IsItemClickEnabled="True" ItemClick="ForkItUp"/>

I'm a C++ guy by training, so the lack of type safety got to me a bit and lead to this second solution (which is the one that I ended up committing). So I ended up doing the following in the end. I first created an interface in my ViewModel's PCL:

public interface IHomePageViewCallback
{
    void FinalizeVMWiring(HomePageViewModel homePageViewModel);
}

Then, in the View I implemented the interface:

public sealed partial class MyPageView : Page, IHomePageViewCallback
{
    public MyPageView()
    {
        this.InitializeComponent();
    }

    public void FinalizeVMWiring(MyViewModel myVM)
    {
        PaperList.ItemClick += (s, args) => myVM.NavigateToPaperTile.Execute((args.ClickedItem) as PaperTileViewModel);
    }
}

where NavigateToPaperTile is a ReactiveCommand similar to what Paul has in his answer. This funny call back is needed because as far as I can tell there is no easy way to get a typed version of the ViewModel in Caliburn.Micro.

For completeness here is the XAML:

        <GridView x:Name="PaperList" Margin="0" Grid.Column="1" IsItemClickEnabled="True"/>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top