简体   繁体   中英

Prism 6 Navigation and dynamically discovering views

I'm using Prism 6 to build an app with several different modules. It's a simple menu of buttons, each of which navigates the main content area to a different dynamically-discovered view. Unfortunately, I find myself hard-coding main menu buttons which is obviously not what I want.

What I want is to dynamically build an ItemsControl of radio buttons from the list of all views that have registered for my categories. But I can't figure out how to write the ViewModel property that asks Prism for such a list .

Moreover, I'm hoping for reassurance that my overall approach is sound.

To illustrate, right now I've got several displays for functionality, each implemented in its own module.

  • A Module for showing a live view from a camera and capturing images
  • A module for browsing a library of captured images
  • Other ignored for brevity

In my main view XAML, I have the buttons in a DockPanel on the left and the view content in a region (ContentControl "Main") on the right. Here's the XAML trimmed down a bit.

    <DockPanel >
    <Border MinWidth="50"
            DockPanel.Dock="Left"
            >
        <StackPanel Orientation="Vertical">
            <StackPanel.Resources>
                <Style TargetType="{x:Type RadioButton}"
                       BasedOn="{StaticResource CategoryButton}">
                    <Setter Property="GroupName" Value="MainGroup"/>
                    <Setter Property="IsChecked">
                        <Setter.Value>
                        <MultiBinding Converter="{StaticResource ObjectEqualsConverter}" Mode="OneWay">
                            <Binding Path="DataContext.ActivePageName" 
                                     RelativeSource="{RelativeSource AncestorType={x:Type Window}}" />
                            <Binding Path="CommandParameter" RelativeSource="{RelativeSource Self}"  />
                        </MultiBinding>
                        </Setter.Value>
                    </Setter>
                </Style>
            </StackPanel.Resources>
            <RadioButton Command="{Binding NavigateCmd}" 
                         CommandParameter="CaptureView"
                         Margin="5"  Content="Capture"
            />

            <RadioButton Command="{Binding NavigateCmd}" 
                         CommandParameter="LibraryView"
                         Margin="5"   Content="Explore" 
            />

        </StackPanel>
    </Border>

    <!--
    Content is in the region named "Main".  Modules register their own page 
    views and we navigate this region to show them as the user clicks the
    page buttons.  
    -->
    <ContentControl x:Name="Page" 
                    prism:RegionManager.RegionName="{x:Static ga:Regions.Main}"
                    />
</DockPanel>

</Window>

My Main View Model

    public class MainWindowVm : BaseVm
{
    private readonly IRegionManager _regionManager;
    private readonly IUnityContainer _container;
    private readonly IModuleCatalog _catalog;
    private readonly IEventAggregator _aggregator;
    public MainWindowVm(
        IRegionManager rm, 
        IUnityContainer container, 
        IModuleCatalog catalog)
    {
        NavigateCmd = new Prism.Commands.DelegateCommand<string>(Navigate);

        _regionManager = rm;
        _container = container;
        _catalog = catalog;
    }

    public string CurrentView => (string)_regionManager?.Regions[Regions.Main]?.ActiveViews?.FirstOrDefault()?.ToString() ?? "";
    public Prism.Commands.DelegateCommand<string> NavigateCmd { get; private set; }
    public void Navigate(string path)
    {
        _regionManager.RequestNavigate(Regions.Main, path, NavigationCompleted);
    }



    private void NavigationCompleted(NavigationResult nr)
    {
        RaisePropertyChanged("");
    }

    public string ActivePageName
    {
        get
        {
            // HACK:  Currently I'm taking the fully qualified name of the
            // current view (e.g. "MyCompany.LibraryModule.LibraryView") and just
            // chopping off all namespaces to get the basic, unqualified 
            // view name (e.g. "LibraryView") which I am blithely assuming 
            // will perfectly match one of the Page buttons on the main 
            // window.  This really needs to be improved and generalized...

            var name = CurrentView;
            var i = name.LastIndexOf('.');
            if (-1 != i)
                name = name.Substring(i+1);

            return name;
        }
    }  
};

My modules register their views using RegisterTypeForNavigation. For example:

public class LibraryModule : IModule
{
    private readonly IRegionManager _regionManager;
    private readonly IUnityContainer _container;

    public LibraryModule(IRegionManager regionManager, IUnityContainer c)
    {
        _regionManager = regionManager;
        _container = c;
    }

    public void Initialize()
    {
        _container.RegisterTypeForNavigation<LibraryView>();
    }
}

Is there a simple way to achieve this given my setup. Should I instead be using some other registration/navigation method?

Prism has changed so drastically and all of samples seem a bit dated so I'm at a loss as to what to do here

Prism has changed so drastically and all of samples seem a bit dated so I'm at a loss as to what to do here

Actually, Prism for WPF hasn't changed in years and all the current samples are up to date. So, not sure what you are basing this statement on.

You are thinking about this all wrong. You are registering your views and then trying to ask Prism what the view names are. Instead, what is actually happening is that you are telling Prism what view names you have and registering accordingly. You already have the data, you just need to store it where you can ask for it. You are probably better off having some type of ViewRegistrationService that manages what view names are registered and have them add to a collection that your ItemsControl can bind to. The service should be a singleton.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM