View - ViewModel binding problem

Topics: Conventions, UI Architecture
Apr 17, 2012 at 6:41 AM
Edited Apr 17, 2012 at 6:42 AM

Hi,

Probably easiest to explain by example code...

Previously I had a structure like this (that was working)...

ShellView.xaml

        <ContentControl 
            x:Name="MappingRegion"
            Grid.ColumnSpan="3"
            Grid.RowSpan="4"
        />
        <ContentControl 
            x:Name="RightLowRegion"
            Grid.Column="2"
            Grid.Row="2"
        />
        <ContentControl 
            x:Name="PopupAreaRegion"
            Grid.ColumnSpan="3"
            Grid.RowSpan="4"
        />

ShellViewModel.cs

 

        [Import]
        public PopupAreaViewModel PopupAreaRegion { get; set; }

        [Import]
        public MappingViewModel MappingRegion { get; set; }

 

MappingView.xaml

 

 <ContentControl
        x:Name="ActiveItem"
        >
    </ContentControl>

 

MappingViewModel.cs

 

[Export(typeof(MappingViewModel))]
    public class MappingViewModel : Conductor<Screen>, IHandle<DisplayViewsEvent>, IHandle<LogOutEvent>
    {

        private List<IMappingViewModel> _viewModels;

        private IMappingViewModel _currentViewModel;

        [ImportingConstructor]
        public MappingViewModel([ImportMany]IEnumerable<IMappingViewModel> moduleVMs)
        {
            _viewModels = new List<IMappingViewModel>(moduleVMs);

            BLL.Instance.EventAggregator.Subscribe(this);

        }

        /// <summary>
        /// Event that determines what view to display
        /// </summary>
        /// <param name="message"></param>
        public void Handle(DisplayViewsEvent message)
        {
            _currentViewModel = _viewModels.Find( x => message.Views.Contains(x.DisplayName));

             if (_currentViewModel != null)
            {
                ActivateItem((Screen)_currentViewModel);
            }
            else
            {
                ActivateItem(null);
            }
        }

 

 

Example Module that extends IMappingViewModel...

Blueprint3D.xaml

- Contains all the ACTUAL view information that I want to display

Blueprint3D.cs

 

 [Export(typeof(IMappingViewModel))]
    [Export(typeof(Blueprint3DViewModel))]
    public class Blueprint3DViewModel : Screen, IMappingViewModel, IHandle<DeviceChangeEvent>, IHandle<LookAtEvent>
    {

       // All the rest of the code...
    }

 

When the user logs in I determine their 'role', fire an event that each region has subscribed to. The event includes what modules are relevant for that role and the region will then activate the appropriate module for that region. So multiple modules could apply to a region and I can switch between them by activating the appropriate module.

It worked all good. :) However I am trying to make the regions dynamic rather than coded in the ShellView.xaml..

Apr 17, 2012 at 7:00 AM

So now in the ShellViewModel I use the WindowManager to create a new ScreenViewModel for each monitor I need to support (expecting some multi-display setups). - This works fine.

In the ScreenViewModel.cs I create a new Grid for the current monitor with required col/row definitions. 

I then loop through my screen regions pulled from database and do the following:

var view = new ContentControl();

// ... redacted
// - Position it correctly in the grid

var module = new ModuleViewModel(); // Create a new module container

// These are the possible modules that can be displayed within this region dependent on the user role
var containers = BLL.Instance.Modules.GetModuleContainers(screenRegion.PossibleModules);

module.PossibleModules = containers; // of type List<IModuleContainer>

view.Content = module;

grid.Children.add(view); // Add content control to grid

I now have replaced the IMappingViewModel etc... with IModuleContainer and ALL modules now derive from that rather than the individual regions I had previously.

ModuleViewModel is similar to the old MappingViewModel.

 

When I run it I can create the windows, grids and colour the regions correctly. However the view(s) will not show up in the region. It will go into the correct constructor for the module I want in a region but if I place a OnViewAttached method within a module it will not get called. So I believe I am not binding the view-viewmodel correctly now. :(

Hope all that makes sense