How to reuse a wpf view?

2019-07-24 17:36发布

问题:

Is there a way to reuse a WPF View using it with Caliburn.Micro?

In example I've got a DetailViewBase.xaml with a SaveAndClose and Cancel button. Now I want to use the DetailViewModelBase and the XAML in PersonView(Model).

I hope this is question is clear.

回答1:

If my assumption is correct, I think what you mean is that you want to 'compose' a more complex view from several simpler viewmodels. You can inherit from viewmodels, but obviously a viewmodel can only have one active view at a time.

However, using bindings you can compose multiple viewmodels and have them all render their respective views together to make a more complex UI

e.g.

A VM with save/cancel buttons

public class ActionsViewModel
{
    public void Save()
    {
    }

    public void Cancel()
    {
    }
}

The corresponding view:

<UserControl>
   <StackPanel Orientation="Horizontal">
       <Button x:Name="Save">Save</Button>
       <Button x:Name="Cancel">Cancel</Button>
   </StackPanel>
</UserControl>

Another view which composes itself and the ActionsViewModel

public class ComposedViewModel
{
    public ActionsViewModel ActionsView
    {
        get; set;
    }

    public ComposedViewModel()
    {
        ActionsView = new ActionsViewModel();
    }      

    public void DoSomething()
    {
    }
}

The View:

<UserControl>
   <StackPanel Orientation="Horizontal">
       <TextBlock>Hello World</TextBlock>
       <Button x:Name="DoSomething">Do Something</Button>
       <ContentControl x:Name="ActionsView" />
   </StackPanel>
</UserControl>

When you use the convention binding (or use the attached properties) to bind a ContentControl CM will automatically bind the VM to the DataContext and wire up the view. This way you can compose multiple VMs into a single more complex piece of functionality.

Additionally, because of the action message bubbling - if you were to remove the 'Ok' and 'Cancel' implementation on the ActionsViewModel and put them in the ComposedViewModel implementation, the action message will bubble up to the ComposedViewModel instance and fire the methods on there instead

e.g.

public class ActionsViewModel
{
    // Remove the command handlers
}


public class ComposedViewModel
{
    public ActionsViewModel ActionsView
    {
        get; set;
    }

    public ComposedViewModel()
    {
        ActionsView = new ActionsViewModel();
    }      

    public void DoSomething()
    {
    }

    // CM will bubble the messages up so that these methods handle them when the user clicks on the buttons in the ActionsView
    public void Save()
    {
    }

    public void Cancel()
    {
    }
}

EDIT:

Sorry I forgot about this - convention based bindings won't allow messages to bubble, but you can just use the Message.Attach attached property for this to work:

// Make sure you include the caliburn namespace:
<UserControl xmlns:cal="http://www.caliburnproject.org">
   <StackPanel Orientation="Horizontal">
       <Button x:Name="Save" cal:Message.Attach="Save">Save</Button>
       <Button x:Name="Cancel" cal:Message.Attach="Cancel">Cancel</Button>
   </StackPanel>
</UserControl>


回答2:

You can bind the ViewModel to the View explicitly using code like this:

cal:Bind.Model={Binding DetailViewModelBase}