MVVM - View and ViewModel Problems

6901
19
03-20-2012 06:40 AM
CorySchinkel
New Contributor II
Hi all,

I am using the MVVM pattern and the WPF API to build a mapping app.  I have a map object defined in a View and my app logic is defined in a ViewModel.  The ViewModel is set as the datacontext of the View.  Everything works great until I try to do something like work with the draw object in the ViewModel.  The draw constructor requires a reference to the map which I cannot access in the ViewModel.  This of course prevents me from defining the draw object in the ViewModel which is needed to respond to events on the draw object.  I could define the draw object in the View but it goes against the MVVM pattern to reference the View from the ViewModel.  So the dilemma is that I have no way of getting a reference to the map or draw object in the ViewModel and thus no way to handle events raised by those objects and no way to access their properties. 

If I were to define the draw object in my view I could setup commanding to handle some of the logic in the ViewModel, but I have requirements that would be difficult to implement with that design.  I would prefer to have the draw object (and other esri related objects) defined in the ViewModel and bound to the View somehow, but finding a good way to accomplish that is elusive.
 
Since I am using MVVM (fairly strictly) I do not want any (or very limited) amounts of code in the view code-behind.

Can someone offer guidance on best practices for handling this type of scenario?  Is there a way to make this work?

Thanks,
Cory
0 Kudos
19 Replies
AnttiKajanus1
Occasional Contributor III
Just noting that if you are working with .Net Framework 4.5, you can use MarkupExtensions with Events so you can use similar approach (CommandGenerator) with Events there. In my opinion, its about the time!

You can read more from http://blogs.microsoft.co.il/blogs/pavely/archive/2012/04/07/wpf-4-5-markup-extension-for-events.asp...
0 Kudos
ae
by
Occasional Contributor II
Hi,

In a project I'm working on we make use of pointdatasource for adding objects to a graphicslayer. However, when using pointdatasource, the resulting graphics will not contain any attribute information, making it impossible (as far as I can see) to show infowindows containing information about the objects, and also to use uniquevaluerenderer to determine which icon each graphics should have.

Is there any workaround for this issue (i.e. is it somehow possible to add attributes to graphics when using pointdatasource)?

Pointdatasource seems to be the preferred way of implementing an mvvm structure using the api.

Any help is greatly appreciated 🙂

Cheers
0 Kudos
AnttiKajanus1
Occasional Contributor III
I am not aware that using PointDataSource is the preferred way to go with MVVM since. From the experience that I have got with working mainly with Silverlight, is that you can work with Graphic's in the ViewModels with no problem and there is no need to build a lot of extra-work-a-rounds since you can bind the graphics directly. I would be interested if other peoples have different view to this topic.

You can use quite a lot of different approaches here but I have been using GraphicCollection or ObservableCollection<Graphic> that I bind directly in XAML to graphics layer. You can look how you can do that from here http://forums.arcgis.com/threads/63189-GpsLayer-and-MVVM-issues?p=220140&viewfull=1#post220140 With this kind of approach you can easily use other stuff like Task's in very mannered way from the ViewModels (or from the application services since you probably won't want to bloat your VM's code with all that stuff).

Also one good way to abstract association code with the Graphics is to create custom list like in the "Using GraphicsSource Online"-example in the Samples.

Hope this helps.

Edit:
Jeff Jackson kept very good tutorial to MVVM development in Developer summit. I encourage people to check it out
http://video.arcgis.com/watch/1185/software-development-and-design-using-mvvm
0 Kudos
ae
by
Occasional Contributor II
I am not aware that using PointDataSource is the preferred way to go with MVVM since. From the experience that I have got with working mainly with Silverlight, is that you can work with Graphic's in the ViewModels with no problem and there is no need to build a lot of extra-work-a-rounds since you can bind the graphics directly. I would be interested if other peoples have different view to this topic.

You can use quite a lot of different approaches here but I have been using GraphicCollection or ObservableCollection<Graphic> that I bind directly in XAML to graphics layer. You can look how you can do that from here http://forums.arcgis.com/threads/63189-GpsLayer-and-MVVM-issues?p=220140&viewfull=1#post220140 With this kind of approach you can easily use other stuff like Task's in very mannered way from the ViewModels (or from the application services since you probably won't want to bloat your VM's code with all that stuff).

Also one good way to abstract association code with the Graphics is to create custom list like in the "Using GraphicsSource Online"-example in the Samples.

Hope this helps.

Edit:
Jeff Jackson kept very good tutorial to MVVM development in Developer summit. I encourage people to check it out
http://video.arcgis.com/watch/1185/software-development-and-design-using-mvvm


Hi Antti, and thanks for your reply! I was probably wrong when saying that PointDataSource was the preferred way to go with mvvm in the API. I got this impression when I read the following description on the api web site:

The PointDataSource class provides the implementation necessary to easily bind to items with attributes that reference location using X and Y values. This functionality caters to the use of Model View ViewModel (MVVM) design patterns. In general, the view (user interface [UI]) can bind to data (model) via a view-model, implemented in code-behind.

Anyway, I will go for using a graphiccollection instead, this seems to be a much better approach 🙂 Thanks again for your help!
0 Kudos
AnkitaBhatia
New Contributor III
Hi,
I have been following this post since a long time and saw the examples above. It is really great work.
However from what I perceive of MVVM, my viewmodel should actually be totally unaware of the view. While when I try to implement the same in ESRI's SDK for WPF, it makes me use instance of Map in the ViewModel.

Has someone found a way to create a viewmodel that does not include a reference to ESRI? This somehow is the first requirement for the application I am developing.
0 Kudos
AnargyrosTomaras
New Contributor III
Hi,
I have been following this post since a long time and saw the examples above. It is really great work.
However from what I perceive of MVVM, my viewmodel should actually be totally unaware of the view. While when I try to implement the same in ESRI's SDK for WPF, it makes me use instance of Map in the ViewModel.

Has someone found a way to create a viewmodel that does not include a reference to ESRI? This somehow is the first requirement for the application I am developing.



  1. You can always delegate more work (through indirections) to the View.

  2. Make a MapViewModel for what is bindable and for anything that isn't you can:

    1. listen for custom VM events/propertychanges in the View that tells it , indirectly, what to do with the Map.

    2. similarly but with the use of attached properties like here where a property change event

    3. is used to indirectly signal a ZoomTo call on the Map through an AttachedDP. This reminds me a bit of
      Prism's InteractionRequest trick which essentially is a Action Triggered by a property change
  3. Another solution might be to make you own custom wrapper control (MapControl) that this time IS bindable.

  4. You are free to design the interface of the control and therefore how its ViewModel will look like. This is
    btw similar to what had to be done by all WinPhone devs to bypass the fact that the
    ApplicationBar control on WinPhone is not bindable!! They made a bindable wrapper.
  5. Another solution is to embrace the fact that not everything can and will be bindable and use a hybrid approach which

  6. I am very fond off called PresentationModel, which is essentially the parent of MVVM (think bindable Presenter), along with the option of having a interface for the View.
    An elegant way of setting this up is similar to how GWT does it :

    public class PresentationModel
    {
        public interface View 
        {
             void ZoomTo(Geometry geom);
        }
    
        public View View {get; set;}
    }
    

  7. Now, if all these seem to be too much work then...

  8. If you find that going pure MVVM is too much of a hassle in some cases then I personally don't mind
    making a wrapper ViewModel (think MapViewModel that wraps the Map). I know it breaks "rules"
    but I can get the job done whilst respecting the MVVM goal and retaining the fundamental benefits.
    It's going to look, feel and smell like a VM but in reality it wont bind to anything.
    This way I still code against a ViewModel, I can mock it, test code that uses it etc etc.
    1) I keep the benefits of using a ViewModel,
    2) I have the flexibility of changing the interface I code against completely if I wish so. For example I could provide a LocationViewModel (or DrawViewModel) off the MapViewModel to simulate the new Map.LocationDisplay coming in the WinStore and WP8 instead of dealing with a GpsLayer (WP7/WPF API) thus making my code more portable also (since I can hide some API differences behind my interface)..
    3) You have less to worry about concerning trying to workaround the non-bindable scenarios.


Hope this helps

Cheers 🙂
0 Kudos
RogerF
by
Occasional Contributor
Keith,

If you want to wire up a method on your ViewModel to some arbitrary event, then you need to use something like the InvokeCommandAction which is defined in System.Windows.Interactivity. Then you can generate a command using the CommandGenerator and you're set.

In the case you describe though, you don't really need to use an event to determine if the ComboBox selection changes. You can simply bind to another property in your ViewModel instead.

For example, your view ComboBox might be defined like this:


  <ComboBox ItemsSource="{Binding States}"
            SelectedItem="{Binding CurrentState}"
            Height="25" 
            Width="120"/>




By binding to the SelectedItem property, the setter on you ViewModel property (CurrentState) will get called any time the selection changes.

Hope that helps,
Jeff


Jeff

your MVVM session has been a great starting point for me. I have been working on similar functionality where Listbox needs be multi-selectable. Upon research, I figured that 'SelectedItems' property is not 'bindable' with view. Is there any MVVM way of doing this ?.I need to zoom to the results selected in Listbox. Your quick response will be greatly appreciated.

Thanks
0 Kudos
AnargyrosTomaras
New Contributor III
Hi Federer,

You can introduce a boolean IsSelected property in your List ViewModels and Two-Way bind them to the IsSelected DP property of the generated ListBoxItem's.

Here's the XAML part :

<ListBox ItemsSource="{Binding ItemVMs}">
  <ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
      <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
    </Style>
  </ListBox.ItemContainerStyle>
</ListBox>


Hope this helps.
0 Kudos
AnttiKajanus1
Occasional Contributor III
As atomaras said, that solution works quite well in most of the scenarios. Just check that UIVirtualization is support is ok for your needs.

Simplest solution is to create codebehind event handler and then direct selection to viewmodel from there. Yes, it's code in the codebehind but in this kind of scenarios it is ok. I use this solution if I'm lazy and want fast results.

One solution is to create attached property that encapsulates that but that needs a bit more testing. This was found with fast googling
http://blog.functionalfun.net/2009/02/how-to-databind-to-selecteditems.html

(side note, if you guys are coming to DevSummit to Palm Springs this year, I would love to have a chat about MVVM and how you do it).
0 Kudos
BrianLocke
Occasional Contributor II
MVVM Light!~
0 Kudos