Prism / Unity: не удается перейти к всплывающему региону - PullRequest
0 голосов
/ 09 марта 2020

У меня есть приложение Prism 6.3 / Unity WPF, которое будет искать установленные сканеры после запуска и представлять пользователю сообщение, когда его нет. Для представления сообщения в моем представлении оболочки есть специальный регион, который обычно свернут:

Shell.xaml

    <Grid Grid.ColumnSpan="3" Grid.RowSpan="3" Panel.ZIndex="2" Visibility="{Binding MessageVisibility}" 
          fade:VisibilityAnimation.AnimationType="Fade">
        <Grid.RowDefinitions>
            <RowDefinition Height="15*"/>
            <RowDefinition Height="70*"/>
            <RowDefinition Height="15*"/>
        </Grid.RowDefinitions>

        <Rectangle Grid.Row="0" Fill="{DynamicResource AccentColorBrush2}"/>
        <ContentControl Grid.Row="1" prism:RegionManager.RegionName="{x:Static local:RegionNames.PopUpRegionName}"/>
        <Rectangle Grid.Row="2" Fill="{DynamicResource AccentColorBrush2}"/>
    </Grid>

Когда создается сообщение, агрегатор событий запускает событие, подобное этому

_eventAggregator.GetEvent<ShowMessage>().Publish(message);

, и ShellViewModel прослушивает это событие следующим образом:

ShellViewModel Конструктор и метод

_eventAggregator.GetEvent<ShowMessage>().Subscribe(ReceiveMessage);

public void ReceiveMessage(Models.Message message)
{
    _regionManager.RequestNavigate(RegionNames.PopUpRegionName, "MessageView");
    MessageVisibility = Visibility.Visible;
}

После этого выскакивает область сообщения и сообщение представляется пользователю.

Загрузчик:

public class Bootstrapper : UnityBootstrapper
{
    public override void Run(bool runWithDefaultConfiguration)
    {
        base.Run(runWithDefaultConfiguration);

        (Container.Resolve(typeof(ScanViewModel)) as ScanViewModel).InitializeTwain();
    }

    protected override System.Windows.DependencyObject CreateShell()
    {
        return Container.Resolve(typeof(Shell), "Shell") as DependencyObject;
    }

    protected override void InitializeShell()
    {
        base.InitializeShell();
        var mainWindow = (Shell)this.Shell;
        Application.Current.MainWindow = mainWindow;                       
        mainWindow.Show();
    }

    protected override void ConfigureServiceLocator()
    {
        base.ConfigureServiceLocator();
        Container.RegisterType<IEventAggregator, EventAggregator>(new ContainerControlledLifetimeManager());
        Container.RegisterType<IMessageViewModel, MessageViewModel>(new ContainerControlledLifetimeManager());
        Container.RegisterType<IFolderSelectionViewModel, FolderSelectionViewModel>(new ContainerControlledLifetimeManager());
        Container.RegisterType<IRegionManager, RegionManager>(new ContainerControlledLifetimeManager());

        var regionManager = Container.TryResolve<IRegionManager>();
        regionManager.RegisterViewWithRegion(RegionNames.PopUpRegionName, typeof(Views.MessageView));
        regionManager.RegisterViewWithRegion(RegionNames.PopUpRegionName, typeof(Views.FolderSelectionView));
    }
}

ScanViewModel InitializeTwain () метод

public void InitializeTwain()
{
        try
        {
            twain = new Twain(new WpfWindowMessageHook(Application.Current.MainWindow));
            SelectedScanner = null;
            Scanners = new ObservableCollection<string>();
            for (int i = 0; i < twain.SourceNames.Count; i++)
            {
                Scanners.Add(twain.SourceNames[i]);
            }

            if (Scanners.Count > 0)
                SelectedScanner = Scanners[0];
            else
                throw new TwainException();

            twain.ScanningComplete += Twain_ScanningComplete;

            twain.TransferImage += delegate (object sender, TransferImageEventArgs args)
            {
                if (args.Image != null)
                {
                    resultImage = args.Image;
                    images.Add(resultImage);
                }
            };
            canScan = true;
            ((DelegateCommand)ScanCommand).RaiseCanExecuteChanged();
        }
        catch (TwainException)
        {
            canScan = false;
            ((DelegateCommand)ScanCommand).RaiseCanExecuteChanged();
            Message = new Models.Message("TwainException", "No TWAIN compatible scanner could be found.");
            // _eventAggregator.GetEvent<ShowMessage>().Publish(message) gets called here
        }
    }

Моя проблема:

Когда я вызываю метод InitializeTwain () в методе Run () программы начальной загрузки и сообщение о том, что нет присутствующий сканер должен отображаться пользователю, PopupRegion НЕ отображается, а лежит в основе ScanView. И я не могу ничего щелкнуть в ScanView, поэтому что-то скрывает это.

Когда я удаляю вызов InitializeTwain () из метода Run () загрузчика, создаю кнопку для его вызова и нажимаю ее после приложения загружено, сообщение отображается правильно.

Чего мне не хватает?

РЕДАКТИРОВАТЬ: кажется, что-то не так с определением fade:VisibilityAnimation.AnimationType="Fade" в Shell.xaml. Пространство имен исчезновения указывает на VisibilityAnimation.cs, и это следующее:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media.Animation;

namespace Sdadv.CeDis.Wpf.DependencyProperties
{
    /// <summary>
    /// Code from: http://blogs.microsoft.co.il/arik/2010/02/08/wpf-how-to-animate-visibility-property/
    /// </summary>
    public class VisibilityAnimation
    {
        public enum AnimationType
        {
            /// <summary>
            /// No animation
            /// </summary>
            None,

            /// <summary>
            /// Fade in / Fade out
            /// </summary>
            Fade
        }

        /// <summary>
        /// Animation duration
        /// </summary>
        private const int AnimationDuration = 200;

        /// <summary>
        /// List of hooked objects
        /// </summary>
        private static readonly Dictionary<FrameworkElement, bool> _hookedElements =
            new Dictionary<FrameworkElement, bool>();

        /// <summary>
        /// Get AnimationType attached property
        /// </summary>
        /// <param name=”obj”>Dependency object</param>
        /// <returns>AnimationType value</returns>
        public static AnimationType GetAnimationType(DependencyObject obj)
        {
            return (AnimationType)obj.GetValue(AnimationTypeProperty);
        }

        /// <summary>
        /// Set AnimationType attached property
        /// </summary>
        /// <param name=”obj”>Dependency object</param>
        /// <param name=”value”>New value for AnimationType</param>
        public static void SetAnimationType(DependencyObject obj, AnimationType value)
        {
            obj.SetValue(AnimationTypeProperty, value);
        }

        /// <summary>
        /// Using a DependencyProperty as the backing store for AnimationType. 
        /// This enables animation, styling, binding, etc…
        /// </summary>
        public static readonly DependencyProperty AnimationTypeProperty =
            DependencyProperty.RegisterAttached(
                "AnimationType",
                typeof(AnimationType),
                typeof(VisibilityAnimation),
                new FrameworkPropertyMetadata(AnimationType.None,
                    new PropertyChangedCallback(OnAnimationTypePropertyChanged)));

        /// <summary>
        /// AnimationType property changed
        /// </summary>
        /// <param name=”dependencyObject”>Dependency object</param>
        /// <param name=”e”>e</param>
        private static void OnAnimationTypePropertyChanged(
            DependencyObject dependencyObject,
            DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement frameworkElement = dependencyObject as FrameworkElement;

            if (frameworkElement == null)
            {
                return;
            }

            // If AnimationType is set to True on this framework element, 
            if (GetAnimationType(frameworkElement) != AnimationType.None)
            {
                // Add this framework element to hooked list
                HookVisibilityChanges(frameworkElement);
            }
            else
            {
                // Otherwise, remove it from the hooked list
                UnHookVisibilityChanges(frameworkElement);
            }
        }

        /// <summary>
        /// Add framework element to list of hooked objects
        /// </summary>
        /// <param name=”frameworkElement”>Framework element</param>
        private static void HookVisibilityChanges(FrameworkElement frameworkElement)
        {
            _hookedElements.Add(frameworkElement, false);
        }

        /// <summary>
        /// Remove framework element from list of hooked objects
        /// </summary>
        /// <param name=”frameworkElement”>Framework element</param>
        private static void UnHookVisibilityChanges(FrameworkElement frameworkElement)
        {
            if (_hookedElements.ContainsKey(frameworkElement))
            {
                _hookedElements.Remove(frameworkElement);
            }
        }

        /// <summary>
        /// VisibilityAnimation static ctor
        /// </summary>
        static VisibilityAnimation()
        {
            // Here we “register” on Visibility property “before change” event
            UIElement.VisibilityProperty.AddOwner(
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(
                    Visibility.Visible,
                    VisibilityChanged,
                    CoerceVisibility));
        }

        /// <summary>
        /// Visibility changed
        /// </summary>
        /// <param name=”dependencyObject”>Dependency object</param>
        /// <param name=”e”>e</param>
        private static void VisibilityChanged(
            DependencyObject dependencyObject,
            DependencyPropertyChangedEventArgs e)
        {
            // Ignore
        }

        /// <summary>
        /// Coerce visibility
        /// </summary>
        /// <param name=”dependencyObject”>Dependency object</param>
        /// <param name=”baseValue”>Base value</param>
        /// <returns>Coerced value</returns>
        private static object CoerceVisibility(
            DependencyObject dependencyObject,
            object baseValue)
        {
            // Make sure object is a framework element
            FrameworkElement frameworkElement = dependencyObject as FrameworkElement;
            if (frameworkElement == null)
            {
                return baseValue;
            }

            // Cast to type safe value
            Visibility visibility = (Visibility)baseValue;

            // If Visibility value hasn’t change, do nothing.
            // This can happen if the Visibility property is set using data binding 
            // and the binding source has changed but the new visibility value 
            // hasn’t changed.
            if (visibility == frameworkElement.Visibility)
            {
                return baseValue;
            }

            // If element is not hooked by our attached property, stop here
            if (!IsHookedElement(frameworkElement))
            {
                return baseValue;
            }

            // Update animation flag
            // If animation already started, don’t restart it (otherwise, infinite loop)
            if (UpdateAnimationStartedFlag(frameworkElement))
            {
                return baseValue;
            }

            // If we get here, it means we have to start fade in or fade out animation. 
            // In any case return value of this method will be Visibility.Visible, 
            // to allow the animation.
            DoubleAnimation doubleAnimation = new DoubleAnimation
            {
                Duration = new Duration(TimeSpan.FromMilliseconds(AnimationDuration))
            };

            // When animation completes, set the visibility value to the requested 
            // value (baseValue)
            doubleAnimation.Completed += (sender, eventArgs) =>
            {
                if (visibility == Visibility.Visible)
                {
                    // In case we change into Visibility.Visible, the correct value 
                    // is already set, so just update the animation started flag
                    UpdateAnimationStartedFlag(frameworkElement);
                }
                else
                {
                    // This will trigger value coercion again 
                    // but UpdateAnimationStartedFlag() function will reture true 
                    // this time, thus animation will not be triggered. 
                    if (BindingOperations.IsDataBound(frameworkElement,
                        UIElement.VisibilityProperty))
                    {
                        // Set visiblity using bounded value
                        Binding bindingValue =
                            BindingOperations.GetBinding(frameworkElement,
                                UIElement.VisibilityProperty);
                        BindingOperations.SetBinding(frameworkElement,
                            UIElement.VisibilityProperty, bindingValue);
                    }
                    else
                    {
                        // No binding, just assign the value
                        frameworkElement.Visibility = visibility;
                    }
                }
            };

            if (visibility == Visibility.Collapsed || visibility == Visibility.Hidden)
            {
                // Fade out by animating opacity
                doubleAnimation.From = 1.0;
                doubleAnimation.To = 0.0;
            }
            else
            {
                // Fade in by animating opacity
                doubleAnimation.From = 0.0;
                doubleAnimation.To = 1.0;
            }

            // Start animation
            frameworkElement.BeginAnimation(UIElement.OpacityProperty, doubleAnimation);

            // Make sure the element remains visible during the animation
            // The original requested value will be set in the completed event of 
            // the animation
            return Visibility.Visible;
        }

        /// <summary>
        /// Check if framework element is hooked with AnimationType property
        /// </summary>
        /// <param name=”frameworkElement”>Framework element to check</param>
        /// <returns>Is the framework element hooked?</returns>
        private static bool IsHookedElement(FrameworkElement frameworkElement)
        {
            return _hookedElements.ContainsKey(frameworkElement);
        }

        /// <summary>
        /// Update animation started flag or a given framework element
        /// </summary>
        /// <param name=”frameworkElement”>Given framework element</param>
        /// <returns>Old value of animation started flag</returns>
        private static bool UpdateAnimationStartedFlag(FrameworkElement frameworkElement)
        {
            bool animationStarted = (bool)_hookedElements[frameworkElement];
            _hookedElements[frameworkElement] = !animationStarted;

            return animationStarted;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...