座標軸xaml:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Transvalue.Timeline" x:Class="Transvalue.Timeline.TimelineBandControl"
mc:Ignorable="d"
Width="Auto"
Name="timelineBandControl"
>
<UserControl.Resources>
<Style x:Key="TimelineLabel" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<ContentPresenter HorizontalAlignment="Center" Margin="17,19,17,24" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Center" Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="FontFamily" Value="/Transvalue.Timeline;component/Fonts/#Segoe UI Light"/>
<Setter Property="Width" Value="200"/>
<Setter Property="Foreground" Value="White"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=DataContext}"
Value="1">
<DataTrigger.EnterActions>
<BeginStoryboard Name="big">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" Duration="0:0:0.5"
To="800">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},Path=DataContext}"
Value="0">
<DataTrigger.EnterActions>
<BeginStoryboard Name="Small">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" Duration="0:0:0.5"
To="200">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid Width="Auto" Height="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="0.40*"></RowDefinition>
<RowDefinition Height="0.10*"></RowDefinition>
<RowDefinition Height="0.40*"></RowDefinition>
</Grid.RowDefinitions>
<WrapPanel Width="Auto" Height="Auto" Name="timelineEventItems"></WrapPanel>
<WrapPanel x:Name="timelineLabelItems" Width="Auto" Height="Auto" Grid.Row="2"></WrapPanel>
<WrapPanel x:Name="timelinePoint" Width="Auto" Height="Auto" Grid.Row="1"></WrapPanel>
</Grid>
</UserControl>
座標軸 代碼:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Surface.Presentation.Controls;
namespace Transvalue.Timeline
{
/// <summary>
/// TimelineBandControl.xaml 的交互邏輯
/// </summary>
public partial class TimelineBandControl : UserControl, INotifyPropertyChanged
{
private static Style timelineLabelStyle;
private static int currentPageIndex = 0; //初始當前頁
private static int totalPage = 0; //最大頁數
private static int changedBand = 0; //0不變 1變大 2縮小
Dictionary<Predicate<string>, Action> PropertyChangedDictAction = new Dictionary<Predicate<string>, Action>();
Dictionary<Predicate<TimeLineEnum.TimeLineBandType>, Func<TimelineLabelItem, ObservableCollection<TimelineEventItem>, TimelineEventItemControl, bool, bool>>
TimelineEventGenericDictAction =
new Dictionary<Predicate<TimeLineEnum.TimeLineBandType>, Func<TimelineLabelItem, ObservableCollection<TimelineEventItem>, TimelineEventItemControl, bool, bool>>();
#region 需要顯示的數據標籤
public static ObservableCollection<TimelineLabelItem> tempTimelineLabels;
public static DependencyProperty timelineLabels = DependencyProperty.Register("TimelineLabelSource",
typeof(ObservableCollection<TimelineLabelItem>), typeof(TimelineBandControl)
, new PropertyMetadata(new PropertyChangedCallback(TimelineLabelsCallBack)));
public ObservableCollection<TimelineLabelItem> TimelineLabels
{
get
{
return (ObservableCollection<TimelineLabelItem>)GetValue(timelineLabels);
}
set
{
SetValue(timelineLabels, value);
OnPropertyChanged("TimelineLabels");
}
}
private static void TimelineLabelsCallBack(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
}
#endregion
#region 時間軸顯示項數量
public static DependencyProperty pageSize = DependencyProperty.Register("PageSize",
typeof(int), typeof(TimelineBandControl),
new PropertyMetadata(new PropertyChangedCallback(TimelinePageSizeCallBack)));
public int PageSize
{
get
{
return (int)GetValue(pageSize);
}
set
{
SetValue(pageSize, value);
OnPropertyChanged("PageSize");
}
}
private static void TimelinePageSizeCallBack(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
var timelineBand = sender as TimelineBandControl;
if (e.Property == pageSize)
{
timelineBand.PageSize = (int)e.NewValue;
}
}
#endregion
#region 當前顯示模式
private static int defaultTimelineMode = -1;
public static DependencyProperty currentTimelineMode = DependencyProperty.Register("CurrentTimelineMode",
typeof(int), typeof(TimelineBandControl),
new PropertyMetadata(new PropertyChangedCallback(CurrentTimelineModeCallBack)));
public int CurrentTimelineMode
{
get
{
return (int)GetValue(currentTimelineMode);
}
set
{
SetValue(currentTimelineMode, value);
OnPropertyChanged("CurrentTimelineMode");
}
}
private static void CurrentTimelineModeCallBack(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
if (-1 != defaultTimelineMode && defaultTimelineMode != (int)e.NewValue)
changedBand = defaultTimelineMode < (int)e.NewValue ? 1 : 2;
else
changedBand = 0;
defaultTimelineMode = (int)e.NewValue;
}
#endregion
#region 事件數據源
private static int currentIndexInBand = 0;
public static DependencyProperty timelineEventSource = DependencyProperty.Register("TimelineEventSource",
typeof(ObservableCollection<TimelineEventItem>),
typeof(TimelineBandControl)
, new PropertyMetadata(new PropertyChangedCallback(timelineEventSourceCallBack)));
public ObservableCollection<TimelineEventItem> TimelineEventSource
{
get { return (ObservableCollection<TimelineEventItem>)GetValue(timelineEventSource); }
set
{
SetValue(timelineEventSource, value);
OnPropertyChanged("TimelineEventSource");
}
}
private static void timelineEventSourceCallBack(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
}
#endregion
#region 自定義事件
#region 加載詳細座標事件
public static readonly RoutedEvent ShowDetailEvent;
public class ShowDetailEventArgs : RoutedEventArgs
{
public TimeLineEnum.TimeLineBandType showMode
{
get;
set;
}
public DateTime startDate
{
get;
set;
}
public DateTime endDate
{
get;
set;
}
}
public delegate void ShowDetailEventHandler(object sender,
ShowDetailEventArgs e);
public event ShowDetailEventHandler ShowDetailEH
{
add
{
AddHandler(TimelineBandControl.ShowDetailEvent,
value);
}
remove
{
RemoveHandler(TimelineBandControl.ShowDetailEvent,
value);
}
}
#endregion
#region 加載mdiWindow事件
public static readonly RoutedEvent ShowScatterEvent;
public class ShowScatterEventArgs : RoutedEventArgs
{
public UIElement svi
{
get;
set;
}
}
public delegate void ShowScatterEventHandler(object sender,
ShowScatterEventArgs e);
public event ShowScatterEventHandler ShowScatterEH
{
add
{
AddHandler(TimelineBandControl.ShowScatterEvent,
value);
}
remove
{
RemoveHandler(TimelineBandControl.ShowScatterEvent,
value);
}
}
#endregion
#region 加載事件完成事件
public static readonly RoutedEvent LoadComplatedEvent;
public class LoadComplatedEventArgs : RoutedEventArgs
{
public bool ok
{
get;
set;
}
}
public delegate void LoadComplatedEventHandler(object sender,
LoadComplatedEventArgs e);
public event LoadComplatedEventHandler LoadComplatedEH
{
add
{
AddHandler(TimelineBandControl.LoadComplatedEvent,
value);
}
remove
{
RemoveHandler(TimelineBandControl.LoadComplatedEvent,
value);
}
}
#endregion
static TimelineBandControl()
{
ShowScatterEvent = EventManager.RegisterRoutedEvent(
"ShowScatterEvent",
RoutingStrategy.Bubble,
typeof(ShowScatterEventHandler),
typeof(TimelineBandControl));
LoadComplatedEvent = EventManager.RegisterRoutedEvent(
"LoadComplatedEvent",
RoutingStrategy.Bubble,
typeof(LoadComplatedEventHandler),
typeof(TimelineBandControl));
ShowDetailEvent = EventManager.RegisterRoutedEvent(
"ShowDetailEvent",
RoutingStrategy.Bubble,
typeof(ShowDetailEventHandler),
typeof(TimelineBandControl));
}
#endregion
#region 默認軸之間的寬度
public static double defaultItemWidth;
public double DefaultItemWidth
{
get
{
return defaultItemWidth;
}
set
{
if (defaultItemWidth != value)
{
defaultItemWidth = value;
OnPropertyChanged("DefaultItemWidth");
}
}
}
#endregion
public TimelineBandControl()
{
InitializeComponent();
InitializeDictoinary();
timelineLabelStyle = Resources["TimelineLabel"] as Style;
this.PropertyChanged += ((sender, e) =>
{
PropertyChangedDictAction.Where(s => s.Key(e.PropertyName)).ForEach(s =>
{
Console.WriteLine("進來了" + e.PropertyName);
s.Value();
});
});
}
private async void InitializeDictoinary()
{
await Task.Run(() =>
{
#region 屬性變更通知方法
PropertyChangedDictAction.Add(item => item.Equals("TimelineLabels"), () =>
{
if (null != TimelineLabels && TimelineLabels.Count != 0)
{
totalPage = TimelineLabels.Count / PageSize;
Console.WriteLine("進來字典" + totalPage);
Console.WriteLine("進來字典標籤數:" + TimelineLabels.Count);
GenericTimelineLabelByData(TimelineLabels, PageSize, currentPageIndex);
}
});
PropertyChangedDictAction.Add(item => item.Equals("PageSize"), () =>
{
if (PageSize > 200)
{
Console.WriteLine("警告,分頁數組不要超過200會引起系統緩慢");
PageSize = 200;
}
});
PropertyChangedDictAction.Add(item => item.Equals("DefaultItemWidth"), () =>
{
});
PropertyChangedDictAction.Add(item => item.Equals("TimelineEventSource"), () =>
{
});
PropertyChangedDictAction.Add(item => item.Equals("CurrentTimelineMode"), () =>
{
});
#endregion
#region 生成事件字典
TimelineEventGenericDictAction.Add(item => item == TimeLineEnum.TimeLineBandType.Days, (item, events, eventControl, getEvent) =>
{
foreach (var e in events)
{
Console.WriteLine("判斷天事件時間是:" + e.Date.ToShortDateString());
Console.WriteLine("判斷天座標的時間是:" + item.TimelineDate.ToShortDateString());
if (e.Date.Day == item.TimelineDate.Day &&
e.Date.Year == item.TimelineDate.Year &&
e.Date.Month == item.TimelineDate.Month)
{
eventControl.DataContext = e;
timelineEventItems.Children.Add(eventControl);
getEvent = true;
break;
}
return getEvent;
}
return false;
});
TimelineEventGenericDictAction.Add(item => item == TimeLineEnum.TimeLineBandType.Months, (item, events, eventControl, getEvent) =>
{
foreach (var e in events)
{
Console.WriteLine("判斷月事件時間是:" + e.Date.ToShortDateString());
Console.WriteLine("判斷月座標的時間是:" + item.TimelineDate.ToShortDateString());
if (e.Date.Year == item.TimelineDate.Year && e.Date.Month == item.TimelineDate.Month)
{
var o = new TimelineEventItem();
o.Content = "month";
o.Date = e.Date;
o.EventType = TimelineEventEnum.TimelineEventType.Detail;
eventControl.Name = o.Content + o.Date.Year + o.Date.Month;
eventControl.DataContext = o;
if (timelineEventItems.Children.IndexOf(eventControl) == -1)
{
timelineEventItems.Children.Add(eventControl);
getEvent = true;
break;
}
}
return getEvent;
}
return false;
});
TimelineEventGenericDictAction.Add(item => item == TimeLineEnum.TimeLineBandType.Years, (item, events, eventControl, getEvent) =>
{
foreach (var e in events)
{
Console.WriteLine("判斷年事件時間是:" + e.Date.ToShortDateString());
Console.WriteLine("判斷年座標的時間是:" + item.TimelineDate.ToShortDateString());
if (e.Date.Year == item.TimelineDate.Year)
{
var o = new TimelineEventItem();
o.Content = "year";
o.Date = e.Date;
o.EventType = TimelineEventEnum.TimelineEventType.Detail;
eventControl.DataContext = o;
eventControl.Name = o.Content + o.Date.Year + o.Date.Month;
if (timelineEventItems.Children.IndexOf(eventControl) == -1)
{
timelineEventItems.Children.Add(eventControl);
getEvent = true;
break;
}
}
return getEvent;
}
return false;
});
TimelineEventGenericDictAction.Add(item => item == TimeLineEnum.TimeLineBandType.Decades,
(item, events, eventControl, getEvent) =>
{
foreach (var e in events)
{
Console.WriteLine("判斷十年事件時間是:" + e.Date.ToShortDateString());
Console.WriteLine("判斷十年座標的時間是:" + item.TimelineDate.ToShortDateString());
if (e.Date.Year <= item.TimelineDate.Year && e.Date.Year >= item.TimelineDate.AddYears(-9).Year)
{
var o = new TimelineEventItem();
o.Content = "decade";
o.EventType = TimelineEventEnum.TimelineEventType.Detail;
o.Date = e.Date;
eventControl.DataContext = o;
eventControl.Name = o.Content + o.Date.Year + o.Date.Month;
if (timelineEventItems.Children.IndexOf(eventControl) == -1)
{
timelineEventItems.Children.Add(eventControl);
getEvent = true;
break;
}
}
return getEvent;
}
return false;
});
#endregion
});
}
public async Task ChangeBand(bool o)
{
await Task.Factory.StartNew(() =>
{
totalPage = TimelineLabels.Count / PageSize;
if (currentPageIndex <= totalPage && o) currentPageIndex++;
else return;
GenericTimelineLabelByData(TimelineLabels, PageSize, currentPageIndex);
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
/// <summary>
/// 分頁生成時間軸
/// </summary>
/// <param name="source"></param>
/// <param name="pageSize"></param>
/// <param name="pageIndex"></param>
/// <returns></returns>
private async void GenericTimelineLabelByData(ObservableCollection<TimelineLabelItem> source,
int pageSize, int pageIndex)
{
var skip = pageSize * pageIndex;
if (changedBand == 0)
{
//翻頁操作
tempTimelineLabels = new ObservableCollection<TimelineLabelItem>
(source.Skip(skip).
Take(pageSize).OrderBy(item => item.TimelineIndex));
}
else
{
//換軸操作
var takeCount = timelineLabelItems.Children.Count > PageSize ? timelineLabelItems.Children.Count : PageSize;
tempTimelineLabels = new ObservableCollection<TimelineLabelItem>
(source.Take(takeCount).
OrderBy(item => item.TimelineDate));
timelinePoint.Children.Clear();
timelineLabelItems.Children.Clear();
timelineEventItems.Children.Clear();
currentIndexInBand = 0;
changedBand = 0;
}
await BeginGeneric();
await GenericEvent();
LoadComplatedEventArgs args = new LoadComplatedEventArgs();
args.ok = true;
args.RoutedEvent = LoadComplatedEvent;
RaiseEvent(args);
}
#region 生成座標軸
private async Task BeginGeneric()
{
await Task.Factory.StartNew(() =>
{
tempTimelineLabels.ForEach(item =>
{
#region 生成點以及時間座標
var point = new TimelinePointControl();
var timelineLabelItem = new Lazy<Button>();
timelineLabelItem.Value.Style = timelineLabelStyle;
timelineLabelItem.Value.Content = item.TimelineLabelContent;
timelineLabelItem.Value.Name = getBtnLabelIndex(item);
timelineLabelItem.Value.Width = DefaultItemWidth;
timelinePoint.Children.Add(point);
switch (item.TimelineState)
{
case TimeLineEnum.TimelineLabelItemState.New:
timelineLabelItems.Children.Add(timelineLabelItem.Value);
break;
case TimeLineEnum.TimelineLabelItemState.Del:
var elements = timelineLabelItems.Children;
for (int i = 0; i < elements.Count; i++)
{
var btn = elements[i] as Button;
if (btn.Name.Equals(getBtnLabelIndex(item)))
timelineLabelItems.Children.Remove(elements[i]);
}
break;
default:
var normalBtn = this.FindName(getBtnLabelIndex(item)) as Button;
if (null == normalBtn)
timelineLabelItems.Children.Add(timelineLabelItem.Value);
break;
}
#endregion
});
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
#endregion
#region 生成座標軸上事件
private async Task GenericEvent()
{
await Task.Factory.StartNew(() =>
{
tempTimelineLabels.ForEach(item =>
{
Console.WriteLine("有:" + TimelineEventSource.Count);
if (item.TimelineState != TimeLineEnum.TimelineLabelItemState.Del
&& null != TimelineEventSource && TimelineEventSource.Count > 0)
{
Console.WriteLine("當前是第:" + currentIndexInBand + "個事件");
var e = new ObservableCollection<TimelineEventItem>(TimelineEventSource.Skip(currentIndexInBand));
var eventControl = new TimelineEventItemControl();
eventControl.ShowScatterEH += ((sender, eventArgs) =>
{
ShowScatterEventArgs args = new ShowScatterEventArgs();
args.svi = eventArgs.svi;
args.RoutedEvent = ShowScatterEvent;
RaiseEvent(args);
});
eventControl.ShowDetailEH += ((sender, eventArgs) =>
{
ShowDetailEventArgs args = new ShowDetailEventArgs();
args.startDate = eventArgs.startDate;
args.endDate = eventArgs.endDate;
args.showMode = eventArgs.showMode;
args.RoutedEvent = ShowDetailEvent;
RaiseEvent(args);
});
bool getEvent = false;
getEvent = TimelineEventGenericDictAction.Where(s => s.Key(item.TimelineType)).ForEach(s =>
s.Value(item, e, eventControl, getEvent))[0];
Console.WriteLine("拿到事件:" + getEvent);
if (!getEvent)
{
var o = new TimelineEventItem();
o.EventType = TimelineEventEnum.TimelineEventType.None;
eventControl.DataContext = o;
timelineEventItems.Children.Add(eventControl);
}
else
getEvent = false;
}
});
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
#endregion
private static string getBtnLabelIndex(TimelineLabelItem item)
{
return "index" + item.TimelineDate.Year.ToString()
+ item.TimelineDate.Month.ToString()
+ item.TimelineDate.Day.ToString();
}
public async Task<bool> doAnimation(bool o)
{
int key = 0;
if (o) key = 1;
return await Task.Factory.StartNew<bool>(() =>
{
for (int i = 0; i < timelineLabelItems.Children.Count; i++)
{
(timelinePoint.Children[i] as UserControl).DataContext = key;
(timelineLabelItems.Children[i] as Button).DataContext = key;
}
for (int i = 0; i < timelineEventItems.Children.Count; i++)
{
(timelineEventItems.Children[i] as UserControl).DataContext = key;
}
return true;
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}