PageEditContent.xaml.cs 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. using PDF_Office.EventAggregators;
  2. using PDF_Office.Helper;
  3. using PDF_Office.Model.PageEdit;
  4. using PDF_Office.ViewModels.PageEdit;
  5. using Prism.Events;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Threading.Tasks;
  11. using System.Windows;
  12. using System.Windows.Controls;
  13. using System.Windows.Controls.Primitives;
  14. using System.Windows.Data;
  15. using System.Windows.Documents;
  16. using System.Windows.Input;
  17. using System.Windows.Media;
  18. using System.Windows.Media.Imaging;
  19. using System.Windows.Navigation;
  20. using System.Windows.Shapes;
  21. using System.Windows.Threading;
  22. using WpfToolkit.Controls;
  23. namespace PDF_Office.Views.PageEdit
  24. {
  25. /// <summary>
  26. /// PageEditContent.xaml 的交互逻辑
  27. /// </summary>
  28. public partial class PageEditContent : UserControl
  29. {
  30. /// <summary>
  31. /// 用于通知刷新图片的事件
  32. /// 因为目前的图片刷新策略依赖很多UI事件判断,因为将主要判断逻辑放在UI层,VM负责图片刷新,非必要情况尽量不要采用这种形式
  33. /// </summary>
  34. private IEventAggregator eventor;
  35. /// <summary>
  36. /// 暂存的唯一索引值,用于区分多页签
  37. /// </summary>
  38. private string unicode;
  39. /// <summary>
  40. /// 是否是加载时第一次触发滚动
  41. /// </summary>
  42. private bool isFirstScrollChange = true;
  43. /// <summary>
  44. /// 用于判断滚轮停止的计时器
  45. /// </summary>
  46. private DispatcherTimer timer = new DispatcherTimer();
  47. /// <summary>
  48. /// 判断是否开始框选
  49. /// </summary>
  50. private bool startChoose = false;
  51. /// <summary>
  52. /// 框选的起始位置
  53. /// </summary>
  54. private Point starPosition = new Point();
  55. /// <summary>
  56. /// 记录当前滑块的状态
  57. /// </summary>
  58. private ScrollEventType scrolltype = ScrollEventType.EndScroll;
  59. //鼠标点击时在item中的位置 实现类似点哪拖哪的细节
  60. private double item_x;
  61. private double item_y;
  62. //插入标记代表的插入位置
  63. private int InsertIndex = -1;
  64. //拖动的Item
  65. private PageEditItem tempItem;
  66. ///鼠标是否停留在item前半部
  67. ///显示在前半部时,获取的index为实际索引值
  68. ///显示在后半部时,获取的index需要+1
  69. private bool isFrontHalf = false;
  70. /// <summary>
  71. /// 是否正在拖拽排序中,通过该变量避免单击触发拖动
  72. /// </summary>
  73. private bool isDraging = false;
  74. //是否正在从外部拖入文件
  75. private bool isDragingEnter = false;
  76. /// <summary>
  77. /// 是否需要自动滚动
  78. /// </summary>
  79. private bool needScroll = false;
  80. //自动滚动速度
  81. private int speed = 0;
  82. private PageEditContentViewModel viewModel;
  83. public PageEditContent()
  84. {
  85. InitializeComponent();
  86. }
  87. public PageEditContent(IEventAggregator eventAggregator) :this()
  88. {
  89. eventor = eventAggregator;
  90. unicode = App.mainWindowViewModel.SelectedItem.Unicode;
  91. timer.Interval = TimeSpan.FromSeconds(0.3);
  92. timer.Tick += Timer_Tick;
  93. viewModel = this.DataContext as PageEditContentViewModel;
  94. //订阅页面刷新事件
  95. eventor.GetEvent<PageEditNotifyEvent>().Subscribe(OneNotifyEvent, e => e.Unicode == unicode);
  96. }
  97. private void Timer_Tick(object sender, EventArgs e)
  98. {
  99. PulishEvent();
  100. timer.Stop();
  101. }
  102. private void OneNotifyEvent(PageEditNotifyEventArgs e)
  103. {
  104. if (e.Type == NotifyType.RefreshPage)
  105. {
  106. PulishEvent();
  107. }
  108. else
  109. {
  110. if (e.Type == NotifyType.SelectItems)
  111. {
  112. if (e.PageRange.Count == 1)
  113. {
  114. ListPageEdit.SelectedIndex = e.PageRange[0] - 1;
  115. ListPageEdit.ScrollIntoView(ListPageEdit.SelectedItem);
  116. }
  117. else
  118. {
  119. ListPageEdit.SelectedItems.Clear();
  120. for (int i = 0; i < e.PageRange.Count; i++)
  121. {
  122. ListPageEdit.SelectedItems.Add(ListPageEdit.Items[e.PageRange[i] - 1]);
  123. }
  124. }
  125. }
  126. }
  127. }
  128. #region UI事件
  129. /// <summary>
  130. /// 每次显示的时候就触发事件,刷新所有图片
  131. /// </summary>
  132. /// <param name="sender"></param>
  133. /// <param name="e"></param>
  134. private void PageEdit_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
  135. {
  136. if((bool)e.NewValue)
  137. {
  138. //当前页面没有发生变化时,刷新图片 这种情况下会拿两次图,需要留意
  139. PulishEvent();
  140. //当前页面发生变化时通过ScrollChanged事件来刷新图片
  141. isFirstScrollChange = true;
  142. }
  143. }
  144. /// <summary>
  145. /// 鼠标滚轮滚动时触发的事件
  146. /// </summary>
  147. /// <param name="sender"></param>
  148. /// <param name="e"></param>
  149. private void ListPageEdit_ScrollChanged(object sender, ScrollChangedEventArgs e)
  150. {
  151. if (isFirstScrollChange)
  152. {
  153. PulishEvent();//第一次加载时触发的Scollchange 直接刷新界面,减少白板显示时间
  154. isFirstScrollChange = false;
  155. return;
  156. }
  157. else
  158. {
  159. if (e.VerticalChange != 0)
  160. timer.Start();//暂时找不到比较好的 判断Scroller停止的方法,先用计时器粗略判断
  161. }
  162. }
  163. /// <summary>
  164. /// 拖动右侧滑块时触发的事件
  165. /// </summary>
  166. /// <param name="sender"></param>
  167. /// <param name="e"></param>
  168. private void ListPageEdit_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
  169. {
  170. scrolltype = e.ScrollEventType;
  171. if (scrolltype != System.Windows.Controls.Primitives.ScrollEventType.EndScroll)
  172. {
  173. timer.Stop();
  174. return;
  175. }
  176. PulishEvent();
  177. }
  178. #endregion
  179. #region 方法
  180. /// <summary>
  181. /// 发布事件
  182. /// </summary>
  183. private void PulishEvent()
  184. {
  185. var itemSize = (ListPageEdit.Items[0] as PageEditItem).ItemSize;
  186. var range = GetRoughFromView(ListPageEdit, itemSize, new Thickness(5, 10, 5, 10));
  187. eventor.GetEvent<PageEditRefreshEvent>().Publish(new PageEditRefreshEventArgs() { Unicode = unicode, PageRange = range });
  188. }
  189. /// <summary>
  190. /// 获取滑轨的垂直偏移量,结合item总数和Item尺寸以及间隔,来估算实际展示的item范围
  191. /// 返回值为页面范围 从1开始
  192. /// </summary>
  193. /// <param name="view"></param>
  194. /// <param name="itemSize"></param>
  195. /// <param name="itemMargin"></param>
  196. /// <returns></returns>
  197. private Tuple<int, int, int> GetRoughFromView(ListBox view, Size itemSize, Thickness itemMargin)
  198. {
  199. //var scrollViewer = GetScrollHost(view);
  200. var scrollViewer = CommonHelper.FindVisualChild<ScrollViewer>(view);
  201. if (scrollViewer == null || scrollViewer.ActualHeight == 0 || scrollViewer.ActualWidth == 0)//视图展开
  202. return new Tuple<int, int, int>(0, 0, 0);
  203. try
  204. {
  205. var currentHeight = scrollViewer.ActualHeight - view.Padding.Top;
  206. var currentWidth = scrollViewer.ActualWidth;
  207. //计算当前窗口大小能显示的行数和列数
  208. var columnCount = (int)(currentWidth / (itemSize.Width + itemMargin.Left));
  209. var rowCount = (int)Math.Ceiling(currentHeight / (itemSize.Height + itemMargin.Bottom));
  210. var preItemCount = (int)((scrollViewer.VerticalOffset / scrollViewer.ExtentHeight) * ((view.Items.Count + columnCount - 1) / columnCount));//滑动百分比*行数 = 大概的垂直位置
  211. preItemCount = preItemCount * columnCount;
  212. var preEnd = (int)(((scrollViewer.VerticalOffset + scrollViewer.ActualHeight) / scrollViewer.ExtentHeight) * ((view.Items.Count + columnCount - 1) / columnCount));
  213. preEnd = preEnd * columnCount + columnCount - 1;
  214. var middle = (int)Math.Ceiling(preItemCount + preEnd / 2d);
  215. return new Tuple<int, int, int>(
  216. Math.Max(preItemCount, 0),
  217. Math.Min(view.Items.Count, preEnd),
  218. middle);
  219. }
  220. catch { }
  221. return new Tuple<int, int, int>(0, 0, 0);
  222. }
  223. /// <summary>
  224. /// 获取listbox里的ScrollViewer对象
  225. /// 留意如果有重写ListBox对象,该方法可能无效
  226. /// </summary>
  227. /// <param name="listBox"></param>
  228. /// <returns></returns>
  229. private ScrollViewer GetScrollHost(ListBox listBox)
  230. {
  231. if (VisualTreeHelper.GetChildrenCount(listBox) > 0)
  232. {
  233. int s = VisualTreeHelper.GetChildrenCount(listBox);
  234. Border border = VisualTreeHelper.GetChild(listBox, 0) as Border;
  235. if (border != null)
  236. {
  237. return VisualTreeHelper.GetChild(border, 0) as ScrollViewer;
  238. }
  239. }
  240. return null;
  241. }
  242. #endregion
  243. /// <summary>
  244. /// 输入框显示时,自动获取焦点
  245. /// </summary>
  246. /// <param name="sender"></param>
  247. /// <param name="e"></param>
  248. private void TextBox_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
  249. {
  250. if((bool)e.NewValue)
  251. {
  252. (sender as Control).Focus();
  253. }
  254. }
  255. private void ListPageEdit_PreviewMouseMove(object sender, MouseEventArgs e)
  256. {
  257. try
  258. {
  259. if (e.LeftButton == MouseButtonState.Pressed)
  260. {
  261. //鼠标框选逻辑
  262. if (startChoose)
  263. {
  264. var position = e.GetPosition(ListPageEdit);
  265. if (position.X < 5 || position.X > ListPageEdit.ActualWidth - 5 || position.Y < 5 || position.Y > ListPageEdit.ActualHeight - 5)
  266. {
  267. startChoose = false;
  268. RectChoose.Visibility = Visibility.Collapsed;
  269. //暂时未想到靠近顶部和底部自动翻滚的好方法,只能先屏蔽这部分功能
  270. Mouse.Capture(null);
  271. return;
  272. }
  273. //矩形框内的item设为选中
  274. DoSelectItems();
  275. return;
  276. }
  277. //拖拽排序的逻辑
  278. var pos = e.GetPosition(ListPageEdit);
  279. if (pos.Y < 0 || pos.Y > ListPageEdit.ActualHeight)
  280. {
  281. LineInset.Visibility = Visibility.Collapsed;
  282. return;
  283. }
  284. HitTestResult result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  285. if (result == null)
  286. {
  287. return;
  288. }
  289. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  290. if (listBoxItem == null)
  291. {
  292. return;
  293. }
  294. isDragingEnter = false;
  295. tempItem = listBoxItem.DataContext as PageEditItem;
  296. var item_pos = e.GetPosition(listBoxItem);
  297. if (item_pos != null)
  298. {
  299. item_x = item_pos.X;
  300. item_y = item_pos.Y;
  301. }
  302. var scroll = GetScrollHost(ListPageEdit);
  303. string filename = Guid.NewGuid().ToString() + ".pdf";
  304. string tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), filename);
  305. System.IO.File.Create(tempPath);
  306. string[] files = new string[1];
  307. files[0] = tempPath;
  308. DataObject dataObj = new DataObject(DataFormats.FileDrop, files);
  309. DragDrop.DoDragDrop(ListPageEdit, dataObj, DragDropEffects.Copy);
  310. Mouse.Capture(ListPageEdit);
  311. return;
  312. }
  313. RectChoose.Visibility = Visibility.Collapsed;
  314. startChoose = false;
  315. Mouse.Capture(null);
  316. }
  317. catch
  318. {
  319. LineInset.Visibility = Visibility.Collapsed;
  320. }
  321. }
  322. /// <summary>
  323. /// 判断是否开始框选、记录框选起始位置
  324. /// </summary>
  325. /// <param name="sender"></param>
  326. /// <param name="e"></param>
  327. private void ListPageEdit_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  328. {
  329. var pos = e.GetPosition(ListPageEdit);
  330. HitTestResult result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  331. if (result == null)
  332. {
  333. return;
  334. }
  335. //未选中item 并且不是点击滑轨时 开始框选
  336. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  337. var scroller = CommonHelper.FindVisualParent<ScrollBar>(result.VisualHit);
  338. if (listBoxItem == null)
  339. {
  340. if (scroller != null)
  341. {
  342. startChoose = false;
  343. return;
  344. }
  345. //点击空白处时开始框选
  346. startChoose = true;
  347. if (ListPageEdit.SelectedItems.Count > 0)
  348. {
  349. ListPageEdit.SelectedItems.Clear();
  350. }
  351. starPosition = e.GetPosition(ListPageEdit);
  352. starPosition = new Point(starPosition.X, starPosition.Y + GetWrapPanel(ListPageEdit).VerticalOffset);
  353. Mouse.Capture(ListPageEdit);
  354. return;
  355. }
  356. //选中了item 时,不能框选
  357. startChoose = false;
  358. //更改系统的选中规则,选中状态下,鼠标松开后取消选中
  359. //方便实现多选拖拽功能
  360. if (listBoxItem.IsSelected == true && !Keyboard.IsKeyDown(Key.LeftCtrl))
  361. {
  362. e.Handled = true;
  363. }
  364. }
  365. private void ListPageEdit_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  366. {
  367. var pos = e.GetPosition(ListPageEdit);
  368. HitTestResult result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  369. if (result == null)
  370. {
  371. return;
  372. }
  373. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  374. if (listBoxItem == null)
  375. {
  376. return;
  377. }
  378. //更改系统默认的选中规则,多选后,鼠标单击抬起后再选中单个
  379. //拖拽框选之后的抬起鼠标不进入处理
  380. if (!startChoose&&!Keyboard.IsKeyDown(Key.LeftCtrl) && !Keyboard.IsKeyDown(Key.LeftShift))
  381. {
  382. ListPageEdit.SelectedItems.Clear();
  383. ListPageEdit.SelectedItem = listBoxItem;
  384. listBoxItem.IsSelected = true;
  385. return;
  386. }
  387. Mouse.Capture(null);
  388. //结束鼠标框选
  389. startChoose = false;
  390. RectChoose.Visibility = Visibility.Collapsed;
  391. }
  392. /// <summary>
  393. /// 获取Listobox的Wrappanel容器
  394. /// </summary>
  395. /// <param name="listBox"></param>
  396. /// <returns></returns>
  397. public VirtualizingWrapPanel GetWrapPanel(ListBox listBox)
  398. {
  399. Border border = VisualTreeHelper.GetChild(listBox, 0) as Border;
  400. var panel = CommonHelper.FindVisualChild<VirtualizingWrapPanel>(border);
  401. return panel;
  402. }
  403. /// <summary>
  404. ///根据鼠标拖选的框 选中矩形框里面的Item
  405. /// </summary>
  406. private void DoSelectItems()
  407. {
  408. var s = GetScrollHost(ListPageEdit);
  409. Point start = new Point();
  410. //通过 实时的垂直偏移量和第一次的偏移量抵消,来获取准确的垂直偏移值。
  411. start = new Point(starPosition.X, starPosition.Y - s.VerticalOffset);
  412. var rec = new Rect(start, Mouse.GetPosition(ListPageEdit));
  413. RectChoose.Margin = new Thickness(rec.Left, rec.Top, 0, 0);
  414. RectChoose.Width = rec.Width;
  415. RectChoose.Height = rec.Height;
  416. RectChoose.Visibility = Visibility.Visible;
  417. //检测遍历所有项,筛选在矩形框中的Item
  418. for (int i = 0; i < ListPageEdit.Items.Count; i++)
  419. {
  420. var _item = ListPageEdit.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
  421. //通过这一步来避免重复误选中
  422. var parent = CommonHelper.FindVisualParent<VirtualizingWrapPanel>(_item);
  423. if (parent == null)
  424. continue;
  425. var v = VisualTreeHelper.GetOffset(_item);
  426. if (rec.IntersectsWith(new Rect(v.X, v.Y, _item.ActualWidth, _item.ActualHeight)))
  427. {
  428. ListPageEdit.SelectedItems.Add(ListPageEdit.Items[i]);
  429. }
  430. else
  431. {
  432. ListPageEdit.SelectedItems.Remove(ListPageEdit.Items[i]);
  433. }
  434. }
  435. return;
  436. }
  437. /// <summary>
  438. /// 计算插入标记线和虚影显示
  439. /// </summary>
  440. /// <param name="sender"></param>
  441. /// <param name="e"></param>
  442. private void ListPageEdit_DragOver(object sender, DragEventArgs e)
  443. {
  444. try
  445. {
  446. //ctrl建按下 不显示插入标记和虚影 因为释放不会响应drop事件
  447. if (e.KeyStates == (DragDropKeyStates.ControlKey | DragDropKeyStates.LeftMouseButton) || e.KeyStates == (DragDropKeyStates.ShiftKey | DragDropKeyStates.LeftMouseButton | DragDropKeyStates.ControlKey))
  448. return;
  449. //滚动后有 位置不准确 要减去滚动偏移量
  450. //控制线的位置
  451. var pos = e.GetPosition(ListPageEdit);
  452. var result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  453. if (result == null)
  454. {
  455. //MidLane.Visibility = Visibility.Collapsed;
  456. //return;
  457. }
  458. //获取当前鼠标指针下的容器
  459. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  460. if (listBoxItem == null)
  461. {
  462. //MidLane.Visibility = Visibility.Collapsed;
  463. //return;
  464. }
  465. #region 计算虚影位置
  466. //xaml层 要设置 虚影控件为左上
  467. double xPos = 0;
  468. double yPos = 0;
  469. //内部拖动
  470. if (!isDragingEnter)
  471. {
  472. //Viewbox viewBox = (tempItem.Content as StackPanel).Children[0] as Viewbox;//获取item宽度
  473. ImgPicture.Width = tempItem.ItemSize.Width;
  474. ImgPicture.Height = tempItem.ItemSize.Height;
  475. ImgPicture.Source = tempItem.Image;
  476. xPos = e.GetPosition(ListPageEdit).X - item_x;
  477. yPos = e.GetPosition(ListPageEdit).Y - item_y;
  478. }
  479. //else
  480. //{
  481. // //从外部拖入的逻辑
  482. // //var pic = ToBitmapSource(dragingEnterPath);
  483. // //ShadowPicture.Width = pic.Width;
  484. // //ShadowPicture.Height = pic.Height;
  485. // //ShadowPicture.Source = pic;
  486. // //xPos = e.GetPosition(ListPageEdit).X - pic.Width / 2;
  487. // //yPos = e.GetPosition(ListPageEdit).Y - pic.Height / 2;
  488. //}
  489. ImgPicture.Margin = new Thickness(xPos, yPos, 0, 0);
  490. #endregion
  491. #region 计算插入标记位置
  492. var scroll = GetScrollHost(ListPageEdit);
  493. if (listBoxItem != null)
  494. {
  495. //虚拟化影响到该值计算
  496. var p = VisualTreeHelper.GetOffset(listBoxItem);//计算控件在容器中的偏移(位置)
  497. LineInset.Visibility = Visibility.Visible;
  498. var panel = GetWrapPanel(ListPageEdit);
  499. var item = (ListPageEdit.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem).DesiredSize.Width;
  500. int count = (int)(panel.ViewportWidth / item);
  501. var gap = (panel.ViewportWidth - count * item) / (count + 1) * 1.0;
  502. LineInset.X2 = LineInset.X1 = p.X + gap / 2 + listBoxItem.DesiredSize.Width;
  503. if (pos.X < p.X + gap / 2 + listBoxItem.ActualWidth / 2)
  504. {
  505. isFrontHalf = true;//前半部 线条出现在位置前
  506. LineInset.X2 = LineInset.X1 = p.X - gap / 2;
  507. InsertIndex = ListPageEdit.Items.IndexOf(listBoxItem);
  508. }
  509. else
  510. {
  511. isFrontHalf = false;
  512. InsertIndex = ListPageEdit.Items.IndexOf(listBoxItem) + 1;
  513. }
  514. //MidLane.Y1 = p.Y - scroll.VerticalOffset;//向下滑动后要减去滑动值
  515. LineInset.Y1 = p.Y;
  516. if (LineInset.Y1 < 0)//避免超出上边界
  517. {
  518. LineInset.Y1 = 0;
  519. }
  520. //MidLane.Y2 = p.Y + listBoxItem.ActualHeight - scroll.VerticalOffset;//仿智能滚动后可能会导致 垂直滚动偏量不准确
  521. LineInset.Y2 = p.Y + listBoxItem.ActualHeight;
  522. if (LineInset.Y2 < 0)
  523. {
  524. LineInset.Y2 = 0;
  525. }
  526. }
  527. #endregion
  528. //暂时处理 鼠标移出边框时,虚影的显示问题
  529. if (pos.Y <= 30 || pos.Y >= ListPageEdit.ActualHeight - 10)
  530. {
  531. LineInset.Visibility = Visibility.Collapsed;
  532. needScroll = false;
  533. }
  534. if (pos.X <= 40 || pos.X >= scroll.ViewportWidth - 50)
  535. {
  536. LineInset.Visibility = Visibility.Collapsed;
  537. needScroll = false;
  538. }
  539. #region 靠近上下边界时,自动滚动,离边界越近,滚动速度越快
  540. //speed = 0;
  541. //if (pos.Y >= PageEditListBox.ActualHeight - 30)
  542. //{
  543. // speed = 30 - (int)(PageEditListBox.ActualHeight - pos.Y);
  544. // needScroll = true;
  545. //}
  546. //else if (pos.Y <= 30)
  547. //{
  548. // speed = (int)(pos.Y - 30);
  549. // needScroll = true;
  550. //}
  551. //else
  552. // needScroll = false;
  553. //var v = scroll.VerticalOffset;
  554. //scroll.ScrollToVerticalOffset(v + speed);//触发连续滚动
  555. #endregion
  556. }
  557. catch (Exception ex)
  558. {
  559. }
  560. }
  561. /// <summary>
  562. /// 退出拖拽模式
  563. /// </summary>
  564. private void ExitDraging()
  565. {
  566. LineInset.Visibility = Visibility.Collapsed;
  567. isDraging = false;
  568. }
  569. /// <summary>
  570. /// 拖拽释放后的处理逻辑
  571. /// </summary>
  572. /// <param name="sender"></param>
  573. /// <param name="e"></param>
  574. private void ListPageEdit_Drop(object sender, DragEventArgs e)
  575. {
  576. needScroll = false;
  577. if (!isDraging)
  578. {
  579. //未拖拽时隐藏插入标记和虚影
  580. LineInset.Visibility = Visibility.Collapsed;
  581. return;
  582. }
  583. #region 功能付费锁
  584. // //if (!App.IsActive())
  585. // //{
  586. // // MidLane.Visibility = Visibility.Collapsed;
  587. // // IAPFunctionDialog dialog = new IAPFunctionDialog("PageEdit");
  588. // // dialog.ShowDialog();
  589. // // return;
  590. // //}
  591. #endregion
  592. #region 从外部拖拽插入文件
  593. //if (isDragingEnter)
  594. //{
  595. // //在当前位置插入整个pdf
  596. // CPDFDocument dragDoc = CPDFDocument.InitWithFilePath(dragingEnterPath);
  597. // if (dragDoc.IsLocked)
  598. // {
  599. // VerifyPasswordDialog dialog = new VerifyPasswordDialog(dragDoc);
  600. // dialog.ShowDialog();
  601. // if (dragDoc.IsLocked)
  602. // return;
  603. // }
  604. // if (dragingEnterPath.Substring(dragingEnterPath.LastIndexOf(".")).ToLower() == ".pdf")
  605. // {
  606. // if (dragDoc != null)
  607. // {
  608. // int index = InsertIndex == -1 ? 0 : InsertIndex;
  609. // pdfViewer.Document.ImportPagesAtIndex(dragDoc, "1-" + dragDoc.PageCount, index);
  610. // PopulateThumbnailList();
  611. // ItemsInViewHitTest();
  612. // pdfViewer.UndoManager.ClearHistory();
  613. // pdfViewer.UndoManager.CanSave = true;
  614. // pdfViewer.ReloadDocument();
  615. // PageEditListBox.ScrollIntoView(PageEditListBox.SelectedItem as ListBoxItem);
  616. // PageMoved.Invoke(this, new RoutedEventArgs());
  617. // PDFViewerCtrl viewerCtrl = ParentPage?.GetCurrentViewer();
  618. // if (viewerCtrl != null)
  619. // {
  620. // viewerCtrl.IsPageEdit = true;
  621. // }
  622. // dragDoc.Release();
  623. // }
  624. // else
  625. // {
  626. // MessageBoxEx.Show(App.MainPageLoader.GetString("Merge_FileCannotOpenedWarningd"));
  627. // }
  628. // //提示文档损坏无法打开
  629. // }
  630. // else if (!string.IsNullOrEmpty(dragingEnterPath))
  631. // {
  632. // //其他文件 则新增一个页签打开
  633. // // DragAddTab.Invoke(dragingEnterPath, new RoutedEventArgs());//底层库需要加一个 Load(TPDFDocument)的接口
  634. // }
  635. // MidLane.Visibility = Visibility.Collapsed;
  636. // isDragingEnter = false;
  637. // dragingEnterPath = null;
  638. // return;
  639. //}
  640. #endregion
  641. var pos = e.GetPosition(ListPageEdit);
  642. var result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  643. if (result == null)
  644. {
  645. //超出当前可控区域
  646. ExitDraging();
  647. return;
  648. }
  649. //查找元数据
  650. var sourcePerson = e.Data.GetData(typeof(StackPanel)) as StackPanel;
  651. if (sourcePerson == null)
  652. {
  653. ExitDraging();
  654. return;
  655. }
  656. //查找目标数据
  657. int targetindex = 0;//目标插入位置
  658. if (InsertIndex != -1)
  659. {
  660. //往前移动时 此index 不是准确的,需要处理++
  661. targetindex = InsertIndex;
  662. }
  663. else//基本不会命中 仅作为保险措施
  664. {
  665. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  666. if (listBoxItem == null)
  667. {
  668. ////鼠标停留在两个item之间或其他无效区域 暂时不做处理(比较麻烦)
  669. ExitDraging();
  670. return;
  671. }
  672. var targetPerson = listBoxItem;
  673. targetPerson.Opacity = 1;
  674. sourcePerson.Opacity = 1;
  675. if (ReferenceEquals(targetPerson, sourcePerson))
  676. {
  677. ExitDraging();
  678. return;
  679. }
  680. targetindex = ListPageEdit.Items.IndexOf(targetPerson);
  681. }
  682. List<ListBoxItem> list = new List<ListBoxItem>();
  683. List<int> sourceindex = new List<int>();//需要保存每个页面对应的位置
  684. //开始排序
  685. List<int> pages = new List<int>();
  686. //要先对所有选中项 根据页码排序
  687. for (int i = 0; i < ListPageEdit.SelectedItems.Count; i++)
  688. {
  689. var pageindex = ListPageEdit.Items.IndexOf(ListPageEdit.SelectedItems[i] as ListBoxItem);
  690. pages.Add(pageindex);//存入的为页码索引值
  691. }
  692. pages.Sort();
  693. if (pages.Count <= 0)
  694. {
  695. ExitDraging();
  696. return;
  697. }
  698. //要考虑每一次交换都会导致局部页码发生改变
  699. //每次整体往后移动时,先移动大页码;整体往前移动时,先移动小页码;往中间移动时,再按上述两种情况分别移动
  700. //if (targetindex <= pages[0])// 目标位置在所有选中内容左边,整体前移动 优先先判断左移的情况
  701. //{
  702. // sourceindex.Add(-1);
  703. // list = new List<ListBoxItem>();
  704. // for (int i = 0; i < pages.Count; i++)
  705. // {
  706. // list.Add(PageEditListBox.Items[pages[i]] as ListBoxItem);
  707. // sourceindex.Add(pages[i]);
  708. // DragToSort(pages[i], targetindex + i);
  709. // }
  710. //}
  711. //else if (targetindex > pages[pages.Count - 1])//目标位置在所有选中内容右边 整体后移
  712. //{
  713. // sourceindex.Add(1);
  714. // list = new List<ListBoxItem>();
  715. // for (int i = 0; i < pages.Count; i++)
  716. // {
  717. // list.Add(PageEditListBox.Items[pages[pages.Count - 1 - i]] as ListBoxItem);
  718. // sourceindex.Add(pages[pages.Count - 1 - i]);
  719. // DragToSort(pages[pages.Count - 1 - i], targetindex - 1 - i/* + (PageEditListBox.SelectedItems.Count - 1 - i)*/);
  720. // }
  721. //}
  722. //else//目标位置在所有选中项中间
  723. //{
  724. // int i, j, k;
  725. // for (k = 0; k < pages.Count - 1; k++)//找出PageEditListBox.Items中页码等于destpage的下标
  726. // {
  727. // //这里要算入K---即前面部分的页面个数
  728. // if (pages[k] < targetindex && pages[k + 1] >= targetindex)
  729. // break;
  730. // }
  731. // sourceindex.Add(0);
  732. // list = new List<ListBoxItem>();
  733. // for (i = 0; i <= k; i++)//局部往后移动
  734. // {
  735. // list.Add(PageEditListBox.Items[pages[k - i]] as ListBoxItem);
  736. // sourceindex.Add(pages[k - i]);
  737. // DragToSort(pages[k - i], targetindex - 1 - i);
  738. // }
  739. // for (j = i; j < pages.Count; j++)//局部往前移动
  740. // {
  741. // list.Add(PageEditListBox.Items[pages[j]] as ListBoxItem);
  742. // sourceindex.Add(pages[j]);
  743. // DragToSort(pages[j], targetindex);
  744. // targetindex++;
  745. // }
  746. // sourceindex.Add(k);//往中间移时, index数组的最后一位 表示 间隔位置K
  747. //}
  748. isDraging = false;
  749. }
  750. private void MidLane_Drop(object sender, DragEventArgs e)
  751. {
  752. ListPageEdit_Drop(sender, e);
  753. }
  754. private void ImgPicture_Drop(object sender, DragEventArgs e)
  755. {
  756. ListPageEdit_Drop(sender, e);
  757. }
  758. /// <summary>
  759. /// 拖拽事件写在外部的Grid里,会更加流畅
  760. /// </summary>
  761. /// <param name="sender"></param>
  762. /// <param name="e"></param>
  763. private void Grid_DragOver(object sender, DragEventArgs e)
  764. {
  765. try
  766. {
  767. //ctrl建按下 不显示插入标记和虚影 因为释放不会响应drop事件
  768. if (e.KeyStates == (DragDropKeyStates.ControlKey | DragDropKeyStates.LeftMouseButton) || e.KeyStates == (DragDropKeyStates.ShiftKey | DragDropKeyStates.LeftMouseButton | DragDropKeyStates.ControlKey))
  769. return;
  770. //滚动后有 位置不准确 要减去滚动偏移量
  771. //控制线的位置
  772. var pos = e.GetPosition(ListPageEdit);
  773. var result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  774. if (result == null)
  775. {
  776. //MidLane.Visibility = Visibility.Collapsed;
  777. //return;
  778. }
  779. //获取当前鼠标指针下的容器
  780. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  781. if (listBoxItem == null)
  782. {
  783. //MidLane.Visibility = Visibility.Collapsed;
  784. //return;
  785. }
  786. #region 计算虚影位置
  787. //xaml层 要设置 虚影控件为左上
  788. double xPos = 0;
  789. double yPos = 0;
  790. //内部拖动
  791. if (!isDragingEnter)
  792. {
  793. //Viewbox viewBox = (tempItem.Content as StackPanel).Children[0] as Viewbox;//获取item宽度
  794. ImgPicture.Width = tempItem.ItemSize.Width;
  795. ImgPicture.Height = tempItem.ItemSize.Height;
  796. ImgPicture.Source = tempItem.Image;
  797. xPos = e.GetPosition(ListPageEdit).X - item_x;
  798. yPos = e.GetPosition(ListPageEdit).Y - item_y;
  799. }
  800. //else
  801. //{
  802. // //从外部拖入的逻辑
  803. // //var pic = ToBitmapSource(dragingEnterPath);
  804. // //ShadowPicture.Width = pic.Width;
  805. // //ShadowPicture.Height = pic.Height;
  806. // //ShadowPicture.Source = pic;
  807. // //xPos = e.GetPosition(ListPageEdit).X - pic.Width / 2;
  808. // //yPos = e.GetPosition(ListPageEdit).Y - pic.Height / 2;
  809. //}
  810. ImgPicture.Margin = new Thickness(xPos, yPos, 0, 0);
  811. #endregion
  812. #region 计算插入标记位置
  813. var scroll = GetScrollHost(ListPageEdit);
  814. if (listBoxItem != null)
  815. {
  816. //虚拟化影响到该值计算
  817. var p = VisualTreeHelper.GetOffset(listBoxItem);//计算控件在容器中的偏移(位置)
  818. LineInset.Visibility = Visibility.Visible;
  819. var panel = GetWrapPanel(ListPageEdit);
  820. //var item = panel.ItemSize.Width;
  821. //var item = (ListPageEdit.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem).DesiredSize.Width;
  822. var item = listBoxItem.DesiredSize.Width;
  823. int count = (int)(panel.ViewportWidth / item);
  824. var gap = (panel.ViewportWidth - count * item) / (count + 1) * 1.0;
  825. LineInset.X2 = LineInset.X1 = p.X + gap / 2 + listBoxItem.DesiredSize.Width;
  826. if (pos.X < p.X + gap / 2 + listBoxItem.ActualWidth / 2)
  827. {
  828. isFrontHalf = true;//前半部 线条出现在位置前
  829. LineInset.X2 = LineInset.X1 = p.X - gap / 2;
  830. InsertIndex = ListPageEdit.Items.IndexOf(listBoxItem);
  831. }
  832. else
  833. {
  834. isFrontHalf = false;
  835. InsertIndex = ListPageEdit.Items.IndexOf(listBoxItem) + 1;
  836. }
  837. //MidLane.Y1 = p.Y - scroll.VerticalOffset;//向下滑动后要减去滑动值
  838. LineInset.Y1 = p.Y;
  839. if (LineInset.Y1 < 0)//避免超出上边界
  840. {
  841. LineInset.Y1 = 0;
  842. }
  843. //MidLane.Y2 = p.Y + listBoxItem.ActualHeight - scroll.VerticalOffset;//仿智能滚动后可能会导致 垂直滚动偏量不准确
  844. LineInset.Y2 = p.Y + listBoxItem.ActualHeight;
  845. if (LineInset.Y2 < 0)
  846. {
  847. LineInset.Y2 = 0;
  848. }
  849. }
  850. #endregion
  851. //暂时处理 鼠标移出边框时,虚影的显示问题
  852. if (pos.Y <= 30 || pos.Y >= ListPageEdit.ActualHeight - 10)
  853. {
  854. LineInset.Visibility = Visibility.Collapsed;
  855. needScroll = false;
  856. }
  857. if (pos.X <= 40 || pos.X >= scroll.ViewportWidth - 50)
  858. {
  859. LineInset.Visibility = Visibility.Collapsed;
  860. needScroll = false;
  861. }
  862. #region 靠近上下边界时,自动滚动,离边界越近,滚动速度越快
  863. speed = 0;
  864. if (pos.Y >= ListPageEdit.ActualHeight - 30)
  865. {
  866. speed = 30 - (int)(ListPageEdit.ActualHeight - pos.Y);
  867. needScroll = true;
  868. }
  869. else if (pos.Y <= 30)
  870. {
  871. speed = (int)(pos.Y - 30);
  872. needScroll = true;
  873. }
  874. else
  875. needScroll = false;
  876. var v = scroll.VerticalOffset;
  877. scroll.ScrollToVerticalOffset(v + speed);//触发连续滚动
  878. #endregion
  879. }
  880. catch
  881. {
  882. }
  883. }
  884. private void ListBoxItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  885. {
  886. //e.Handled = true;
  887. }
  888. private void ListBoxItem_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
  889. {
  890. if(e.ChangedButton== MouseButton.Left)
  891. {
  892. //双击回到PDFViewer界面
  893. var item = sender as ListBoxItem;
  894. if (item != null)
  895. {
  896. var index = ListPageEdit.ItemContainerGenerator.IndexFromContainer(item);
  897. //双击事件无法绑定Command 暂时采用这种方式调用VM里的方法
  898. viewModel.BackToPDFViewer(index);
  899. }
  900. }
  901. }
  902. private void PageEdit_SizeChanged(object sender, SizeChangedEventArgs e)
  903. {
  904. //BOTA缩略图模式下需要调整Item宽度
  905. if (GridBOTAHeader.Visibility == Visibility.Visible)
  906. {
  907. ItemSuitAcutalWidth(e.NewSize.Width);
  908. }
  909. }
  910. private void ItemSuitAcutalWidth(double width)
  911. {
  912. //缩略图模式下,保持一列或者两列显示
  913. if ((bool)TbnTwoLine.IsChecked)
  914. {
  915. var itemwidth = (width - 80) / 2;
  916. var itemHeight = 294 * itemwidth / 208.0;
  917. viewModel.ChangeItemSize(new Size(itemwidth, itemHeight));
  918. }
  919. else
  920. {
  921. var itemwidth = 0.6 * width;
  922. var itemheight = 294 * itemwidth / 208.0;
  923. viewModel.ChangeItemSize(new Size(itemwidth,itemheight));
  924. }
  925. }
  926. private void TbnTwoLine_Click(object sender, RoutedEventArgs e)
  927. {
  928. ItemSuitAcutalWidth(this.ActualWidth);
  929. }
  930. }
  931. }