using PDF_Office.EventAggregators;
using PDF_Office.Helper;
using PDF_Office.Model.PageEdit;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using WpfToolkit.Controls;
namespace PDF_Office.Views.PageEdit
{
///
/// PageEditContent.xaml 的交互逻辑
///
public partial class PageEditContent : UserControl
{
///
/// 用于通知刷新图片的事件
/// 因为目前的图片刷新策略依赖很多UI事件判断,因为将主要判断逻辑放在UI层,VM负责图片刷新,非必要情况尽量不要采用这种形式
///
private IEventAggregator eventor;
///
/// 暂存的唯一索引值,用于区分多页签
///
private string unicode;
///
/// 是否是加载时第一次触发滚动
///
private bool isFirstScrollChange = true;
///
/// 用于判断滚轮停止的计时器
///
private DispatcherTimer timer = new DispatcherTimer();
///
/// 判断是否开始框选
///
private bool startChoose = false;
///
/// 框选的起始位置
///
private Point starPosition = new Point();
///
/// 记录当前滑块的状态
///
private ScrollEventType scrolltype = ScrollEventType.EndScroll;
public PageEditContent()
{
InitializeComponent();
}
public PageEditContent(IEventAggregator eventAggregator) :this()
{
eventor = eventAggregator;
unicode = App.mainWindowViewModel.SelectedItem.Unicode;
timer.Interval = TimeSpan.FromSeconds(0.3);
timer.Tick += Timer_Tick;
//订阅页面刷新事件
eventor.GetEvent().Subscribe(OneNotifyEvent, e => e.Unicode == unicode);
}
private void Timer_Tick(object sender, EventArgs e)
{
PulishEvent();
timer.Stop();
}
private void OneNotifyEvent(PageEditNotifyEventArgs e)
{
PulishEvent();
}
#region UI事件
///
/// 每次显示的时候就触发事件,刷新所有图片
///
///
///
private void PageEdit_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if((bool)e.NewValue)
{
//当前页面没有发生变化时,刷新图片 这种情况下会拿两次图,需要留意
PulishEvent();
//当前页面发生变化时通过ScrollChanged事件来刷新图片
isFirstScrollChange = true;
}
}
///
/// 鼠标滚轮滚动时触发的事件
///
///
///
private void ListPageEdit_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (isFirstScrollChange)
{
PulishEvent();//第一次加载时触发的Scollchange 直接刷新界面,减少白板显示时间
isFirstScrollChange = false;
return;
}
else
{
if (e.VerticalChange != 0)
timer.Start();//暂时找不到比较好的 判断Scroller停止的方法,先用计时器粗略判断
}
}
///
/// 拖动右侧滑块时触发的事件
///
///
///
private void ListPageEdit_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
{
scrolltype = e.ScrollEventType;
if (scrolltype != System.Windows.Controls.Primitives.ScrollEventType.EndScroll)
{
timer.Stop();
return;
}
PulishEvent();
}
#endregion
#region 方法
///
/// 发布事件
///
private void PulishEvent()
{
var itemSize = (ListPageEdit.Items[0] as PageEditItem).ItemSize;
var range = GetRoughFromView(ListPageEdit, itemSize, new Thickness(5, 10, 5, 10));
eventor.GetEvent().Publish(new PageEditRefreshEventArgs() { Unicode = unicode, PageRange = range });
}
///
/// 获取滑轨的垂直偏移量,结合item总数和Item尺寸以及间隔,来估算实际展示的item范围
/// 返回值为页面范围 从1开始
///
///
///
///
///
private Tuple GetRoughFromView(ListBox view, Size itemSize, Thickness itemMargin)
{
//var scrollViewer = GetScrollHost(view);
var scrollViewer = CommonHelper.FindVisualChild(view);
if (scrollViewer == null || scrollViewer.ActualHeight == 0 || scrollViewer.ActualWidth == 0)//视图展开
return new Tuple(0, 0, 0);
try
{
var currentHeight = scrollViewer.ActualHeight - view.Padding.Top;
var currentWidth = scrollViewer.ActualWidth;
//计算当前窗口大小能显示的行数和列数
var columnCount = (int)(currentWidth / (itemSize.Width + itemMargin.Left));
var rowCount = (int)Math.Ceiling(currentHeight / (itemSize.Height + itemMargin.Bottom));
var preItemCount = (int)((scrollViewer.VerticalOffset / scrollViewer.ExtentHeight) * ((view.Items.Count + columnCount - 1) / columnCount));//滑动百分比*行数 = 大概的垂直位置
preItemCount = preItemCount * columnCount;
var preEnd = (int)(((scrollViewer.VerticalOffset + scrollViewer.ActualHeight) / scrollViewer.ExtentHeight) * ((view.Items.Count + columnCount - 1) / columnCount));
preEnd = preEnd * columnCount + columnCount - 1;
var middle = (int)Math.Ceiling(preItemCount + preEnd / 2d);
return new Tuple(
Math.Max(preItemCount, 0),
Math.Min(view.Items.Count, preEnd),
middle);
}
catch { }
return new Tuple(0, 0, 0);
}
///
/// 获取listbox里的ScrollViewer对象
/// 留意如果有重写ListBox对象,该方法可能无效
///
///
///
private ScrollViewer GetScrollHost(ListBox listBox)
{
if (VisualTreeHelper.GetChildrenCount(listBox) > 0)
{
int s = VisualTreeHelper.GetChildrenCount(listBox);
Border border = VisualTreeHelper.GetChild(listBox, 0) as Border;
if (border != null)
{
return VisualTreeHelper.GetChild(border, 0) as ScrollViewer;
}
}
return null;
}
#endregion
///
/// 输入框显示时,自动获取焦点
///
///
///
private void TextBox_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if((bool)e.NewValue)
{
(sender as Control).Focus();
}
}
private void ListPageEdit_PreviewMouseMove(object sender, MouseEventArgs e)
{
try
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (startChoose)
{
var position = e.GetPosition(ListPageEdit);
if (position.X < 5 || position.X > ListPageEdit.ActualWidth - 5 || position.Y < 5 || position.Y > ListPageEdit.ActualHeight - 5)
{
startChoose = false;
RectChoose.Visibility = Visibility.Collapsed;
Mouse.Capture(null);//暂时未想到靠近顶部和底部自动翻滚的好方法,只能先屏蔽这部分功能
return;
}
DoSelectItems();
return;
}
//拖拽排序的逻辑
//var pos = e.GetPosition(ListPageEdit);
//if (pos.Y < 0 || pos.Y > ListPageEdit.ActualHeight)
//{
// MidLane.Visibility = Visibility.Collapsed;
// return;
//}
//HitTestResult result = VisualTreeHelper.HitTest(PageEditListBox, pos);
//if (result == null)
//{
// return;
//}
//var listBoxItem = CommonHelper.FindVisualParent(result.VisualHit);
//if (listBoxItem == null)
//{
// return;
//}
//isDragingEnter = false;
//tempItem = listBoxItem;
//var panel = GetPanel(tempItem);
//var item_pos = e.GetPosition(panel);
//if (item_pos != null)
//{
// item_x = item_pos.X;
// item_y = item_pos.Y;
//}
//var scroll = GetScrollHost(PageEditListBox);
//DataObject dataObj = new DataObject(listBoxItem.Content as StackPanel);
//DragDrop.DoDragDrop(PageEditListBox, dataObj, DragDropEffects.Move);
//Mouse.Capture(PageEditListBox);
//return;
}
RectChoose.Visibility = Visibility.Collapsed;
startChoose = false;
Mouse.Capture(null);
}
catch (Exception ex)
{
// MidLane.Visibility = Visibility.Collapsed;
}
}
private void ListPageEdit_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var pos = e.GetPosition(ListPageEdit);
HitTestResult result = VisualTreeHelper.HitTest(ListPageEdit, pos);
if (result == null)
{
return;
}
//未选中item 并且不是点击滑轨时 开始框选
var listBoxItem = CommonHelper.FindVisualParent(result.VisualHit);
var scroller = CommonHelper.FindVisualParent(result.VisualHit);
if (listBoxItem == null)
{
if (scroller != null)
{
startChoose = false;
return;
}
//点击空白处时开始框选
startChoose = true;
ListPageEdit.SelectedItems.Clear();
starPosition = e.GetPosition(ListPageEdit);
starPosition = new Point(starPosition.X, starPosition.Y + GetWrapPanel(ListPageEdit).VerticalOffset);
Mouse.Capture(ListPageEdit);
return;
}
startChoose = false;//选中了item 时,不能框选
}
private void ListPageEdit_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
startChoose = false;
Mouse.Capture(null);
RectChoose.Visibility = Visibility.Collapsed;
}
///
/// 获取Listobox的Wrappanel容器
///
///
///
public VirtualizingWrapPanel GetWrapPanel(ListBox listBox)
{
Border border = VisualTreeHelper.GetChild(listBox, 0) as Border;
var panel = CommonHelper.FindVisualChild(border);
return panel;
}
///
///根据鼠标拖选的框 选中里面的Item
///
private void DoSelectItems()
{
var s = GetScrollHost(ListPageEdit);
Point start = new Point();
//通过 实时的垂直偏移量和第一次的偏移量抵消,来获取准确的垂直偏移值。
start = new Point(starPosition.X, starPosition.Y - s.VerticalOffset);
var rec = new Rect(start, Mouse.GetPosition(ListPageEdit));
RectChoose.Margin = new Thickness(rec.Left, rec.Top, 0, 0);
RectChoose.Width = rec.Width;
RectChoose.Height = rec.Height;
RectChoose.Visibility = Visibility.Visible;
//检测遍历所有项,筛选在矩形框中的Item
for (int i = 0; i < ListPageEdit.Items.Count; i++)
{
var _item = ListPageEdit.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
//通过这一步来避免重复误选中
var parent = CommonHelper.FindVisualParent(_item);
if (parent == null)
continue;
var v = VisualTreeHelper.GetOffset(_item);
if (rec.IntersectsWith(new Rect(v.X, v.Y, _item.ActualWidth, _item.ActualHeight)))
{
ListPageEdit.SelectedItems.Add(ListPageEdit.Items[i]);
}
else
{
ListPageEdit.SelectedItems.Remove(ListPageEdit.Items[i]);
}
}
return;
}
}
}