PageEditContent.xaml.cs 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  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 tempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "Temp.pdf");
  304. System.IO.File.Create(tempPath);
  305. string[] files = new string[1];
  306. files[0] = tempPath;
  307. DataObject dataObj = new DataObject(DataFormats.FileDrop, files);
  308. DragDrop.DoDragDrop(ListPageEdit, dataObj, DragDropEffects.Copy);
  309. Mouse.Capture(ListPageEdit);
  310. return;
  311. }
  312. RectChoose.Visibility = Visibility.Collapsed;
  313. startChoose = false;
  314. Mouse.Capture(null);
  315. }
  316. catch
  317. {
  318. LineInset.Visibility = Visibility.Collapsed;
  319. }
  320. }
  321. /// <summary>
  322. /// 判断是否开始框选、记录框选起始位置
  323. /// </summary>
  324. /// <param name="sender"></param>
  325. /// <param name="e"></param>
  326. private void ListPageEdit_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  327. {
  328. var pos = e.GetPosition(ListPageEdit);
  329. HitTestResult result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  330. if (result == null)
  331. {
  332. return;
  333. }
  334. //未选中item 并且不是点击滑轨时 开始框选
  335. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  336. var scroller = CommonHelper.FindVisualParent<ScrollBar>(result.VisualHit);
  337. if (listBoxItem == null)
  338. {
  339. if (scroller != null)
  340. {
  341. startChoose = false;
  342. return;
  343. }
  344. //点击空白处时开始框选
  345. startChoose = true;
  346. if (ListPageEdit.SelectedItems.Count > 0)
  347. {
  348. ListPageEdit.SelectedItems.Clear();
  349. }
  350. starPosition = e.GetPosition(ListPageEdit);
  351. starPosition = new Point(starPosition.X, starPosition.Y + GetWrapPanel(ListPageEdit).VerticalOffset);
  352. Mouse.Capture(ListPageEdit);
  353. return;
  354. }
  355. //选中了item 时,不能框选
  356. startChoose = false;
  357. }
  358. private void ListPageEdit_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  359. {
  360. startChoose = false;
  361. Mouse.Capture(null);
  362. RectChoose.Visibility = Visibility.Collapsed;
  363. }
  364. /// <summary>
  365. /// 获取Listobox的Wrappanel容器
  366. /// </summary>
  367. /// <param name="listBox"></param>
  368. /// <returns></returns>
  369. public VirtualizingWrapPanel GetWrapPanel(ListBox listBox)
  370. {
  371. Border border = VisualTreeHelper.GetChild(listBox, 0) as Border;
  372. var panel = CommonHelper.FindVisualChild<VirtualizingWrapPanel>(border);
  373. return panel;
  374. }
  375. /// <summary>
  376. ///根据鼠标拖选的框 选中里面的Item
  377. /// </summary>
  378. private void DoSelectItems()
  379. {
  380. var s = GetScrollHost(ListPageEdit);
  381. Point start = new Point();
  382. //通过 实时的垂直偏移量和第一次的偏移量抵消,来获取准确的垂直偏移值。
  383. start = new Point(starPosition.X, starPosition.Y - s.VerticalOffset);
  384. var rec = new Rect(start, Mouse.GetPosition(ListPageEdit));
  385. RectChoose.Margin = new Thickness(rec.Left, rec.Top, 0, 0);
  386. RectChoose.Width = rec.Width;
  387. RectChoose.Height = rec.Height;
  388. RectChoose.Visibility = Visibility.Visible;
  389. //检测遍历所有项,筛选在矩形框中的Item
  390. for (int i = 0; i < ListPageEdit.Items.Count; i++)
  391. {
  392. var _item = ListPageEdit.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
  393. //通过这一步来避免重复误选中
  394. var parent = CommonHelper.FindVisualParent<VirtualizingWrapPanel>(_item);
  395. if (parent == null)
  396. continue;
  397. var v = VisualTreeHelper.GetOffset(_item);
  398. if (rec.IntersectsWith(new Rect(v.X, v.Y, _item.ActualWidth, _item.ActualHeight)))
  399. {
  400. ListPageEdit.SelectedItems.Add(ListPageEdit.Items[i]);
  401. }
  402. else
  403. {
  404. ListPageEdit.SelectedItems.Remove(ListPageEdit.Items[i]);
  405. }
  406. }
  407. return;
  408. }
  409. /// <summary>
  410. /// 计算插入标记线和虚影显示
  411. /// </summary>
  412. /// <param name="sender"></param>
  413. /// <param name="e"></param>
  414. private void ListPageEdit_DragOver(object sender, DragEventArgs e)
  415. {
  416. try
  417. {
  418. //ctrl建按下 不显示插入标记和虚影 因为释放不会响应drop事件
  419. if (e.KeyStates == (DragDropKeyStates.ControlKey | DragDropKeyStates.LeftMouseButton) || e.KeyStates == (DragDropKeyStates.ShiftKey | DragDropKeyStates.LeftMouseButton | DragDropKeyStates.ControlKey))
  420. return;
  421. //滚动后有 位置不准确 要减去滚动偏移量
  422. //控制线的位置
  423. var pos = e.GetPosition(ListPageEdit);
  424. var result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  425. if (result == null)
  426. {
  427. //MidLane.Visibility = Visibility.Collapsed;
  428. //return;
  429. }
  430. //获取当前鼠标指针下的容器
  431. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  432. if (listBoxItem == null)
  433. {
  434. //MidLane.Visibility = Visibility.Collapsed;
  435. //return;
  436. }
  437. #region 计算虚影位置
  438. //xaml层 要设置 虚影控件为左上
  439. double xPos = 0;
  440. double yPos = 0;
  441. //内部拖动
  442. if (!isDragingEnter)
  443. {
  444. //Viewbox viewBox = (tempItem.Content as StackPanel).Children[0] as Viewbox;//获取item宽度
  445. ImgPicture.Width = tempItem.ItemSize.Width;
  446. ImgPicture.Height = tempItem.ItemSize.Height;
  447. ImgPicture.Source = tempItem.Image;
  448. xPos = e.GetPosition(ListPageEdit).X - item_x;
  449. yPos = e.GetPosition(ListPageEdit).Y - item_y;
  450. }
  451. //else
  452. //{
  453. // //从外部拖入的逻辑
  454. // //var pic = ToBitmapSource(dragingEnterPath);
  455. // //ShadowPicture.Width = pic.Width;
  456. // //ShadowPicture.Height = pic.Height;
  457. // //ShadowPicture.Source = pic;
  458. // //xPos = e.GetPosition(ListPageEdit).X - pic.Width / 2;
  459. // //yPos = e.GetPosition(ListPageEdit).Y - pic.Height / 2;
  460. //}
  461. ImgPicture.Margin = new Thickness(xPos, yPos, 0, 0);
  462. #endregion
  463. #region 计算插入标记位置
  464. var scroll = GetScrollHost(ListPageEdit);
  465. if (listBoxItem != null)
  466. {
  467. //虚拟化影响到该值计算
  468. var p = VisualTreeHelper.GetOffset(listBoxItem);//计算控件在容器中的偏移(位置)
  469. LineInset.Visibility = Visibility.Visible;
  470. var panel = GetWrapPanel(ListPageEdit);
  471. var item = (ListPageEdit.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem).DesiredSize.Width;
  472. int count = (int)(panel.ViewportWidth / item);
  473. var gap = (panel.ViewportWidth - count * item) / (count + 1) * 1.0;
  474. LineInset.X2 = LineInset.X1 = p.X + gap / 2 + listBoxItem.DesiredSize.Width;
  475. if (pos.X < p.X + gap / 2 + listBoxItem.ActualWidth / 2)
  476. {
  477. isFrontHalf = true;//前半部 线条出现在位置前
  478. LineInset.X2 = LineInset.X1 = p.X - gap / 2;
  479. InsertIndex = ListPageEdit.Items.IndexOf(listBoxItem);
  480. }
  481. else
  482. {
  483. isFrontHalf = false;
  484. InsertIndex = ListPageEdit.Items.IndexOf(listBoxItem) + 1;
  485. }
  486. //MidLane.Y1 = p.Y - scroll.VerticalOffset;//向下滑动后要减去滑动值
  487. LineInset.Y1 = p.Y;
  488. if (LineInset.Y1 < 0)//避免超出上边界
  489. {
  490. LineInset.Y1 = 0;
  491. }
  492. //MidLane.Y2 = p.Y + listBoxItem.ActualHeight - scroll.VerticalOffset;//仿智能滚动后可能会导致 垂直滚动偏量不准确
  493. LineInset.Y2 = p.Y + listBoxItem.ActualHeight;
  494. if (LineInset.Y2 < 0)
  495. {
  496. LineInset.Y2 = 0;
  497. }
  498. }
  499. #endregion
  500. //暂时处理 鼠标移出边框时,虚影的显示问题
  501. if (pos.Y <= 30 || pos.Y >= ListPageEdit.ActualHeight - 10)
  502. {
  503. LineInset.Visibility = Visibility.Collapsed;
  504. needScroll = false;
  505. }
  506. if (pos.X <= 40 || pos.X >= scroll.ViewportWidth - 50)
  507. {
  508. LineInset.Visibility = Visibility.Collapsed;
  509. needScroll = false;
  510. }
  511. #region 靠近上下边界时,自动滚动,离边界越近,滚动速度越快
  512. //speed = 0;
  513. //if (pos.Y >= PageEditListBox.ActualHeight - 30)
  514. //{
  515. // speed = 30 - (int)(PageEditListBox.ActualHeight - pos.Y);
  516. // needScroll = true;
  517. //}
  518. //else if (pos.Y <= 30)
  519. //{
  520. // speed = (int)(pos.Y - 30);
  521. // needScroll = true;
  522. //}
  523. //else
  524. // needScroll = false;
  525. //var v = scroll.VerticalOffset;
  526. //scroll.ScrollToVerticalOffset(v + speed);//触发连续滚动
  527. #endregion
  528. }
  529. catch (Exception ex)
  530. {
  531. }
  532. }
  533. /// <summary>
  534. /// 退出拖拽模式
  535. /// </summary>
  536. private void ExitDraging()
  537. {
  538. LineInset.Visibility = Visibility.Collapsed;
  539. isDraging = false;
  540. }
  541. /// <summary>
  542. /// 拖拽释放后的处理逻辑
  543. /// </summary>
  544. /// <param name="sender"></param>
  545. /// <param name="e"></param>
  546. private void ListPageEdit_Drop(object sender, DragEventArgs e)
  547. {
  548. needScroll = false;
  549. if (!isDraging)
  550. {
  551. //未拖拽时隐藏插入标记和虚影
  552. LineInset.Visibility = Visibility.Collapsed;
  553. return;
  554. }
  555. #region 功能付费锁
  556. // //if (!App.IsActive())
  557. // //{
  558. // // MidLane.Visibility = Visibility.Collapsed;
  559. // // IAPFunctionDialog dialog = new IAPFunctionDialog("PageEdit");
  560. // // dialog.ShowDialog();
  561. // // return;
  562. // //}
  563. #endregion
  564. #region 从外部拖拽插入文件
  565. //if (isDragingEnter)
  566. //{
  567. // //在当前位置插入整个pdf
  568. // CPDFDocument dragDoc = CPDFDocument.InitWithFilePath(dragingEnterPath);
  569. // if (dragDoc.IsLocked)
  570. // {
  571. // VerifyPasswordDialog dialog = new VerifyPasswordDialog(dragDoc);
  572. // dialog.ShowDialog();
  573. // if (dragDoc.IsLocked)
  574. // return;
  575. // }
  576. // if (dragingEnterPath.Substring(dragingEnterPath.LastIndexOf(".")).ToLower() == ".pdf")
  577. // {
  578. // if (dragDoc != null)
  579. // {
  580. // int index = InsertIndex == -1 ? 0 : InsertIndex;
  581. // pdfViewer.Document.ImportPagesAtIndex(dragDoc, "1-" + dragDoc.PageCount, index);
  582. // PopulateThumbnailList();
  583. // ItemsInViewHitTest();
  584. // pdfViewer.UndoManager.ClearHistory();
  585. // pdfViewer.UndoManager.CanSave = true;
  586. // pdfViewer.ReloadDocument();
  587. // PageEditListBox.ScrollIntoView(PageEditListBox.SelectedItem as ListBoxItem);
  588. // PageMoved.Invoke(this, new RoutedEventArgs());
  589. // PDFViewerCtrl viewerCtrl = ParentPage?.GetCurrentViewer();
  590. // if (viewerCtrl != null)
  591. // {
  592. // viewerCtrl.IsPageEdit = true;
  593. // }
  594. // dragDoc.Release();
  595. // }
  596. // else
  597. // {
  598. // MessageBoxEx.Show(App.MainPageLoader.GetString("Merge_FileCannotOpenedWarningd"));
  599. // }
  600. // //提示文档损坏无法打开
  601. // }
  602. // else if (!string.IsNullOrEmpty(dragingEnterPath))
  603. // {
  604. // //其他文件 则新增一个页签打开
  605. // // DragAddTab.Invoke(dragingEnterPath, new RoutedEventArgs());//底层库需要加一个 Load(TPDFDocument)的接口
  606. // }
  607. // MidLane.Visibility = Visibility.Collapsed;
  608. // isDragingEnter = false;
  609. // dragingEnterPath = null;
  610. // return;
  611. //}
  612. #endregion
  613. var pos = e.GetPosition(ListPageEdit);
  614. var result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  615. if (result == null)
  616. {
  617. //超出当前可控区域
  618. ExitDraging();
  619. return;
  620. }
  621. //查找元数据
  622. var sourcePerson = e.Data.GetData(typeof(StackPanel)) as StackPanel;
  623. if (sourcePerson == null)
  624. {
  625. ExitDraging();
  626. return;
  627. }
  628. //查找目标数据
  629. int targetindex = 0;//目标插入位置
  630. if (InsertIndex != -1)
  631. {
  632. //往前移动时 此index 不是准确的,需要处理++
  633. targetindex = InsertIndex;
  634. }
  635. else//基本不会命中 仅作为保险措施
  636. {
  637. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  638. if (listBoxItem == null)
  639. {
  640. ////鼠标停留在两个item之间或其他无效区域 暂时不做处理(比较麻烦)
  641. ExitDraging();
  642. return;
  643. }
  644. var targetPerson = listBoxItem;
  645. targetPerson.Opacity = 1;
  646. sourcePerson.Opacity = 1;
  647. if (ReferenceEquals(targetPerson, sourcePerson))
  648. {
  649. ExitDraging();
  650. return;
  651. }
  652. targetindex = ListPageEdit.Items.IndexOf(targetPerson);
  653. }
  654. List<ListBoxItem> list = new List<ListBoxItem>();
  655. List<int> sourceindex = new List<int>();//需要保存每个页面对应的位置
  656. //开始排序
  657. List<int> pages = new List<int>();
  658. //要先对所有选中项 根据页码排序
  659. for (int i = 0; i < ListPageEdit.SelectedItems.Count; i++)
  660. {
  661. var pageindex = ListPageEdit.Items.IndexOf(ListPageEdit.SelectedItems[i] as ListBoxItem);
  662. pages.Add(pageindex);//存入的为页码索引值
  663. }
  664. pages.Sort();
  665. if (pages.Count <= 0)
  666. {
  667. ExitDraging();
  668. return;
  669. }
  670. //要考虑每一次交换都会导致局部页码发生改变
  671. //每次整体往后移动时,先移动大页码;整体往前移动时,先移动小页码;往中间移动时,再按上述两种情况分别移动
  672. //if (targetindex <= pages[0])// 目标位置在所有选中内容左边,整体前移动 优先先判断左移的情况
  673. //{
  674. // sourceindex.Add(-1);
  675. // list = new List<ListBoxItem>();
  676. // for (int i = 0; i < pages.Count; i++)
  677. // {
  678. // list.Add(PageEditListBox.Items[pages[i]] as ListBoxItem);
  679. // sourceindex.Add(pages[i]);
  680. // DragToSort(pages[i], targetindex + i);
  681. // }
  682. //}
  683. //else if (targetindex > pages[pages.Count - 1])//目标位置在所有选中内容右边 整体后移
  684. //{
  685. // sourceindex.Add(1);
  686. // list = new List<ListBoxItem>();
  687. // for (int i = 0; i < pages.Count; i++)
  688. // {
  689. // list.Add(PageEditListBox.Items[pages[pages.Count - 1 - i]] as ListBoxItem);
  690. // sourceindex.Add(pages[pages.Count - 1 - i]);
  691. // DragToSort(pages[pages.Count - 1 - i], targetindex - 1 - i/* + (PageEditListBox.SelectedItems.Count - 1 - i)*/);
  692. // }
  693. //}
  694. //else//目标位置在所有选中项中间
  695. //{
  696. // int i, j, k;
  697. // for (k = 0; k < pages.Count - 1; k++)//找出PageEditListBox.Items中页码等于destpage的下标
  698. // {
  699. // //这里要算入K---即前面部分的页面个数
  700. // if (pages[k] < targetindex && pages[k + 1] >= targetindex)
  701. // break;
  702. // }
  703. // sourceindex.Add(0);
  704. // list = new List<ListBoxItem>();
  705. // for (i = 0; i <= k; i++)//局部往后移动
  706. // {
  707. // list.Add(PageEditListBox.Items[pages[k - i]] as ListBoxItem);
  708. // sourceindex.Add(pages[k - i]);
  709. // DragToSort(pages[k - i], targetindex - 1 - i);
  710. // }
  711. // for (j = i; j < pages.Count; j++)//局部往前移动
  712. // {
  713. // list.Add(PageEditListBox.Items[pages[j]] as ListBoxItem);
  714. // sourceindex.Add(pages[j]);
  715. // DragToSort(pages[j], targetindex);
  716. // targetindex++;
  717. // }
  718. // sourceindex.Add(k);//往中间移时, index数组的最后一位 表示 间隔位置K
  719. //}
  720. isDraging = false;
  721. }
  722. private void MidLane_Drop(object sender, DragEventArgs e)
  723. {
  724. ListPageEdit_Drop(sender, e);
  725. }
  726. private void ImgPicture_Drop(object sender, DragEventArgs e)
  727. {
  728. ListPageEdit_Drop(sender, e);
  729. }
  730. /// <summary>
  731. /// 拖拽事件写在外部的Grid里,会更加流畅
  732. /// </summary>
  733. /// <param name="sender"></param>
  734. /// <param name="e"></param>
  735. private void Grid_DragOver(object sender, DragEventArgs e)
  736. {
  737. try
  738. {
  739. //ctrl建按下 不显示插入标记和虚影 因为释放不会响应drop事件
  740. if (e.KeyStates == (DragDropKeyStates.ControlKey | DragDropKeyStates.LeftMouseButton) || e.KeyStates == (DragDropKeyStates.ShiftKey | DragDropKeyStates.LeftMouseButton | DragDropKeyStates.ControlKey))
  741. return;
  742. //滚动后有 位置不准确 要减去滚动偏移量
  743. //控制线的位置
  744. var pos = e.GetPosition(ListPageEdit);
  745. var result = VisualTreeHelper.HitTest(ListPageEdit, pos);
  746. if (result == null)
  747. {
  748. //MidLane.Visibility = Visibility.Collapsed;
  749. //return;
  750. }
  751. //获取当前鼠标指针下的容器
  752. var listBoxItem = CommonHelper.FindVisualParent<ListBoxItem>(result.VisualHit);
  753. if (listBoxItem == null)
  754. {
  755. //MidLane.Visibility = Visibility.Collapsed;
  756. //return;
  757. }
  758. #region 计算虚影位置
  759. //xaml层 要设置 虚影控件为左上
  760. double xPos = 0;
  761. double yPos = 0;
  762. //内部拖动
  763. if (!isDragingEnter)
  764. {
  765. //Viewbox viewBox = (tempItem.Content as StackPanel).Children[0] as Viewbox;//获取item宽度
  766. ImgPicture.Width = tempItem.ItemSize.Width;
  767. ImgPicture.Height = tempItem.ItemSize.Height;
  768. ImgPicture.Source = tempItem.Image;
  769. xPos = e.GetPosition(ListPageEdit).X - item_x;
  770. yPos = e.GetPosition(ListPageEdit).Y - item_y;
  771. }
  772. //else
  773. //{
  774. // //从外部拖入的逻辑
  775. // //var pic = ToBitmapSource(dragingEnterPath);
  776. // //ShadowPicture.Width = pic.Width;
  777. // //ShadowPicture.Height = pic.Height;
  778. // //ShadowPicture.Source = pic;
  779. // //xPos = e.GetPosition(ListPageEdit).X - pic.Width / 2;
  780. // //yPos = e.GetPosition(ListPageEdit).Y - pic.Height / 2;
  781. //}
  782. ImgPicture.Margin = new Thickness(xPos, yPos, 0, 0);
  783. #endregion
  784. #region 计算插入标记位置
  785. var scroll = GetScrollHost(ListPageEdit);
  786. if (listBoxItem != null)
  787. {
  788. //虚拟化影响到该值计算
  789. var p = VisualTreeHelper.GetOffset(listBoxItem);//计算控件在容器中的偏移(位置)
  790. LineInset.Visibility = Visibility.Visible;
  791. var panel = GetWrapPanel(ListPageEdit);
  792. //var item = panel.ItemSize.Width;
  793. //var item = (ListPageEdit.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem).DesiredSize.Width;
  794. var item = listBoxItem.DesiredSize.Width;
  795. int count = (int)(panel.ViewportWidth / item);
  796. var gap = (panel.ViewportWidth - count * item) / (count + 1) * 1.0;
  797. LineInset.X2 = LineInset.X1 = p.X + gap / 2 + listBoxItem.DesiredSize.Width;
  798. if (pos.X < p.X + gap / 2 + listBoxItem.ActualWidth / 2)
  799. {
  800. isFrontHalf = true;//前半部 线条出现在位置前
  801. LineInset.X2 = LineInset.X1 = p.X - gap / 2;
  802. InsertIndex = ListPageEdit.Items.IndexOf(listBoxItem);
  803. }
  804. else
  805. {
  806. isFrontHalf = false;
  807. InsertIndex = ListPageEdit.Items.IndexOf(listBoxItem) + 1;
  808. }
  809. //MidLane.Y1 = p.Y - scroll.VerticalOffset;//向下滑动后要减去滑动值
  810. LineInset.Y1 = p.Y;
  811. if (LineInset.Y1 < 0)//避免超出上边界
  812. {
  813. LineInset.Y1 = 0;
  814. }
  815. //MidLane.Y2 = p.Y + listBoxItem.ActualHeight - scroll.VerticalOffset;//仿智能滚动后可能会导致 垂直滚动偏量不准确
  816. LineInset.Y2 = p.Y + listBoxItem.ActualHeight;
  817. if (LineInset.Y2 < 0)
  818. {
  819. LineInset.Y2 = 0;
  820. }
  821. }
  822. #endregion
  823. //暂时处理 鼠标移出边框时,虚影的显示问题
  824. if (pos.Y <= 30 || pos.Y >= ListPageEdit.ActualHeight - 10)
  825. {
  826. LineInset.Visibility = Visibility.Collapsed;
  827. needScroll = false;
  828. }
  829. if (pos.X <= 40 || pos.X >= scroll.ViewportWidth - 50)
  830. {
  831. LineInset.Visibility = Visibility.Collapsed;
  832. needScroll = false;
  833. }
  834. #region 靠近上下边界时,自动滚动,离边界越近,滚动速度越快
  835. speed = 0;
  836. if (pos.Y >= ListPageEdit.ActualHeight - 30)
  837. {
  838. speed = 30 - (int)(ListPageEdit.ActualHeight - pos.Y);
  839. needScroll = true;
  840. }
  841. else if (pos.Y <= 30)
  842. {
  843. speed = (int)(pos.Y - 30);
  844. needScroll = true;
  845. }
  846. else
  847. needScroll = false;
  848. var v = scroll.VerticalOffset;
  849. scroll.ScrollToVerticalOffset(v + speed);//触发连续滚动
  850. #endregion
  851. }
  852. catch
  853. {
  854. }
  855. }
  856. private void ListBoxItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  857. {
  858. //e.Handled = true;
  859. }
  860. private void ListBoxItem_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
  861. {
  862. if(e.ChangedButton== MouseButton.Left)
  863. {
  864. //双击回到PDFViewer界面
  865. var item = sender as ListBoxItem;
  866. if (item != null)
  867. {
  868. var index = ListPageEdit.ItemContainerGenerator.IndexFromContainer(item);
  869. //双击事件无法绑定Command 暂时采用这种方式调用VM里的方法
  870. viewModel.BackToPDFViewer(index);
  871. }
  872. }
  873. }
  874. private void PageEdit_SizeChanged(object sender, SizeChangedEventArgs e)
  875. {
  876. //BOTA缩略图模式下需要调整Item宽度
  877. if (GridBOTAHeader.Visibility == Visibility.Visible)
  878. {
  879. ItemSuitAcutalWidth(e.NewSize.Width);
  880. }
  881. }
  882. private void ItemSuitAcutalWidth(double width)
  883. {
  884. //缩略图模式下,保持一列或者两列显示
  885. if ((bool)TbnTwoLine.IsChecked)
  886. {
  887. var itemwidth = (width - 80) / 2;
  888. var itemHeight = 294 * itemwidth / 208.0;
  889. viewModel.ChangeItemSize(new Size(itemwidth, itemHeight));
  890. }
  891. else
  892. {
  893. var itemwidth = 0.6 * width;
  894. var itemheight = 294 * itemwidth / 208.0;
  895. viewModel.ChangeItemSize(new Size(itemwidth,itemheight));
  896. }
  897. }
  898. private void TbnTwoLine_Click(object sender, RoutedEventArgs e)
  899. {
  900. ItemSuitAcutalWidth(this.ActualWidth);
  901. }
  902. }
  903. }