Composite WPF - Obtaining View reference with Presentation Model

In this message thread bsimser needs to close the View from the Presentation Model.  In MVP this would not be a problem because the View instantiates the Presenter and then hands the presenter a reference to itself.   In the Presentation Model this isn't the case, the Presentation Model is "an abstract of the view that is not dependent on a specific GUI framework"; there won't be a reference to the view in the Presentation Model.  You'll see something as follows where the data is "pulled" from the model.

Note: All references will be in the context of the CompositeWPF Commanding.sln solution.  The changes noted below provide a POC for bsimser' requirement.

OrdersEditorView.Xaml
 
<DataTemplate DataType="{x:Type models:OrderPresentationModel}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />            <<==  Added an extra row for demo
        </Grid.RowDefinitions>

I'll show how we can meet bsimser's requirement in a decoupled manner - the only dependency will be on the "Window" class.

In the same OrdersEditorView.xaml file (referenced above) I added the following Button.  The somewhat busy Binding basically will search up the logical tree until it finds a control of type Window, once found it will set a reference to it in the CommandParameter.

            <Button AutomationProperties.AutomationId="Close"
                    Grid.Row="7"
                    Grid.Column="1"
                    Content="Close"
                    CommandParameter="{Binding RelativeSource={
                        RelativeSource FindAncestor, 
                        AncestorType={x:Type Window}}}"
                    Command="{Binding CloseCommand}">
            </Button>
            </Grid>
        </DataTemplate>
    </UserControl.Resources>

I then added the following code to the OrderPresentationModel.cs to handle the new Button click:

The following provided for your copy/paste convenience:

public DelegateCommand<object> SaveOrderCommand { get; private set; }
public DelegateCommand<object> CloseCommand { get; private set; }

public OrderPresentationModel()
{
    SaveOrderCommand = new DelegateCommand<object>(Save, CanSave);
    CloseCommand = new DelegateCommand<object>(Close, CanClose);
    DeliveryDate = DateTime.Now;
    PropertyChanged += OnPropertyChangedEvent;
    Validate();
}

private bool CanClose(object arg)
{
    return this.errors.Count == 0 && Quantity > 0;
}
private void Close(object obj)
{
    //Save the order here.
    Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
        "{0} saved.", OrderName));

    Window view = obj as Window;
    if (view == null)
        throw new InvalidOperationException(
            "Could not find view in " + GetType().Name);

    view.Close();
}

With the above noted changes you can close the view with the click of the [Close] button; reference FLASH DEMO HERE

Source available at http://www.CodePlex.com/SDMS | Change set 24041

CompositeWPF | QuickStarts | Commanding | Commanding project (startup)


Tags: , ,
Categories: CompositeWPF


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know