1

OK so I am (very) new to WPF but have 13 years with Win-forms, so no newbie. I am writing a new system and decided to break the ice with WPF using the MVP-VM pattern as I am familiar with MVP.

Now I am also reusing my own (composite) architecture which has the UI or presentation layer in a project separate from the Presenters and View models. One of the main benefits to this approach is that the Presenter layer or Base layer has all the presentation/command/controller logic and no reference to UI matters. The Main IDEA is that this layer has no reference to any UI assemblies like Winforms or WPF.

The ISSUE: IN Xaml, I have a menu item 'Exit' which I want to bind to the View model. Every example of this that I have seen uses ICommand.. which is housed in Presentation.core... the view model is in the presentation layer and therefore does not have a reference to the Presentation.Core..

The Xaml thus far is

<Window x:Class="Homestead.Wpf.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="244" Width="490" xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="23"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="23" />
    </Grid.RowDefinitions>
    <Menu Grid.Row="0">
        <MenuItem Header="File">
            <MenuItem Header="Exit"  />
        </MenuItem> 
    </Menu>
    <StatusBar Grid.Row="2"  >
        <StatusBarItem   >
            <TextBlock  Text="{Binding Path=StatusMessage}" />
        </StatusBarItem>
        <StatusBarItem  HorizontalAlignment="Right" MinWidth="120">
            <TextBlock  Text="{Binding Path=UserName}" />
        </StatusBarItem>
    </StatusBar>
</Grid>

the view model thus far is

public class ShellViewModel : ViewModelBase
{

    #region Private Variables

    private string _status = string.Empty;
    private string _userName;

    #endregion

    #region Public Properties

    public string StatusMessage
    {
        get { return _status; }
        set
        {
            _status = value;
            OnPropertyChanged("StatusMessage");
        }
    }

    public string UserName
    {
        get { return _userName; }
        set
        {
            _userName = value;
            OnPropertyChanged("UserName");
        }
    }


    #endregion

    #region Commands

    // No reference to ICommand... WTF

    #endregion
}
  1. is there any alternative to this pattern..(without using code behind)
  2. How does this work with Menu items added at runtime, amusing there is a way.

Must I redesign or break the design pattern to use WPF? please guide me.

There is one possibility that I can see and that is to Interface out the ViewModel as well as the View.. I have a Controller that creates the Presenters that usually passes in to the presenter the implementation of the view. I.e a typical Presenter constructor would be

    public ErrorMessagePresenter(IErrorMessageView view)
    {
        View = view;
        View.Presenter = this;            
    }

The controller code is thus

    public ErrorMessagePresenter CreateErrorPresenter()
    {
        return new ErrorMessagePresenter(_viewFactory.CreateErrorMessageView());
    }

now I know that this is reversed but literally the UI layer is only concerned with UI matters, everything else including navigation is handled in the Base layer or below..

Mamta D
  • 6,310
  • 3
  • 27
  • 41

2 Answers2

2

The most common pattern in WPF is Model-View-ViewModel, a pattern in which the presenter has been removed in favor of a more knowledgeable view-model, which is indeed aware of things like ICommand (which is a contract, shared by the view layer as a way to communicate actions, and this justifies the view-model knowing about it).

You can try to force the application not use ICommand by implementing behaviors and data triggers which execute actions in the view-model based on the actions in the UI, but this requires much more coding, not just binding and it is not scalable or sustainable if you intend to continue developing WPF applications in the future (or Windows Store applications for that matter, which commonly use MVVM as well).

I recommend looking into incorporating a framework like MVVM-light in your project using NuGet, so that you can start on top of the foundation of a well-established set of classes, patterns and utilities which have adapted to WPF as a technology for many years instead of trying to hammer the "spherical" framework you are familiar with into the "square" cavity which is WPF (figuratively speaking).

I learned the hard way when I started with it, that trying to bring my experience and habits from WinForms to WPF brings nothing but trouble, so the sooner you start making your peace with the idea that most of what you have done won't be applicable in WPF, the better for your mental sanity.

Of course, patterns are patterns and they can be applied in different ways in a multitude of environments, but the reality is that WPF already has the plugs for certain things to work a certain way and trying to go against that is only going to give you more work as a developer and architect, so it is better to just go with the flow and adapt to the most common way of doing things in the XAML world.

Murven
  • 2,377
  • 17
  • 23
1

To give you some quick solution options:

  • 1 - System.Windows.Input.ICommand is available if you're targeting a Portable Class Library. This might be possible or not depending on other requirements for your project, but if it is an option, it's really recommendable that you put all your ViewModels and "UI targeting" code in PCLs, since these are by definition the most reusable and platform agnostic type of assemblies you can create in .Net, supporting not only Windows .Net scenarios, but also mobile thru Xamarin.

  • 2 - Abstract the ICommand interface away via dependency injection or Service Locator patterns.

  • 3: Add a reference to PresentationCore.dll but make sure you aren't using anything other than ICommand from there.


To answer your question #2, Menus: ListBoxes, ComboBoxes, TreeViews, and any other items-based UI elements in WPF are derived from the ItemsControl class. It provides an abstract way to dynamically generate UI elements from a collection of data items.

See this blog series for a very comprehensive explanation. The ItemsControl is one of the most powerful WPF features and mastering it can be very rewarding. I have created all sorts of things using it from breadcrumb bars to "Tagging controls" (similar to StackOverflow's tags selection), to chess boards to diagram designers

Basically you will create a class with simple properties representing the Menu Items (with text, an image, and an ICommand to be executed when the menu item is clicked) and put instances of this class into an ObservableCollection<T>, which supports WPF databinding to collections.


On a side note, your Controller creating the presenter and the view and associating the view with the ViewModel and the Presenter approach and all that is not needed. It creates an overly complex, totally unmaintainable scenario where you need to manually do this every time you need to show a View.

WPF resolves that with the use of DataTemplates. See this answer for a very simple usage example.

In fact, the whole concept of a Presenter is not even needed at all in WPF. Since your Views are "glued" to their underlying ViewModels using DataBinding, and there's no need for manual "piping" code or passing data back and forth.

Community
  • 1
  • 1
Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154