Browse Source

页面编辑-调整页面编辑图片刷新逻辑:UI发送事件通知给VM刷新图片

ZhouJieSheng 2 years ago
parent
commit
fcd794d9ca

+ 32 - 0
PDF Office/EventAggregators/PageEditRefreshEvent.cs

@@ -0,0 +1,32 @@
+using Prism.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PDF_Office.EventAggregators
+{
+    /// <summary>
+    /// Xaml用于通知页面编辑VM刷新图像的事件
+    /// </summary>
+    public class PageEditRefreshEvent: PubSubEvent<PageEditRefreshEventArgs>
+    {
+
+
+
+    }
+
+    public class PageEditRefreshEventArgs
+    {
+        /// <summary>
+        /// 避免触发其他页签的识别码
+        /// </summary>
+        public string Unicode { get; set; }
+
+        /// <summary>
+        /// 页码范围
+        /// </summary>
+        public Tuple<int,int,int> PageRange { get; set; }
+    }
+}

+ 1 - 0
PDF Office/PDF Office.csproj

@@ -114,6 +114,7 @@
     <Compile Include="CustomControl\ToastControl.xaml.cs">
       <DependentUpon>ToastControl.xaml</DependentUpon>
     </Compile>
+    <Compile Include="EventAggregators\PageEditRefreshEvent.cs" />
     <Compile Include="Model\DialogNames.cs" />
     <Compile Include="CustomControl\SystemControl\InterTabClient.cs" />
     <Compile Include="CustomControl\LoadingControl.xaml.cs">

+ 0 - 2
PDF Office/Styles/ListBoxStyle.xaml

@@ -9,8 +9,6 @@
             BorderThickness="{TemplateBinding BorderThickness}"
             SnapsToDevicePixels="True">
             <ContentPresenter
-                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
-                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                 Content="{TemplateBinding Content}"
                 ContentStringFormat="{TemplateBinding ContentStringFormat}"
                 ContentTemplate="{TemplateBinding ContentTemplate}"

+ 32 - 151
PDF Office/ViewModels/PageEdit/PageEditContentViewModel.cs

@@ -19,6 +19,8 @@ using System.Diagnostics;
 using System.Windows.Controls;
 using PDF_Office.Tools;
 using System.Windows.Threading;
+using Prism.Events;
+using PDF_Office.EventAggregators;
 
 namespace PDF_Office.ViewModels.PageEdit
 {
@@ -31,6 +33,8 @@ namespace PDF_Office.ViewModels.PageEdit
 
         private IDialogService dialogs;
 
+        private IEventAggregator eventor;
+
         /// <summary>
         /// 是否正在初始化所有列表项,正在初始化时,不刷新图片
         /// </summary>
@@ -44,6 +48,8 @@ namespace PDF_Office.ViewModels.PageEdit
         /// </summary>
         private DispatcherTimer timer = new DispatcherTimer();
 
+        private string unicode = null;
+
         #region 属性
         private Visibility isvisible;
 
@@ -57,19 +63,24 @@ namespace PDF_Office.ViewModels.PageEdit
         }
 
 
-        #endregion
-
-        #region 命令
+        private int selecedIndex;
         /// <summary>
-        /// 是否显示  事件
+        /// 选中项的索引
         /// </summary>
-        public DelegateCommand<object> IsVisibleChangedCommmand { get; set; }
+        public int SelectedIndex
+        {
+            get { return selecedIndex; }
+            set
+            {
+                SetProperty(ref selecedIndex, value);
+            }
+        }
+
 
-        public DelegateCommand<object> ScollChangedComamnd { get; set; }
+        #endregion
 
-        public DelegateCommand<object> ScrollCommand { get; set; }
+        #region 命令
 
-        public DelegateCommand LoadCommand { get; set; }
         #endregion
 
         /// <summary>
@@ -77,111 +88,25 @@ namespace PDF_Office.ViewModels.PageEdit
         /// </summary>
         public ObservableCollection<PageEditItem> PageEditItems { get; set; }
 
-        public PageEditContentViewModel(IDialogService dialogService)
+        public PageEditContentViewModel(IDialogService dialogService, IEventAggregator eventAggregator)
         {
             dialogs = dialogService;
+            eventor = eventAggregator;
+            unicode = App.mainWindowViewModel.SelectedItem.Unicode;
             PageEditItems = new ObservableCollection<PageEditItem>();
-            timer.Interval = TimeSpan.FromSeconds(0.2);
-            timer.Tick += Timer_Tick;
+            eventAggregator.GetEvent<PageEditRefreshEvent>().Subscribe(OnPageEditRefreshEvent, e=>e.Unicode== unicode);
 
-
-            IsVisibleChangedCommmand = new DelegateCommand<object>(IsVisibleChangedEvent);
-            ScollChangedComamnd = new DelegateCommand<object>(ScrollChanged);
-            ScrollCommand = new DelegateCommand<object>(ScrollEvent);
-            LoadCommand = new DelegateCommand(ControlLoad);
         }
 
 
         #region 事件
-        /// <summary>
-        /// 判断鼠标滚轮是否停止滚动的事件
-        /// </summary>
-        /// <param name="sender"></param>
-        /// <param name="e"></param>
-        private void Timer_Tick(object sender, EventArgs e)
-        {
-            if (PDFViewer != null && PDFViewer.Document != null)
-            {
-                timer.Stop();
-            }
-        }
-
-        /// <summary>
-        /// 鼠标滚轮滚动时触发的事件
-        /// </summary>
-        /// <param name="e"></param>
-        private void ScrollChanged(object e)
-        {
-            var args = (ScrollChangedEventArgs)e;
-            var scrollviewer = args.OriginalSource as ScrollViewer;
-            if (scrollviewer == null)
-                return;
-            if (args != null && PDFViewer != null)
-            {
-                //确保第一次所有item添加完之后再刷新图片
-                //鼠标拖动过程中不拿图
-                if (!isInitaling&& scrollType== ScrollEventType.EndScroll)
-                {
-                    //size是拿的DataTemplate的宽高
-                    var range = GetRoughFromView(scrollviewer, new Size(208, 320), new Thickness(5, 10, 5, 10));
-                    RefreshItemImage(range.Item1, range.Item2 + 1);
-                    RefreshBookMarkList();
-                }
-                else//其余滚动的时候,只有滚动暂停后再刷图
-                {
-                    if (args.VerticalChange != 0)
-                    {
-                        timer.Start();
-                    }
-                }
-
-            }
-        }
-
-        /// <summary>
-        /// 拖动右侧滑块时触发的事件
-        /// </summary>
-        /// <param name="e"></param>
-        private void ScrollEvent(object e)
+        private void OnPageEditRefreshEvent(PageEditRefreshEventArgs e)
         {
-            var args = (ScrollEventArgs)e;
-            scrollType = args.ScrollEventType;
-            var scroll = CommonHelper.FindVisualParent<ScrollViewer>(args.OriginalSource as ScrollBar);
-            if(args!=null&&PDFViewer!=null&&scroll!=null)
-            {
-                if(scrollType == ScrollEventType.EndScroll)
-                {
-                    //size是拿的DataTemplate的宽高
-                    var range = GetRoughFromView(scroll, new Size(208, 320), new Thickness(5, 10, 5, 10));
-                    RefreshItemImage(range.Item1, range.Item2+1);
-                
-                }
-            }
+            //UI发送事件过来通知刷新图片时
+            //调整逻辑,前后预加载5页
+            RefreshItemImage(e.PageRange.Item1-5,e.PageRange.Item2+5);
         }
 
-        private void IsVisibleChangedEvent(object e)
-        {
-            var args = (DependencyPropertyChangedEventArgs)e;
-            if (args == null)
-                return;
-            if ((Visibility)args.NewValue == Visibility.Visible)
-            {
-                GetSourceItems();
-                RefreshBookMarkList();
-               
-            }
-        }
-
-        private void ControlLoad()
-        {
-
-        }
-
-
-        private void Load(object e)
-        {
-            Debug.Write("Loaded");
-        }
         #endregion
 
         /// <summary>
@@ -198,7 +123,6 @@ namespace PDF_Office.ViewModels.PageEdit
                 var pagesize = PDFViewer.Document.GetPageSize(i);
 
                 item.PageSize = $"{pagesize.Width}mm*{pagesize.Height} mm";
-                RefreshItemImage(i,i);
                 PageEditItems.Add(item);
             }
             isInitaling = false;
@@ -266,66 +190,23 @@ namespace PDF_Office.ViewModels.PageEdit
 
         /// <summary>
         /// 从其他页面导航过来的时候会触发
+        /// 考虑只有在页面编辑的时候会进行页面的删减,可以尝试逻辑优化:仅第一次进入页面编辑时重新刷新页面
         /// </summary>
         /// <param name="navigationContext"></param>
-        public async void OnNavigatedTo(NavigationContext navigationContext)
+        public void OnNavigatedTo(NavigationContext navigationContext)
         {
             navigationContext.Parameters.TryGetValue<ViewContentViewModel>(ParameterNames.ViewContentViewModel, out viewContentViewModel);
             navigationContext.Parameters.TryGetValue<CPDFViewer>(ParameterNames.PDFViewer, out PDFViewer);
             if (PDFViewer != null)
             {
                 PDFViewer.OnThumbnailGenerated += PDFViewer_OnThumbnailGenerated;
-                //每次进入前 更新item项,刷新书签列表
-                await Task.Run(() =>
-                {
-                    App.Current.Dispatcher.Invoke(() =>
-                    {
-                        GetSourceItems();
-                    });
-                });
-                RefreshBookMarkList();
-            }
-        }
-        #endregion
 
-        /// <summary>
-        /// 获取滑轨的垂直偏移量,结合item总数和Item尺寸以及间隔,来估算实际展示的item范围
-        /// 返回值为页面范围  从1开始
-        /// </summary>
-        /// <param name="scrollViewer"></param>
-        /// <param name="itemSize"></param>
-        /// <param name="itemMargin"></param>
-        /// <returns></returns>
-        private Tuple<int, int, int> GetRoughFromView(ScrollViewer scrollViewer, Size itemSize, Thickness itemMargin)
-        {
-            if (PDFViewer == null || PDFViewer.Document == null || scrollViewer == null || scrollViewer.ActualHeight == 0 || scrollViewer.ActualWidth == 0|| scrollViewer.ExtentHeight==0)//视图展开
-                return new Tuple<int, int, int>(0, 0, 0);
-            try
-            {
-                var currentHeight = scrollViewer.ActualHeight;
-                var currentWidth = scrollViewer.ActualWidth;
-                //计算当前窗口大小能显示的行数和列数
-                var columnCount = (int)(currentWidth / (itemSize.Width + itemMargin.Left));
-                var rowCount = (int)Math.Ceiling(currentHeight / (itemSize.Height + itemMargin.Bottom));
-
-                var preItemCount = (int)((scrollViewer.VerticalOffset / scrollViewer.ExtentHeight) * ((PDFViewer.Document.PageCount + columnCount - 1) / columnCount));//滑动百分比*行数 = 大概的垂直位置
-                preItemCount = preItemCount * columnCount;
-                var preEnd = (int)(((scrollViewer.VerticalOffset + scrollViewer.ActualHeight) / scrollViewer.ExtentHeight) * ((PDFViewer.Document.PageCount + columnCount - 1) / columnCount));
-                preEnd = preEnd * columnCount + columnCount - 1;
-
-                var middle = (int)Math.Ceiling(preItemCount + preEnd / 2d);
-
-                return new Tuple<int, int, int>(
-                    Math.Max(preItemCount, 0),
-                    Math.Min(PageEditItems.Count, preEnd),
-                    middle);
-            }
-            catch (Exception ex)
-            {
+                GetSourceItems();
 
+                RefreshBookMarkList();
             }
-            return new Tuple<int, int, int>(0, 0, 0);
         }
+        #endregion
 
         /// <summary>
         /// 从底层库获取对应页面的图片

+ 5 - 15
PDF Office/Views/PageEdit/PageEditContent.xaml

@@ -17,12 +17,11 @@
     d:DesignHeight="450"
     d:DesignWidth="800"
     prism:ViewModelLocator.AutoWireViewModel="True"
-    Visibility="{Binding IsVisible, Mode=TwoWay}"
+    IsVisibleChanged="PageEdit_IsVisibleChanged"
     mc:Ignorable="d">
     <UserControl.Resources>
         <ResourceDictionary>
             <convert:BoolToVisible x:Key="BoolToVisibleConvert" />
-
             <DataTemplate x:Key="PageEditListBoxItemTemplate" DataType="{x:Type pageedit:PageEditItem}">
                 <Grid Height="320">
                     <Border
@@ -101,12 +100,16 @@
                 <StackPanel Name="StkpnlRight" />
             </Grid>
             <ListBox
+                Name="ListPageEdit"
                 Grid.Row="1"
                 Padding="0"
                 AllowDrop="True"
                 ItemTemplate="{StaticResource PageEditListBoxItemTemplate}"
                 ItemsSource="{Binding PageEditItems}"
+                ScrollBar.Scroll="ListPageEdit_Scroll"
                 ScrollViewer.CanContentScroll="True"
+                ScrollViewer.ScrollChanged="ListPageEdit_ScrollChanged"
+                SelectedIndex="{Binding SelectedIndex}"
                 SelectionMode="Extended"
                 VirtualizingPanel.CacheLength="1"
                 VirtualizingPanel.CacheLengthUnit="Page"
@@ -124,20 +127,7 @@
                         <wpftk:VirtualizingWrapPanel />
                     </ItemsPanelTemplate>
                 </ListBox.ItemsPanel>
-                <i:Interaction.Triggers>
-                    <cussys:RoutedEventTrigger RoutedEvent="ScrollViewer.ScrollChanged">
-                        <i:InvokeCommandAction Command="{Binding ScollChangedComamnd}" PassEventArgsToCommand="True" />
-                    </cussys:RoutedEventTrigger>
-                    <cussys:RoutedEventTrigger RoutedEvent="ScrollBar.Scroll">
-                        <i:InvokeCommandAction Command="{Binding ScrollCommand}" PassEventArgsToCommand="True" />
-                    </cussys:RoutedEventTrigger>
-                </i:Interaction.Triggers>
             </ListBox>
         </Grid>
-        <i:Interaction.Triggers>
-            <i:EventTrigger EventName="Loaded">
-                <i:InvokeCommandAction Command="{Binding LoadCommand}" />
-            </i:EventTrigger>
-        </i:Interaction.Triggers>
     </Border>
 </UserControl>

+ 141 - 1
PDF Office/Views/PageEdit/PageEditContent.xaml.cs

@@ -1,4 +1,6 @@
-using Prism.Events;
+using PDF_Office.EventAggregators;
+using PDF_Office.Tools;
+using Prism.Events;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -6,6 +8,7 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Windows;
 using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
 using System.Windows.Data;
 using System.Windows.Documents;
 using System.Windows.Input;
@@ -13,6 +16,7 @@ using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
+using System.Windows.Threading;
 
 namespace PDF_Office.Views.PageEdit
 {
@@ -21,6 +25,32 @@ namespace PDF_Office.Views.PageEdit
     /// </summary>
     public partial class PageEditContent : UserControl
     {
+        /// <summary>
+        /// 用于通知刷新图片的事件
+        /// 因为目前的图片刷新策略依赖很多UI事件判断,因为将主要判断逻辑放在UI层,VM负责图片刷新,非必要情况尽量不要采用这种形式
+        /// </summary>
+        private IEventAggregator eventor;
+
+        /// <summary>
+        /// 暂存的唯一索引值,用于区分多页签
+        /// </summary>
+        private string unicode;
+
+        /// <summary>
+        /// 是否是加载时第一次触发滚动
+        /// </summary>
+        private bool isFirstScrollChange = true;
+
+        /// <summary>
+        /// 用于判断滚轮停止的计时器
+        /// </summary>
+        private DispatcherTimer timer = new DispatcherTimer();
+
+        /// <summary>
+        /// 记录当前滑块的状态
+        /// </summary>
+        private ScrollEventType scrolltype = ScrollEventType.EndScroll;
+
         public PageEditContent()
         {
             InitializeComponent();
@@ -29,7 +59,17 @@ namespace PDF_Office.Views.PageEdit
 
         public PageEditContent(IEventAggregator eventAggregator) :this()
         {
+            eventor = eventAggregator;
+            unicode = App.mainWindowViewModel.SelectedItem.Unicode;
 
+            timer.Interval = TimeSpan.FromSeconds(0.3);
+            timer.Tick += Timer_Tick;
+        }
+
+        private void Timer_Tick(object sender, EventArgs e)
+        {
+            PulishEvent();
+            timer.Stop();
         }
 
 
@@ -40,7 +80,107 @@ namespace PDF_Office.Views.PageEdit
         /// <param name="e"></param>
         private void PageEdit_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
         {
+            if((bool)e.NewValue)
+            {
+                PulishEvent();
+            }
+        }
 
+        /// <summary>
+        /// 发布事件
+        /// </summary>
+        private void PulishEvent()
+        {
+            var range = GetRoughFromView(ListPageEdit, new Size(208, 320), new Thickness(5, 10, 5, 10));
+            eventor.GetEvent<PageEditRefreshEvent>().Publish(new PageEditRefreshEventArgs() { Unicode = unicode, PageRange = range });
+        }
+
+        /// <summary>
+        /// 获取滑轨的垂直偏移量,结合item总数和Item尺寸以及间隔,来估算实际展示的item范围
+        /// 返回值为页面范围  从1开始
+        /// </summary>
+        /// <param name="view"></param>
+        /// <param name="itemSize"></param>
+        /// <param name="itemMargin"></param>
+        /// <returns></returns>
+        private Tuple<int, int, int> GetRoughFromView(ListBox view, Size itemSize, Thickness itemMargin)
+        {
+            //var scrollViewer = GetScrollHost(view);
+            var scrollViewer = CommonHelper.FindVisualChild<ScrollViewer>(view);
+            if (scrollViewer == null || scrollViewer.ActualHeight == 0 || scrollViewer.ActualWidth == 0)//视图展开
+                return new Tuple<int, int, int>(0, 0, 0);
+            try
+            {
+                var currentHeight = scrollViewer.ActualHeight - view.Padding.Top;
+                var currentWidth = scrollViewer.ActualWidth;
+                //计算当前窗口大小能显示的行数和列数
+                var columnCount = (int)(currentWidth / (itemSize.Width + itemMargin.Left));
+                var rowCount = (int)Math.Ceiling(currentHeight / (itemSize.Height + itemMargin.Bottom));
+
+                var preItemCount = (int)((scrollViewer.VerticalOffset / scrollViewer.ExtentHeight) * ((view.Items.Count + columnCount - 1) / columnCount));//滑动百分比*行数 = 大概的垂直位置
+                preItemCount = preItemCount * columnCount;
+                var preEnd = (int)(((scrollViewer.VerticalOffset + scrollViewer.ActualHeight) / scrollViewer.ExtentHeight) * ((view.Items.Count + columnCount - 1) / columnCount));
+                preEnd = preEnd * columnCount + columnCount - 1;
+
+                var middle = (int)Math.Ceiling(preItemCount + preEnd / 2d);
+
+                return new Tuple<int, int, int>(
+                    Math.Max(preItemCount, 0),
+                    Math.Min(view.Items.Count, preEnd),
+                    middle);
+            }
+            catch (Exception ex)
+            {
+
+            }
+            return new Tuple<int, int, int>(0, 0, 0);
+        }
+
+        /// <summary>
+        /// 获取listbox里的ScrollViewer对象
+        /// 留意如果有重写ListBox对象,该方法可能无效
+        /// </summary>
+        /// <param name="listBox"></param>
+        /// <returns></returns>
+        private ScrollViewer GetScrollHost(ListBox listBox)
+        {
+            if (VisualTreeHelper.GetChildrenCount(listBox) > 0)
+            {
+                int s = VisualTreeHelper.GetChildrenCount(listBox);
+
+                Border border = VisualTreeHelper.GetChild(listBox, 0) as Border;
+                if (border != null)
+                {
+                    return VisualTreeHelper.GetChild(border, 0) as ScrollViewer;
+                }
+            }
+            return null;
+        }
+
+        private void ListPageEdit_ScrollChanged(object sender, ScrollChangedEventArgs e)
+        {
+            if (isFirstScrollChange)
+            {
+                PulishEvent();//第一次加载时触发的Scollchange 直接刷新界面,减少白板显示时间
+                isFirstScrollChange = false;
+                return;
+            }
+            else
+            {
+                if (e.VerticalChange != 0)
+                    timer.Start();//暂时找不到比较好的 判断Scroller停止的方法,先用计时器粗略判断
+            }
+        }
+
+        private void ListPageEdit_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
+        {
+            scrolltype = e.ScrollEventType;
+            if (scrolltype != System.Windows.Controls.Primitives.ScrollEventType.EndScroll)
+            {
+                timer.Stop();
+                return;
+            }
+            PulishEvent();
         }
     }
 }