Визуализация времени разработки пользовательских элементов управления в пользовательском Region / RegionManager

1

Мне очень понравилась реализация навигации, выполненная с помощью платформы MS Prism, но мне не нужны все функции, и у меня возникли проблемы с временным управлением просмотрами и просмотром моделей. Итак, я просунул код и переопределил свой собственный менеджер Region/Region, добавив некоторую дополнительную функциональность.

Пока все отлично работает, но есть некоторая поддержка времени разработки, которую я бы хотел, но не знаю, как реализовать. Я добавил свойство прикрепленного DefaultViewType. Мне бы хотелось, чтобы я мог сделать это представление в дизайнере.

Еще одна странность в том, что Visual Studio (или Resharper) сообщает о следующей проблеме в дизайнере, что, насколько я могу судить, неверно:

Свойство RegionName уже было зарегистрировано в ContentControl.

Здесь код (также доступен на странице https://github.com/agartee/StackOverFlowRegionManagerQuestion.git):

Мой RegionManager - это сервис, который подписывается на сообщения MVVM Light типа, NavigationRequestMessage:

public class RegionManager : IRegionManager
{
    private readonly IDictionary<string, ContentControl> _regions =
        new Dictionary<string, ContentControl>();

    public RegionManager(IMessenger messenger)
    {
        messenger.Register<NavigationRequestMessage>(this, Navigate);
    }

    public void RegisterRegion(string regionName, ContentControl region)
    {
        if (_regions.ContainsKey(regionName))
            _regions.Remove(regionName);

        _regions.Add(regionName, region);
    }

    public void Navigate(NavigationRequestMessage message)
    {
        if (!_regions.ContainsKey(message.RegionName)) return;

        var targetRegion = _regions[message.RegionName];

        if (message.ViewType != null)
        {
            var view = ServiceLocator.Current.GetInstance<UserControl>(message.ViewType.Name);
            targetRegion.Content = view;
        }
        else
        {
            targetRegion.Content = null;
        }
    }
}

public class NavigationRequestMessage
{
    public string RegionName { get; private set; }
    public Type ViewType { get; private set; }

    public NavigationRequestMessage(string regionName, Type viewType)
    {
        RegionName = regionName;
        ViewType = viewType;
    }
}

В регионе находятся прилежащие свойства:

public static class Region
{
    public static readonly DependencyProperty RegionNameProperty = DependencyProperty.RegisterAttached(
        "RegionName",
        typeof(string),
        typeof(ContentControl),
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, RegionNameChanged));

    public static string GetRegionName(UIElement element)
    {
        return (string)element.GetValue(RegionNameProperty);
    }

    public static void SetRegionName(UIElement element, string value)
    {
        element.SetValue(RegionNameProperty, value);
    }

    public static readonly DependencyProperty DefaultViewTypeProperty = DependencyProperty.RegisterAttached(
        "DefaultViewType",
        typeof(Type),
        typeof(ContentControl),
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));

    public static Type GetDefaultViewType(UIElement element)
    {
        return (Type)element.GetValue(DefaultViewTypeProperty);
    }

    public static void SetDefaultViewType(UIElement element, Type value)
    {
        element.SetValue(DefaultViewTypeProperty, value);
    }

    private static void RegionNameChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var regionName = (string)e.NewValue;
        var region = (ContentControl)dependencyObject;

        RoutedEventHandler regionOnLoaded = null;
        regionOnLoaded = (sender, args) =>
        {
            region.Loaded -= regionOnLoaded;

            RegisterRegion(regionName, region);
            NavigateToDefaultView(dependencyObject);

        };
        region.Loaded += regionOnLoaded;
    }

    private static void RegisterRegion(string regionName, ContentControl region)
    {
        var navigationService = ServiceLocator.Current.GetInstance<IRegionManager>();
        navigationService.RegisterRegion(regionName, region);
    }

    public static ContentControl GetParentView(DependencyObject child)
    {
        var parent = VisualTreeHelper.GetParent(child);
        if (parent == null)
            return null;

        var parentWindow = parent as Window;
        if (parentWindow != null)
            return parentWindow;

        var parentUserControl = parent as UserControl;
        return parentUserControl ?? GetParentView(parent);
    }

    private static void NavigateToDefaultView(DependencyObject dependencyObject)
    {
        var regionName = (string)dependencyObject.GetValue(RegionNameProperty);
        var defaultViewType = (Type)dependencyObject.GetValue(DefaultViewTypeProperty);

        if (String.IsNullOrWhiteSpace(regionName) || defaultViewType == null)
            return;

        var navigationService = ServiceLocator.Current.GetInstance<IRegionManager>();
        navigationService.Navigate(new NavigationRequestMessage(regionName, defaultViewType));
    }
}
Теги:
xaml
wpf

1 ответ

1
Лучший ответ

Я смог выполнить то, что я хотел выполнить, с приведенными ниже изменениями:

public class Region : Behavior<ContentControl>
{
    public static readonly DependencyProperty DefaultViewTypeProperty = DependencyProperty.Register(
        "DefaultViewType", 
        typeof(Type),
        typeof(Region), 
        new PropertyMetadata(default(UserControl)));

    public Type DefaultViewType
    {
        get { return (Type)GetValue(DefaultViewTypeProperty); }
        set { SetValue(DefaultViewTypeProperty, value); }
    }

    public static readonly DependencyProperty RegionNameProperty = DependencyProperty.RegisterAttached(
        "RegionName",
        typeof(string),
        typeof(Region),
        new PropertyMetadata(default(string)));

    public string RegionName
    {
        get { return (string)GetValue(RegionNameProperty); }
        set { SetValue(RegionNameProperty, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        ShowDefaultView();
        RegisterRegionWithManager();
    }

    private void ShowDefaultView()
    {
        if (DefaultViewType == null)
            return;

        if (DesignerProperties.GetIsInDesignMode(AssociatedObject))
        {
            var constructorInfo = DefaultViewType.GetConstructors().First();
            var parameters = new List<object>();
            constructorInfo.GetParameters().ToList().ForEach(p => parameters.Add(null));

            AssociatedObject.Content = constructorInfo.Invoke(parameters.ToArray());
        }
        else
        {
            var serviceLocator = ServiceLocator.Current;
            AssociatedObject.Content = serviceLocator.GetInstance(DefaultViewType);    
        }
    }

    private void RegisterRegionWithManager()
    {
        if (DesignerProperties.GetIsInDesignMode(AssociatedObject))
            return;

        var serviceLocator = ServiceLocator.Current;
        var navigationService = serviceLocator.GetInstance<IRegionManager>();

        if (navigationService != null)
            navigationService.RegisterRegion(RegionName, AssociatedObject);
    }
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню