0

WPF application, using Prism.

I am using a multi phase module initialiser and in the initialisation of the module I would like the module to self inspect the views and register any regions defined within.

I am using something similar to the code below to self inspect view model classes and register other things, but I have no idea how to reflect into a view.

protected void SelfInspectRegions()
{
    var assm = Assembly.GetAssembly(this.GetType()).GetTypes();
    foreach (var type in assm)
    {
        if(type.IsSubclassOf(typeof(UserControl)))
        {
            var a = type;
        }
    }
}

An example of a Tab based region (defined on a View/UserControl) I would like to self register is below;

                <controls:ChTabControlModelAware x:Name="OrderProcessingDocumentDetailRegion"  
                                                           cal:RegionManager.RegionManager="{Binding RegionManager, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type shells:FormShell}}}"
                                                           cal:RegionManager.RegionName="Order Processing:DocumentDetailRegion"
                                                           cal:RegionManager.RegionContext="{Binding DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"
                                                           Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="1" VerticalAlignment="Stretch"
                                                           HorizontalAlignment="Stretch">

                    <bindings:EventToCommandBehavior.EventBindings>
                        <bindings:EventBinding Command="{Binding SelectedDetailTabChangedCommand}"
                                  CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=controls:TabControl}, Path= SelectedItem.DataContext.HeaderInfo}"
                                  EventName="SelectionChanged" RaiseOnHandledEvents="True"
                                  PassEventArgsToCommand="True" />
                    </bindings:EventToCommandBehavior.EventBindings>
                </controls:ChTabControlModelAware>

Principally I would like to extract the RegionName defined in the line;

cal:RegionManager.RegionName="Order Processing:DocumentDetailRegion"

I am not sure how to do this and any help would be gratefully received

Many Thanks

Lance

Update 17/10/2018 : What I am trying to achieve.

I am writing a WPF application framework with about 30 modules (and expanding) that all subscribe to and inject services.

All my regions are declared in the view, and there's loads and loads of them. Due to developing requirements in my framework it is now necessary for modules to pre-register their regions in the module initialisation phase. One of the reasons is that some services target particular regions and have operational settings that are unique each of the individual hosts. Currently the host modules are responsible for the settings, which means a lot of cutting and pasting between modules and projects if a change is made to the service's operational settings. By the hosts pre-registering, in module initialisation the service module knows which modules use its services and can inject a settings class into the host modules settings viewModel for user interaction. The changes to operational settings only have to be modified in the service module and not in all the various host modules that use it.

I was looking for an easy way to scrape the names out of the numerous module assemblies without having to explicitly declare them or adorn the view model with a declarative attribute.

Lance
  • 251
  • 5
  • 13
  • RegionName is an attached property that is set on a DependencyObject, e.g. a ChTabControlModelAware instance. You can't get it from a class. – Clemens Oct 16 '18 at 13:35
  • I would suggest you a better approach: do not define region names as string constants in XAML. Instead, create a `static class RegionNames` containing `public const string`s with region names. Then, you can set the region names in XAML using `x:Static` and use Reflection to get all names from the `RegionNames` class on initialization. – dymanoid Oct 16 '18 at 14:19
  • What do you want to achieve? `RegionManager.RegionName="SomeRegionName"` will register the control as region with the region manager, normally. – Haukinger Oct 16 '18 at 15:31

1 Answers1

0

I guess the easiest way to get the actual region names is to intercept them when the registration to the region manager is done.

You should register your own implementation of IRegionManager that forwards everything to the real thing, but passes all region names passing through it during a registration on to your region name registry.

Haukinger
  • 10,420
  • 2
  • 15
  • 28
  • The downside of this is that the the registration only occurs when the view is used, in the event of complex services that require operational configuration this is too late. The service could test that the settings had been initialised and prompt the user to go configure them, but would force a user with a trip to the view in order to initialise and then a trip to the settings screen. I don't think I can avoid it, especially where settings or an Opt-In/Out are required. The View/ViewModel will have to declare the region via an attribute so the Service can do its thing in initialisation. – Lance Oct 17 '18 at 11:46
  • So you basically mean to replace the attached property with an attribute? So that the service parses the attribute to know the region and the view parses it to register the region. Sounds feasible. But if I had to implement this, I would in fact prefer a static class for each module that contains all its region names and reflect into that. But you need something to enforce that, perhaps as simple as parsing the xaml in a pre-build step and throwing an error if RegionName="literal" is found... – Haukinger Oct 17 '18 at 14:54
  • I'm not sure how to replace an attached property with an attribute. I think what I am going to do is leave the Region as it is on the View and put the RegionDeclarationAttribute on the ViewModel. That way I can register the region at module initialisation and if the ViewModel is loaded non-visually the service's can decorate the Host ViewModel with the correct service ViewModels that would have been loaded via the service Views anyway. – Lance Oct 18 '18 at 10:43
  • How do you plan to enforce that the attributes match the xaml? If not enforced, it's just a matter of time for mismatches (and thus bugs) to come around. – Haukinger Oct 18 '18 at 11:42
  • Isn't that generally an issue with WPF? Pretty much all of my Views have the "Unresolved binding path when DataContext is unknown" warning... I've been doing this all these years and I've missed something haven't I? – Lance Oct 18 '18 at 14:21
  • currently how I'm linking it all together is:Container.Resolve().RegisterRegionViewAssociation("Order Processing:DocumentDetailRegion", typeof(VwCsJobOpDocumentDetailDecorator)); – Lance Oct 18 '18 at 14:25
  • Container.Resolve().RegisterViewModelViewAssociation(typeof(VmCsJobOpDocumentDetailDecorator), typeof(VwCsJobOpDocumentDetailDecorator)); – Lance Oct 18 '18 at 14:27
  • The thing's that most of the time data contexts are known. And even if not, view and view model are closeby and incorrect bindings will be detected when testing the module. But if I understand your scenario correctly, you're depending on correct region names in different modules, which will may lead to extensive integration tests, if you want to cover everything. Can be done, of course, just saying that having an enforcable mechanism that ensures correct region name registration can drastically reduce the needed test efforts. – Haukinger Oct 18 '18 at 16:10
  • I think what I will do is, declare the region on the associated ViewModel. When the modules initialise they will retrieve all the declarations and register them with an Adapted Region Manager Module. In the module Post Initialisation phase the services will acknowledge registrations to their services and do stuff. I can then create a View that displays all region associations, what has been registered against them and view any stray declarations. – Lance Oct 19 '18 at 15:46