Skip to content
This repository has been archived by the owner on Jun 7, 2022. It is now read-only.
/ wpf-nav-sample Public archive

Example of DataTemplate-based navigation with WPF

License

Notifications You must be signed in to change notification settings

vain0x/wpf-nav-sample

Repository files navigation

WPF Navigation Example

Example of DataTemplate-based page navigation for WPF.

Key items

  • Define DataTemplates to define a mapping from view models to views (control) in resource dictionary
  • Show views by setting view models to content of ContentControl (referred to as frame)
  • Changing content of the frame is navigation, which is done in the view model layer

Note that you don't need System.Windows.Controls.Frame.

Mechanism

Mechanism: DataTemplate and ContentControl

Let Foo be a class of data context for a view FooControl.

If you define a DataTemplate for Foo like this, the template is automatically applied whenever WPF would display the Foo instance.

For example, you have the following in a resource dictionary:

    <DataTemplate DataType="{x:Type foo:Foo}">
        <foo:FooControl />
    </DataTemplate>

and put a control on window to display an instance of Foo:

    <ContentControl Control="{Binding Foo}" />

then you will see FooControl with DataContext bound to the Foo property.

See AppResourceDictionary.xaml for real implementation.

CommandParameter and RelativeSource

Pages in frame (a control to host pages) must dispatch some message to the parent frame to go to another page. The cyclic reference, "the frame know pages and the pages also know the frame", is bad for maintainability as separation of concerns principle.

You can de-couple the frame and pages using RelativeSource. See the following example:

<UserControl>
    <!-- Inside FooControl (page) -->
    <Button Content="Go some page"
        Command="{Binding
            DataContext.NavigateCommand,
            RelativeSource={RelativeSource
                AncestorType={x:Type layoutFrames:LayoutFrameControl}
            }"
        CommandParameter="{Binding NavigateRequest}" />
</UserControl>

Assume that the user control is a page of LayoutFarmeControl (with DataContext LayoutFrame). The RelativeSource binding finds a lowest ancestor of the type specified with AncestorType, i.e. LayoutFrameControl, and use it as binding source. Hence The value of the binding will be LayoutFrameControol.DataContext.NavigateCommand = LayoutFrame.NavigateCommand. That's how you can use NavigateCommand inside pages, without using reference to the frame.

The command parameter NavigateRequest is something to specify where to go, which also doesn't need to know the frame.

Naming

Naming: Suffix of views

I'm not a big fun of typical xxxViewModel suffix for view models. In this repository the view models have no suffixes, but views have -Control suffix (except for windows). E.g. LayoutFrame is a view model for corresponding view LayoutFrameControl.

Naming: Requests

Requests are objects intended to be a parameter of commands. I know the word is NOT the best choice but at least makes sence.

Extensibility

This system can be exetended to other kind of navigation such as open/close drawer. It should be future work.

Releases

No releases published

Packages

No packages published

Languages