support for .NET framework 3.5
Still have bugs
This commit is contained in:
1 parent
5878039e21
commit
7d6b491f25
704 files changed
+48273
-33
No files matched your search
@@ -0,0 +1,431 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
[TemplatePart(Name = ElementButtonAm, Type = typeof(RadioButton))]
|
||||
[TemplatePart(Name = ElementButtonPm, Type = typeof(RadioButton))]
|
||||
[TemplatePart(Name = ElementButtonConfirm, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ElementCanvas, Type = typeof(Canvas))]
|
||||
[TemplatePart(Name = ElementBorderTitle, Type = typeof(Border))]
|
||||
[TemplatePart(Name = ElementBorderClock, Type = typeof(Border))]
|
||||
[TemplatePart(Name = ElementPanelNum, Type = typeof(CirclePanel))]
|
||||
[TemplatePart(Name = ElementTimeStr, Type = typeof(TextBlock))]
|
||||
public class Clock : Control
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string ElementButtonAm = "PART_ButtonAm";
|
||||
private const string ElementButtonPm = "PART_ButtonPm";
|
||||
private const string ElementButtonConfirm = "PART_ButtonConfirm";
|
||||
private const string ElementCanvas = "PART_Canvas";
|
||||
private const string ElementBorderTitle = "PART_BorderTitle";
|
||||
private const string ElementBorderClock = "PART_BorderClock";
|
||||
private const string ElementPanelNum = "PART_PanelNum";
|
||||
private const string ElementTimeStr = "PART_TimeStr";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Data
|
||||
|
||||
private RadioButton _buttonAm;
|
||||
|
||||
private RadioButton _buttonPm;
|
||||
|
||||
private Button _buttonConfirm;
|
||||
|
||||
private Canvas _canvas;
|
||||
|
||||
private Border _borderTitle;
|
||||
|
||||
private Border _borderClock;
|
||||
|
||||
private ClockRadioButton _currentButton;
|
||||
|
||||
private RotateTransform _rotateTransformClock;
|
||||
|
||||
private CirclePanel _circlePanel;
|
||||
|
||||
private List<ClockRadioButton> _radioButtonList;
|
||||
|
||||
private TextBlock _blockTime;
|
||||
|
||||
private int _secValue;
|
||||
|
||||
private bool _appliedTemplate;
|
||||
|
||||
#endregion Data
|
||||
|
||||
#region Public Events
|
||||
|
||||
public static readonly RoutedEvent SelectedTimeChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("SelectedTimeChanged", RoutingStrategy.Direct,
|
||||
typeof(EventHandler<FunctionEventArgs<DateTime?>>), typeof(Clock));
|
||||
|
||||
public event EventHandler<FunctionEventArgs<DateTime?>> SelectedTimeChanged
|
||||
{
|
||||
add => AddHandler(SelectedTimeChangedEvent, value);
|
||||
remove => RemoveHandler(SelectedTimeChangedEvent, value);
|
||||
}
|
||||
|
||||
public event EventHandler<FunctionEventArgs<DateTime>> DisplayTimeChanged;
|
||||
|
||||
public event Action Confirmed;
|
||||
|
||||
#endregion Public Events
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public static readonly DependencyProperty SelectedTimeProperty = DependencyProperty.Register(
|
||||
"SelectedTime", typeof(DateTime?), typeof(Clock), new PropertyMetadata(default(DateTime?), OnSelectedTimeChanged));
|
||||
|
||||
private static void OnSelectedTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Clock)d;
|
||||
var v = (DateTime?)e.NewValue;
|
||||
ctl.DisplayTime = v ?? DateTime.Now;
|
||||
ctl.OnSelectedTimeChanged(new FunctionEventArgs<DateTime?>(SelectedTimeChangedEvent, ctl)
|
||||
{
|
||||
Info = v
|
||||
});
|
||||
}
|
||||
|
||||
public DateTime? SelectedTime
|
||||
{
|
||||
get => (DateTime?) GetValue(SelectedTimeProperty);
|
||||
set => SetValue(SelectedTimeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TimeFormatProperty = DependencyProperty.Register(
|
||||
"TimeFormat", typeof(string), typeof(Clock), new PropertyMetadata("HH:mm:ss"));
|
||||
|
||||
public string TimeFormat
|
||||
{
|
||||
get => (string) GetValue(TimeFormatProperty);
|
||||
set => SetValue(TimeFormatProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ClockRadioButtonStyleProperty = DependencyProperty.Register(
|
||||
"ClockRadioButtonStyle", typeof(Style), typeof(Clock), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style ClockRadioButtonStyle
|
||||
{
|
||||
get => (Style) GetValue(ClockRadioButtonStyleProperty);
|
||||
set => SetValue(ClockRadioButtonStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DisplayTimeProperty = DependencyProperty.Register(
|
||||
"DisplayTime", typeof(DateTime), typeof(Clock), new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnDisplayTimeChanged));
|
||||
|
||||
private static void OnDisplayTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Clock) d;
|
||||
var v = (DateTime) e.NewValue;
|
||||
ctl.Update(v);
|
||||
ctl.OnDisplayTimeChanged(new FunctionEventArgs<DateTime>(v));
|
||||
}
|
||||
|
||||
public DateTime DisplayTime
|
||||
{
|
||||
get => (DateTime) GetValue(DisplayTimeProperty);
|
||||
set => SetValue(DisplayTimeProperty, value);
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty ShowConfirmButtonProperty = DependencyProperty.Register(
|
||||
"ShowConfirmButton", typeof(bool), typeof(Clock), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
internal bool ShowConfirmButton
|
||||
{
|
||||
get => (bool)GetValue(ShowConfirmButtonProperty);
|
||||
set => SetValue(ShowConfirmButtonProperty, value);
|
||||
}
|
||||
|
||||
private int SecValue
|
||||
{
|
||||
get => _secValue;
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
_secValue = 59;
|
||||
}
|
||||
else if (value > 59)
|
||||
{
|
||||
_secValue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_secValue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
_appliedTemplate = false;
|
||||
if (_buttonAm != null)
|
||||
{
|
||||
_buttonAm.Click -= ButtonAm_OnClick;
|
||||
}
|
||||
|
||||
if (_buttonPm != null)
|
||||
{
|
||||
_buttonPm.Click -= ButtonPm_OnClick;
|
||||
}
|
||||
|
||||
if (_buttonConfirm != null)
|
||||
{
|
||||
_buttonConfirm.Click -= ButtonConfirm_OnClick;
|
||||
}
|
||||
|
||||
if (_borderTitle != null)
|
||||
{
|
||||
_borderTitle.MouseWheel -= BorderTitle_OnMouseWheel;
|
||||
}
|
||||
|
||||
if (_canvas != null)
|
||||
{
|
||||
_canvas.MouseWheel -= Canvas_OnMouseWheel;
|
||||
_canvas.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Canvas_OnClick));
|
||||
_canvas.MouseMove -= Canvas_OnMouseMove;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_buttonAm = GetTemplateChild(ElementButtonAm) as RadioButton;
|
||||
_buttonPm = GetTemplateChild(ElementButtonPm) as RadioButton;
|
||||
_buttonConfirm = GetTemplateChild(ElementButtonConfirm) as Button;
|
||||
_borderTitle = GetTemplateChild(ElementBorderTitle) as Border;
|
||||
_canvas = GetTemplateChild(ElementCanvas) as Canvas;
|
||||
_borderClock = GetTemplateChild(ElementBorderClock) as Border;
|
||||
_circlePanel = GetTemplateChild(ElementPanelNum) as CirclePanel;
|
||||
_blockTime = GetTemplateChild(ElementTimeStr) as TextBlock;
|
||||
|
||||
CheckNull();
|
||||
|
||||
_buttonAm.Click += ButtonAm_OnClick;
|
||||
_buttonPm.Click += ButtonPm_OnClick;
|
||||
_buttonConfirm.Click += ButtonConfirm_OnClick;
|
||||
_borderTitle.MouseWheel += BorderTitle_OnMouseWheel;
|
||||
|
||||
_canvas.MouseWheel += Canvas_OnMouseWheel;
|
||||
_canvas.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(Canvas_OnClick));
|
||||
_canvas.MouseMove += Canvas_OnMouseMove;
|
||||
|
||||
_rotateTransformClock = new RotateTransform();
|
||||
_borderClock.RenderTransform = _rotateTransformClock;
|
||||
|
||||
_radioButtonList = new List<ClockRadioButton>();
|
||||
for (var i = 0; i < 12; i++)
|
||||
{
|
||||
var num = i + 1;
|
||||
var button = new ClockRadioButton
|
||||
{
|
||||
Num = num,
|
||||
Content = num
|
||||
};
|
||||
button.SetBinding(StyleProperty, new Binding(ClockRadioButtonStyleProperty.Name) { Source = this });
|
||||
_radioButtonList.Add(button);
|
||||
_circlePanel.Children.Add(button);
|
||||
}
|
||||
|
||||
_appliedTemplate = true;
|
||||
if (SelectedTime.HasValue)
|
||||
{
|
||||
Update(SelectedTime.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayTime = DateTime.Now;
|
||||
Update(DisplayTime);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected virtual void OnSelectedTimeChanged(FunctionEventArgs<DateTime?> e) => RaiseEvent(e);
|
||||
|
||||
protected virtual void OnDisplayTimeChanged(FunctionEventArgs<DateTime> e)
|
||||
{
|
||||
var handler = DisplayTimeChanged;
|
||||
handler?.Invoke(this, e);
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void CheckNull()
|
||||
{
|
||||
|
||||
if (_buttonPm == null || _buttonAm == null || _buttonConfirm == null || _canvas == null ||
|
||||
_borderTitle == null || _borderClock == null || _circlePanel == null ||
|
||||
_blockTime == null) throw new Exception();
|
||||
}
|
||||
|
||||
private void BorderTitle_OnMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
if (e.Delta < 0)
|
||||
{
|
||||
SecValue--;
|
||||
Update();
|
||||
}
|
||||
else
|
||||
{
|
||||
SecValue++;
|
||||
Update();
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void Canvas_OnMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
var value = (int)_rotateTransformClock.Angle;
|
||||
if (e.Delta < 0)
|
||||
{
|
||||
value += 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
value -= 6;
|
||||
}
|
||||
if (value < 0)
|
||||
{
|
||||
value = value + 360;
|
||||
}
|
||||
_rotateTransformClock.Angle = value;
|
||||
|
||||
Update();
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void Canvas_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_currentButton = e.OriginalSource as ClockRadioButton;
|
||||
if (_currentButton != null)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
private void Canvas_OnMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
var value = ArithmeticHelper.CalAngle(new Point(85, 85), e.GetPosition(_canvas)) + 90;
|
||||
if (value < 0)
|
||||
{
|
||||
value = value + 360;
|
||||
}
|
||||
value = value - value % 6;
|
||||
_rotateTransformClock.Angle = value;
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!_appliedTemplate) return;
|
||||
var hValue = _currentButton.Num;
|
||||
if (_buttonPm.IsChecked == true)
|
||||
{
|
||||
hValue += 12;
|
||||
if (hValue == 24) hValue = 12;
|
||||
}
|
||||
else if (hValue == 12)
|
||||
{
|
||||
hValue = 0;
|
||||
}
|
||||
if (hValue == 12 && _buttonAm.IsChecked == true)
|
||||
{
|
||||
_buttonPm.IsChecked = true;
|
||||
_buttonAm.IsChecked = false;
|
||||
}
|
||||
|
||||
if (_blockTime != null)
|
||||
{
|
||||
DisplayTime = GetDisplayTime();
|
||||
_blockTime.Text = DisplayTime.ToString(TimeFormat);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
internal void Update(DateTime time)
|
||||
{
|
||||
if (!_appliedTemplate) return;
|
||||
var h = time.Hour;
|
||||
var m = time.Minute;
|
||||
|
||||
if (h >= 12)
|
||||
{
|
||||
_buttonPm.IsChecked = true;
|
||||
_buttonAm.IsChecked = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_buttonPm.IsChecked = false;
|
||||
_buttonAm.IsChecked = true;
|
||||
}
|
||||
|
||||
_rotateTransformClock.Angle = m * 6;
|
||||
|
||||
var hRest = h % 12;
|
||||
if (hRest == 0) hRest = 12;
|
||||
var ctl = _radioButtonList[hRest-1];
|
||||
ctl.IsChecked = true;
|
||||
ctl.RaiseEvent(new RoutedEventArgs { RoutedEvent = ButtonBase.ClickEvent });
|
||||
|
||||
_secValue = time.Second;
|
||||
Update();
|
||||
}
|
||||
|
||||
private void ButtonConfirm_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SelectedTime = DisplayTime;
|
||||
Confirmed?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取显示时间
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private DateTime GetDisplayTime()
|
||||
{
|
||||
var hValue = _currentButton.Num;
|
||||
if (_buttonPm.IsChecked == true)
|
||||
{
|
||||
hValue += 12;
|
||||
if (hValue == 24) hValue = 12;
|
||||
}
|
||||
else if (hValue == 12)
|
||||
{
|
||||
hValue = 0;
|
||||
}
|
||||
var now = DateTime.Now;
|
||||
return new DateTime(now.Year, now.Month, now.Day, hValue, (int)Math.Abs(_rotateTransformClock.Angle) % 360 / 6, _secValue);
|
||||
}
|
||||
|
||||
private void ButtonAm_OnClick(object sender, RoutedEventArgs e) => Update();
|
||||
|
||||
private void ButtonPm_OnClick(object sender, RoutedEventArgs e) => Update();
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class ClockRadioButton : RadioButton
|
||||
{
|
||||
public int Num { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class FlipClock : Control
|
||||
{
|
||||
public static readonly DependencyProperty NumberListProperty = DependencyProperty.Register(
|
||||
"NumberList", typeof(List<int>), typeof(FlipClock), new PropertyMetadata(new List<int> {0, 0, 0, 0, 0, 0}));
|
||||
|
||||
public List<int> NumberList
|
||||
{
|
||||
get => (List<int>) GetValue(NumberListProperty);
|
||||
set => SetValue(NumberListProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DisplayTimeProperty = DependencyProperty.Register(
|
||||
"DisplayTime", typeof(DateTime), typeof(FlipClock), new PropertyMetadata(default(DateTime), OnDisplayTimeChanged));
|
||||
|
||||
private static void OnDisplayTimeChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (FlipClock) s;
|
||||
var v = (DateTime) e.NewValue;
|
||||
|
||||
ctl.NumberList = new List<int>
|
||||
{
|
||||
v.Hour / 10,
|
||||
v.Hour % 10,
|
||||
v.Minute / 10,
|
||||
v.Minute % 10,
|
||||
v.Second / 10,
|
||||
v.Second % 10
|
||||
};
|
||||
}
|
||||
|
||||
public DateTime DisplayTime
|
||||
{
|
||||
get => (DateTime) GetValue(DisplayTimeProperty);
|
||||
set => SetValue(DisplayTimeProperty, value);
|
||||
}
|
||||
|
||||
public FlipClock()
|
||||
{
|
||||
var dispatcherTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(200)
|
||||
};
|
||||
dispatcherTimer.Tick += DispatcherTimer_Tick;
|
||||
dispatcherTimer.Start();
|
||||
}
|
||||
|
||||
private void DispatcherTimer_Tick(object sender, EventArgs e) => DisplayTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Media.Media3D;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class FlipNumber : Viewport3D
|
||||
{
|
||||
private bool _isLoaded;
|
||||
|
||||
private TextBlock _page1TextDown;
|
||||
|
||||
private TextBlock _page2TextUp;
|
||||
|
||||
private TextBlock _page2TextDown;
|
||||
|
||||
private TextBlock _page3TextUp;
|
||||
|
||||
private ContainerUIElement3D _page1;
|
||||
|
||||
private ContainerUIElement3D _page2;
|
||||
|
||||
private ContainerUIElement3D _page3;
|
||||
|
||||
private ContainerUIElement3D _content;
|
||||
|
||||
private readonly AxisAngleRotation3D _pageRotation3D;
|
||||
|
||||
private readonly DoubleAnimation _animation;
|
||||
|
||||
private bool _isAnimating;
|
||||
|
||||
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
|
||||
"CornerRadius", typeof(CornerRadius), typeof(FlipNumber), new PropertyMetadata(new CornerRadius(4)));
|
||||
|
||||
public CornerRadius CornerRadius
|
||||
{
|
||||
get => (CornerRadius)GetValue(CornerRadiusProperty);
|
||||
set => SetValue(CornerRadiusProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register(
|
||||
"Background", typeof(Brush), typeof(FlipNumber), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public Brush Background
|
||||
{
|
||||
get => (Brush)GetValue(BackgroundProperty);
|
||||
set => SetValue(BackgroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
|
||||
"Foreground", typeof(Brush), typeof(FlipNumber), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public Brush Foreground
|
||||
{
|
||||
get => (Brush)GetValue(ForegroundProperty);
|
||||
set => SetValue(ForegroundProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
|
||||
"FontSize", typeof(double), typeof(FlipNumber), new PropertyMetadata(70.0));
|
||||
|
||||
[TypeConverter(typeof(FontSizeConverter))]
|
||||
public double FontSize
|
||||
{
|
||||
get => (double)GetValue(FontSizeProperty);
|
||||
set => SetValue(FontSizeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty NumberProperty = DependencyProperty.Register(
|
||||
"Number", typeof(int), typeof(FlipNumber), new PropertyMetadata(ValueBoxes.Int0Box, OnNumberChanged));
|
||||
|
||||
private static void OnNumberChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) =>
|
||||
((FlipNumber)s).OnNumberChanged();
|
||||
|
||||
public int Number
|
||||
{
|
||||
get => (int)GetValue(NumberProperty);
|
||||
set => SetValue(NumberProperty, value);
|
||||
}
|
||||
|
||||
public FlipNumber()
|
||||
{
|
||||
var visual3D = new ModelVisual3D
|
||||
{
|
||||
Content = new DirectionalLight()
|
||||
};
|
||||
Children.Add(visual3D);
|
||||
|
||||
_pageRotation3D = new AxisAngleRotation3D
|
||||
{
|
||||
Angle = 0,
|
||||
Axis = new Vector3D(1, 0, 0)
|
||||
};
|
||||
|
||||
_animation = new DoubleAnimation(0, 180, new Duration(TimeSpan.FromSeconds(0.8)))
|
||||
{
|
||||
FillBehavior = FillBehavior.Stop
|
||||
};
|
||||
_animation.Completed += Animation_Completed;
|
||||
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
if (_isLoaded) return;
|
||||
_isLoaded = true;
|
||||
InitNumber();
|
||||
var transform3D = new RotateTransform3D(_pageRotation3D);
|
||||
_page2.Transform = transform3D;
|
||||
};
|
||||
}
|
||||
|
||||
private void Animation_Completed(object sender, EventArgs e)
|
||||
{
|
||||
_isAnimating = false;
|
||||
UpdateNumber();
|
||||
}
|
||||
|
||||
private void InitNumber()
|
||||
{
|
||||
_page1 = new ContainerUIElement3D();
|
||||
var num1 = Number > 8 ? 0 : Number + 1;
|
||||
var page1NumDown = CreateNumber(num1, false, out _page1TextDown);
|
||||
_page1.Children.Add(page1NumDown);
|
||||
|
||||
_page2 = new ContainerUIElement3D();
|
||||
var page2NumUp = CreateNumber(num1, true, out _page2TextUp);
|
||||
var page2NumDown = CreateNumber(Number, false, out _page2TextDown);
|
||||
_page2.Children.Add(page2NumUp);
|
||||
_page2.Children.Add(page2NumDown);
|
||||
|
||||
_page3 = new ContainerUIElement3D();
|
||||
var page3NumUp = CreateNumber(Number, true, out _page3TextUp);
|
||||
_page3.Children.Add(page3NumUp);
|
||||
var transform3D = new RotateTransform3D(new AxisAngleRotation3D
|
||||
{
|
||||
Angle = 180,
|
||||
Axis = new Vector3D(1, 0, 0)
|
||||
});
|
||||
_page3.Transform = transform3D;
|
||||
|
||||
_content = new ContainerUIElement3D
|
||||
{
|
||||
Children =
|
||||
{
|
||||
_page1,
|
||||
_page2,
|
||||
_page3
|
||||
}
|
||||
};
|
||||
Children.Add(_content);
|
||||
}
|
||||
|
||||
private bool CheckNull() => _page1TextDown != null && _page2TextUp != null && _page2TextDown != null && _page3TextUp != null;
|
||||
|
||||
private void OnNumberChanged()
|
||||
{
|
||||
if (!CheckNull()) return;
|
||||
|
||||
InitNewNumber();
|
||||
|
||||
if (_isAnimating)
|
||||
{
|
||||
_isAnimating = false;
|
||||
UpdateNumber();
|
||||
return;
|
||||
}
|
||||
|
||||
_isAnimating = true;
|
||||
_pageRotation3D.BeginAnimation(AxisAngleRotation3D.AngleProperty, _animation);
|
||||
}
|
||||
|
||||
private void InitNewNumber()
|
||||
{
|
||||
var num1 = Number.ToString();
|
||||
_page1TextDown.Text = num1;
|
||||
_page2TextUp.Text = num1;
|
||||
}
|
||||
|
||||
private void UpdateNumber()
|
||||
{
|
||||
_pageRotation3D.BeginAnimation(AxisAngleRotation3D.AngleProperty, null);
|
||||
_pageRotation3D.Angle = 0;
|
||||
|
||||
var num = Number.ToString();
|
||||
_page2TextDown.Text = num;
|
||||
_page3TextUp.Text = num;
|
||||
|
||||
_isAnimating = false;
|
||||
}
|
||||
|
||||
private Viewport2DVisual3D CreateNumber(int num, bool isUp, out TextBlock textBlock)
|
||||
{
|
||||
int flag;
|
||||
var rotateTransform = new RotateTransform();
|
||||
|
||||
if (isUp)
|
||||
{
|
||||
flag = -1;
|
||||
rotateTransform.Angle = 180;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = 1;
|
||||
}
|
||||
var halfWidth = ActualWidth / 2;
|
||||
var quarterWidth = ActualWidth / 4;
|
||||
var quarterHeight = ActualHeight / 4;
|
||||
|
||||
var meMaterial = new DiffuseMaterial();
|
||||
Viewport2DVisual3D.SetIsVisualHostMaterial(meMaterial, true);
|
||||
|
||||
textBlock = new TextBlock
|
||||
{
|
||||
RenderTransformOrigin = new Point(0.5, 0.5),
|
||||
Foreground = Foreground,
|
||||
FontSize = FontSize,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
TextAlignment = TextAlignment.Center,
|
||||
Text = num.ToString(),
|
||||
RenderTransform = rotateTransform,
|
||||
Margin = new Thickness(0, 0, 0, -quarterHeight),
|
||||
FontFamily = new FontFamily("Consolas")
|
||||
};
|
||||
|
||||
var border = new Border
|
||||
{
|
||||
ClipToBounds = true,
|
||||
CornerRadius = new CornerRadius(CornerRadius.TopLeft, CornerRadius.TopRight, 0, 0),
|
||||
Background = Background,
|
||||
Width = halfWidth,
|
||||
Height = quarterHeight,
|
||||
Child = textBlock
|
||||
};
|
||||
|
||||
var positions = new Point3DCollection
|
||||
{
|
||||
new Point3D(-quarterWidth * flag, quarterHeight, 0),
|
||||
new Point3D(-quarterWidth * flag, 0, 0),
|
||||
new Point3D(quarterWidth * flag, 0, 0),
|
||||
new Point3D(quarterWidth * flag, quarterHeight, 0)
|
||||
};
|
||||
|
||||
var triangleIndices = new Int32Collection
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
2,
|
||||
3
|
||||
};
|
||||
|
||||
var textureCoordinates = new PointCollection
|
||||
{
|
||||
new Point(0, 0),
|
||||
new Point(0, 1),
|
||||
new Point(1, 1),
|
||||
new Point(1, 0)
|
||||
};
|
||||
|
||||
var geometry3D = new MeshGeometry3D
|
||||
{
|
||||
Positions = positions,
|
||||
TriangleIndices = triangleIndices,
|
||||
TextureCoordinates = textureCoordinates
|
||||
};
|
||||
|
||||
var child = new Viewport2DVisual3D
|
||||
{
|
||||
Geometry = geometry3D,
|
||||
Visual = border,
|
||||
Material = meMaterial
|
||||
};
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// 作为刻度使用的文字块
|
||||
/// </summary>
|
||||
internal class SpeTextBlock : TextBlock
|
||||
{
|
||||
public double X { get; set; }
|
||||
|
||||
public SpeTextBlock() => Width = 60;
|
||||
|
||||
public SpeTextBlock(double x) : this()
|
||||
{
|
||||
X = x;
|
||||
Canvas.SetLeft(this, X);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
private DateTime _time;
|
||||
|
||||
/// <summary>
|
||||
/// 时间
|
||||
/// </summary>
|
||||
public DateTime Time
|
||||
{
|
||||
get => _time;
|
||||
set
|
||||
{
|
||||
_time = value;
|
||||
Text = $"{value.ToString(TimeFormat)}\r\n|";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 时间格式
|
||||
/// </summary>
|
||||
public string TimeFormat { get; set; } = "HH:mm";
|
||||
|
||||
/// <summary>
|
||||
/// 横向移动
|
||||
/// </summary>
|
||||
/// <param name="offsetX"></param>
|
||||
public void MoveX(double offsetX) => Canvas.SetLeft(this, X + offsetX);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,475 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// 时间条
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ElementBorderTop, Type = typeof(Border))]
|
||||
[TemplatePart(Name = ElementTextBlockMove, Type = typeof(TextBlock))]
|
||||
[TemplatePart(Name = ElementTextBlockSelected, Type = typeof(TextBlock))]
|
||||
[TemplatePart(Name = ElementCanvasSpe, Type = typeof(Canvas))]
|
||||
public class TimeBar : Control
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string ElementBorderTop = "PART_BorderTop";
|
||||
|
||||
private const string ElementTextBlockMove = "PART_TextBlockMove";
|
||||
|
||||
private const string ElementTextBlockSelected = "PART_TextBlockSelected";
|
||||
|
||||
private const string ElementCanvasSpe = "PART_CanvasSpe";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Data
|
||||
|
||||
private Border _borderTop;
|
||||
|
||||
private TextBlock _textBlockMove;
|
||||
|
||||
private TextBlock _textBlockSelected;
|
||||
|
||||
private Canvas _canvasSpe;
|
||||
|
||||
#endregion Data
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示刻度字符串
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowSpeStrProperty = DependencyProperty.Register(
|
||||
"ShowSpeStr", typeof(bool), typeof(TimeBar), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static readonly DependencyProperty TimeFormatProperty = DependencyProperty.Register(
|
||||
"TimeFormat", typeof(string), typeof(TimeBar), new PropertyMetadata("yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
public string TimeFormat
|
||||
{
|
||||
get => (string) GetValue(TimeFormatProperty);
|
||||
set => SetValue(TimeFormatProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刻度字符串
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty SpeStrProperty = DependencyProperty.Register(
|
||||
"SpeStr", typeof(string), typeof(TimeBar), new PropertyMetadata(Properties.Langs.Lang.Interval1h));
|
||||
|
||||
/// <summary>
|
||||
/// 选中时间
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty SelectedTimeProperty = DependencyProperty.Register(
|
||||
"SelectedTime", typeof(DateTime), typeof(TimeBar), new PropertyMetadata(default(DateTime), OnSelectedTimeChanged));
|
||||
|
||||
private static void OnSelectedTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is TimeBar timeBar && timeBar._textBlockSelected != null)
|
||||
{
|
||||
timeBar._textBlockSelected.Text = ((DateTime) e.NewValue).ToString(timeBar.TimeFormat);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 时间改变事件
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent TimeChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("TimeChanged", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<DateTime>>), typeof(TimeBar));
|
||||
|
||||
/// <summary>
|
||||
/// 刻度集合
|
||||
/// </summary>
|
||||
private readonly List<SpeTextBlock> _speBlockList = new List<SpeTextBlock>();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化时时间
|
||||
/// </summary>
|
||||
private readonly DateTime _starTime;
|
||||
|
||||
/// <summary>
|
||||
/// 时间段集合
|
||||
/// </summary>
|
||||
private readonly List<int> _timeSpeList = new List<int>
|
||||
{
|
||||
7200000,
|
||||
3600000,
|
||||
1800000,
|
||||
600000,
|
||||
300000,
|
||||
60000,
|
||||
30000
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 顶部border是否被按下
|
||||
/// </summary>
|
||||
private bool _borderTopIsMouseLeftButtonDown;
|
||||
|
||||
/// <summary>
|
||||
/// 控件是否处于拖动中
|
||||
/// </summary>
|
||||
private bool _isDragging;
|
||||
|
||||
/// <summary>
|
||||
/// 刻度单项宽度
|
||||
/// </summary>
|
||||
private double _itemWidth;
|
||||
|
||||
/// <summary>
|
||||
/// 鼠标按下拖动时选中的时间
|
||||
/// </summary>
|
||||
private DateTime _mouseDownTime;
|
||||
|
||||
/// <summary>
|
||||
/// 显示的刻度数目
|
||||
/// </summary>
|
||||
private int _speCount = 13;
|
||||
|
||||
/// <summary>
|
||||
/// 刻度区间编号
|
||||
/// </summary>
|
||||
private int _speIndex = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 刻度单次偏移
|
||||
/// </summary>
|
||||
private double _tempOffsetX;
|
||||
|
||||
/// <summary>
|
||||
/// 刻度总偏移
|
||||
/// </summary>
|
||||
private double _totalOffsetX;
|
||||
|
||||
private readonly bool _isLoaded;
|
||||
|
||||
public TimeBar()
|
||||
{
|
||||
_starTime = DateTime.Now;
|
||||
SelectedTime = new DateTime(_starTime.Year, _starTime.Month, _starTime.Day, 0, 0, 0);
|
||||
_starTime = SelectedTime;
|
||||
_isLoaded = true;
|
||||
SizeChanged += TimeBar_OnSizeChanged;
|
||||
MouseMove += TimeBar_OnMouseMove;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_borderTop != null)
|
||||
{
|
||||
_borderTop.MouseLeftButtonDown -= BorderTop_OnMouseLeftButtonDown;
|
||||
_borderTop.PreviewMouseLeftButtonUp -= BorderTop_OnPreviewMouseLeftButtonUp;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_borderTop = GetTemplateChild(ElementBorderTop) as Border;
|
||||
_textBlockMove = GetTemplateChild(ElementTextBlockMove) as TextBlock;
|
||||
_textBlockSelected = GetTemplateChild(ElementTextBlockSelected) as TextBlock;
|
||||
_canvasSpe = GetTemplateChild(ElementCanvasSpe) as Canvas;
|
||||
|
||||
CheckNull();
|
||||
_borderTop.MouseLeftButtonDown += BorderTop_OnMouseLeftButtonDown;
|
||||
_borderTop.PreviewMouseLeftButtonUp += BorderTop_OnPreviewMouseLeftButtonUp;
|
||||
var behavior = new MouseDragElementBehaviorEx
|
||||
{
|
||||
LockY = true,
|
||||
};
|
||||
behavior.DragBegun += DragElementBehavior_OnDragBegun;
|
||||
behavior.Dragging += MouseDragElementBehavior_OnDragging;
|
||||
behavior.DragFinished += MouseDragElementBehavior_OnDragFinished;
|
||||
var collection = Interaction.GetBehaviors(_borderTop);
|
||||
collection.Add(behavior);
|
||||
|
||||
if (_isLoaded)
|
||||
{
|
||||
TimeBar_OnSizeChanged(null, null);
|
||||
}
|
||||
_textBlockSelected.Text = SelectedTime.ToString(TimeFormat);
|
||||
}
|
||||
|
||||
private void CheckNull()
|
||||
{
|
||||
if (_borderTop == null || _textBlockMove == null|| _textBlockSelected == null || _canvasSpe == null) throw new Exception();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示刻度字符串
|
||||
/// </summary>
|
||||
public bool ShowSpeStr
|
||||
{
|
||||
get => (bool)GetValue(ShowSpeStrProperty);
|
||||
set => SetValue(ShowSpeStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刻度字符串
|
||||
/// </summary>
|
||||
internal string SpeStr
|
||||
{
|
||||
get => (string)GetValue(SpeStrProperty);
|
||||
set => SetValue(SpeStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选中时间
|
||||
/// </summary>
|
||||
internal DateTime SelectedTime
|
||||
{
|
||||
get => (DateTime)GetValue(SelectedTimeProperty);
|
||||
set => SetValue(SelectedTimeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刻度区间编号
|
||||
/// </summary>
|
||||
public int SpeIndex
|
||||
{
|
||||
get => _speIndex;
|
||||
private set
|
||||
{
|
||||
if (_speIndex == value) return;
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
SpeStr = Properties.Langs.Lang.Interval2h;
|
||||
_speIndex = 0;
|
||||
return;
|
||||
}
|
||||
if (value > 6)
|
||||
{
|
||||
SpeStr = Properties.Langs.Lang.Interval30s;
|
||||
_speIndex = 6;
|
||||
return;
|
||||
}
|
||||
SetSpeTimeFormat("HH:mm");
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
SpeStr = Properties.Langs.Lang.Interval2h;
|
||||
break;
|
||||
case 1:
|
||||
SpeStr = Properties.Langs.Lang.Interval1h;
|
||||
break;
|
||||
case 2:
|
||||
SpeStr = Properties.Langs.Lang.Interval30m;
|
||||
break;
|
||||
case 3:
|
||||
SpeStr = Properties.Langs.Lang.Interval10m;
|
||||
break;
|
||||
case 4:
|
||||
SpeStr = Properties.Langs.Lang.Interval5m;
|
||||
break;
|
||||
case 5:
|
||||
SpeStr = Properties.Langs.Lang.Interval1m;
|
||||
break;
|
||||
case 6:
|
||||
SetSpeTimeFormat("HH:mm:ss");
|
||||
SpeStr = Properties.Langs.Lang.Interval30s;
|
||||
break;
|
||||
}
|
||||
_speIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 时间改变事件
|
||||
/// </summary>
|
||||
public event EventHandler<FunctionEventArgs<DateTime>> TimeChanged
|
||||
{
|
||||
add => AddHandler(TimeChangedEvent, value);
|
||||
remove => RemoveHandler(TimeChangedEvent, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置刻度时间格式
|
||||
/// </summary>
|
||||
/// <param name="format"></param>
|
||||
private void SetSpeTimeFormat(string format)
|
||||
{
|
||||
foreach (var item in _speBlockList)
|
||||
item.TimeFormat = format;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置显示的时间
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
public void SetShowTime(DateTime time)
|
||||
{
|
||||
if (_isDragging || _borderTopIsMouseLeftButtonDown) return;
|
||||
|
||||
SelectedTime = time;
|
||||
_totalOffsetX = (_starTime - SelectedTime).TotalMilliseconds / _timeSpeList[SpeIndex] * _itemWidth;
|
||||
Update();
|
||||
TimeBar_OnMouseMove(null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
var rest = (_totalOffsetX + _tempOffsetX) % _itemWidth;
|
||||
for (var i = 0; i < _speCount; i++)
|
||||
{
|
||||
var item = _speBlockList[i];
|
||||
item.MoveX(rest + (_itemWidth - item.Width) / 2);
|
||||
}
|
||||
var sub = rest <= 0 ? _speCount / 2 : _speCount / 2 - 1;
|
||||
|
||||
for (var i = 0; i < _speCount; i++)
|
||||
_speBlockList[i].Time = TimeConvert(SelectedTime).AddMilliseconds((i - sub) * _timeSpeList[_speIndex]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 时间转换
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <returns></returns>
|
||||
private DateTime TimeConvert(DateTime time)
|
||||
{
|
||||
switch (_speIndex)
|
||||
{
|
||||
case 0:
|
||||
return new DateTime(time.Year, time.Month, time.Day, time.Hour / 2 * 2, 0, 0);
|
||||
case 1:
|
||||
return new DateTime(time.Year, time.Month, time.Day, time.Hour, 0, 0);
|
||||
case 2:
|
||||
return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute / 30 * 30, 0);
|
||||
case 3:
|
||||
return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute / 10 * 10, 0);
|
||||
case 4:
|
||||
return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute / 5 * 5, 0);
|
||||
case 5:
|
||||
return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, 0);
|
||||
case 6:
|
||||
return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second / 30 * 30);
|
||||
default:
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 鼠标滚轮滚动时改变刻度区间
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
if (Mouse.LeftButton == MouseButtonState.Pressed) return;
|
||||
SpeIndex += e.Delta > 0 ? 1 : -1;
|
||||
_totalOffsetX = (_starTime - SelectedTime).TotalMilliseconds / _timeSpeList[SpeIndex] * _itemWidth;
|
||||
Update();
|
||||
TimeBar_OnMouseMove(null, null);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void MouseDragElementBehavior_OnDragging(object sender, MouseEventArgs e)
|
||||
{
|
||||
_isDragging = true;
|
||||
_tempOffsetX = _borderTop.RenderTransform.Value.OffsetX;
|
||||
|
||||
SelectedTime = _mouseDownTime -
|
||||
TimeSpan.FromMilliseconds(_tempOffsetX / _itemWidth * _timeSpeList[_speIndex]);
|
||||
Update();
|
||||
_borderTopIsMouseLeftButtonDown = false;
|
||||
}
|
||||
|
||||
private void MouseDragElementBehavior_OnDragFinished(object sender, MouseEventArgs e)
|
||||
{
|
||||
_tempOffsetX = 0;
|
||||
_totalOffsetX = (_totalOffsetX + _borderTop.RenderTransform.Value.OffsetX) % ActualWidth;
|
||||
_borderTop.RenderTransform = new TranslateTransform();
|
||||
RaiseEvent(new FunctionEventArgs<DateTime>(TimeChangedEvent, this)
|
||||
{
|
||||
Info = SelectedTime
|
||||
});
|
||||
_isDragging = false;
|
||||
}
|
||||
|
||||
private void DragElementBehavior_OnDragBegun(object sender, MouseEventArgs e) => _mouseDownTime = SelectedTime;
|
||||
|
||||
private void TimeBar_OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
_speBlockList.Clear();
|
||||
_canvasSpe.Children.Clear();
|
||||
|
||||
_speCount = (int)(ActualWidth / 800 * 9) | 1;
|
||||
|
||||
var itemWidthOld = _itemWidth;
|
||||
_itemWidth = ActualWidth / _speCount;
|
||||
_totalOffsetX = _itemWidth / itemWidthOld * _totalOffsetX % ActualWidth;
|
||||
if (double.IsNaN(_totalOffsetX))
|
||||
_totalOffsetX = 0;
|
||||
|
||||
var rest = (_totalOffsetX + _tempOffsetX) % _itemWidth;
|
||||
var sub = rest <= 0 || double.IsNaN(rest) ? _speCount / 2 : _speCount / 2 - 1;
|
||||
for (var i = 0; i < _speCount; i++)
|
||||
{
|
||||
var block = new SpeTextBlock
|
||||
{
|
||||
Time = TimeConvert(SelectedTime).AddMilliseconds((i - sub) * _timeSpeList[_speIndex]),
|
||||
TextAlignment = TextAlignment.Center,
|
||||
TimeFormat = "HH:mm"
|
||||
};
|
||||
_speBlockList.Add(block);
|
||||
_canvasSpe.Children.Add(block);
|
||||
}
|
||||
if (_speIndex == 6)
|
||||
SetSpeTimeFormat("HH:mm:ss");
|
||||
ShowSpeStr = ActualWidth > 320;
|
||||
for (var i = 0; i < _speCount; i++)
|
||||
{
|
||||
var item = _speBlockList[i];
|
||||
item.X = _itemWidth * i;
|
||||
item.MoveX((_itemWidth - item.Width) / 2);
|
||||
}
|
||||
|
||||
Update();
|
||||
TimeBar_OnMouseMove(null, null);
|
||||
}
|
||||
|
||||
private void TimeBar_OnMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
var p = Mouse.GetPosition(this);
|
||||
var mlliseconds = (p.X - ActualWidth / 2) / _itemWidth * _timeSpeList[_speIndex];
|
||||
if (double.IsInfinity(mlliseconds)) return;
|
||||
_textBlockMove.Text = mlliseconds < 0
|
||||
? (SelectedTime - TimeSpan.FromMilliseconds(-mlliseconds)).ToString(TimeFormat)
|
||||
: (SelectedTime + TimeSpan.FromMilliseconds(mlliseconds)).ToString(TimeFormat);
|
||||
_textBlockMove.Margin = new Thickness(p.X - _textBlockMove.ActualWidth / 2, 2, 0, 0);
|
||||
}
|
||||
|
||||
private void BorderTop_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) => _borderTopIsMouseLeftButtonDown = true;
|
||||
|
||||
private void BorderTop_OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (_borderTopIsMouseLeftButtonDown)
|
||||
{
|
||||
_borderTopIsMouseLeftButtonDown = false;
|
||||
|
||||
var p = Mouse.GetPosition(this);
|
||||
_tempOffsetX = ActualWidth / 2 - p.X;
|
||||
SelectedTime -= TimeSpan.FromMilliseconds(_tempOffsetX / _itemWidth * _timeSpeList[_speIndex]);
|
||||
Update();
|
||||
_totalOffsetX = (_totalOffsetX + _tempOffsetX) % ActualWidth;
|
||||
_tempOffsetX = 0;
|
||||
TimeBar_OnMouseMove(null, null);
|
||||
RaiseEvent(new FunctionEventArgs<DateTime>(TimeChangedEvent, this)
|
||||
{
|
||||
Info = SelectedTime
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user