PageEditContent.xaml.cs 37 KB

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