add timebar
No files matched your search
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
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,52 @@
|
||||
<UserControl x:Class="HandyControl.Controls.TimeBar"
|
||||
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:tools="clr-namespace:HandyControl.Tools"
|
||||
xmlns:interactivity="clr-namespace:HandyControl.Interactivity"
|
||||
mc:Ignorable="d"
|
||||
UseLayoutRounding="True"
|
||||
BorderThickness="0,1,0,0"
|
||||
Foreground="White"
|
||||
Background="Black"
|
||||
MouseMove="TimeBar_OnMouseMove"
|
||||
SizeChanged="TimeBar_OnSizeChanged"
|
||||
Height="60"
|
||||
Name="MyUserControl"
|
||||
BorderBrush="#232323">
|
||||
<UserControl.Triggers>
|
||||
<EventTrigger RoutedEvent="FrameworkElement.MouseEnter" SourceName="MyUserControl">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="TextBlockSelected">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<EventTrigger RoutedEvent="FrameworkElement.MouseLeave" SourceName="MyUserControl">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="TextBlockSelected">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</UserControl.Triggers>
|
||||
<Grid>
|
||||
<Border BorderThickness="0,0,0,4" BorderBrush="White" VerticalAlignment="Top" Height="52">
|
||||
<TextBlock FontSize="16" Text="{Binding SelectedTime,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl},StringFormat=yyyy-MM-dd HH:mm:ss}" VerticalAlignment="Top" Margin="0,14,0,0" HorizontalAlignment="Center"></TextBlock>
|
||||
</Border>
|
||||
<TextBlock Visibility="{Binding ShowSpeStr,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl},Converter={StaticResource Boolean2VisibilityConverter}}" Text="{Binding SpeStr,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,14,10,0"></TextBlock>
|
||||
<TextBlock Visibility="Collapsed" Name="TextBlockSelected" HorizontalAlignment="Left" Text="2017-10-16 06:29:28" VerticalAlignment="Top" Margin="0,2,0,0"></TextBlock>
|
||||
<Border Width="1" Background="{DynamicResource DangerBrush}"></Border>
|
||||
<Canvas Name="CanvasSpe" VerticalAlignment="Bottom" Height="28" ></Canvas>
|
||||
<Border PreviewMouseLeftButtonUp="BorderTop_OnPreviewMouseLeftButtonUp" MouseLeftButtonDown="BorderTop_OnMouseLeftButtonDown" Name="BorderTop" Background="Transparent" Cursor="Hand">
|
||||
<interactivity:Interaction.Behaviors>
|
||||
<tools:MouseDragElementBehaviorEx LockY="True" x:Name="DragElementBehavior" DragBegun="DragElementBehavior_OnDragBegun" DragFinished="MouseDragElementBehavior_OnDragFinished" Dragging="MouseDragElementBehavior_OnDragging"/>
|
||||
</interactivity:Interaction.Behaviors>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,390 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// TimeBar.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class TimeBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否显示刻度字符串
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowSpeStrProperty = DependencyProperty.Register(
|
||||
"ShowSpeStr", typeof(bool), typeof(TimeBar), new PropertyMetadata(default(bool)));
|
||||
|
||||
/// <summary>
|
||||
/// 刻度字符串
|
||||
/// </summary>
|
||||
private static readonly DependencyProperty SpeStrProperty = DependencyProperty.Register(
|
||||
"SpeStr", typeof(string), typeof(TimeBar), new PropertyMetadata("间隔1小时"));
|
||||
|
||||
/// <summary>
|
||||
/// 选中时间
|
||||
/// </summary>
|
||||
private static readonly DependencyProperty SelectedTimeProperty = DependencyProperty.Register(
|
||||
"SelectedTime", typeof(DateTime), typeof(TimeBar));
|
||||
|
||||
/// <summary>
|
||||
/// 时间改变事件
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent TimeChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("ButtonCloseClick", 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;
|
||||
|
||||
public TimeBar()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_starTime = DateTime.Now;
|
||||
SelectedTime = new DateTime(_starTime.Year, _starTime.Month, _starTime.Day, 0, 0, 0);
|
||||
_starTime = SelectedTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示刻度字符串
|
||||
/// </summary>
|
||||
public bool ShowSpeStr
|
||||
{
|
||||
get => (bool)GetValue(ShowSpeStrProperty);
|
||||
set => SetValue(ShowSpeStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刻度字符串
|
||||
/// </summary>
|
||||
private string SpeStr
|
||||
{
|
||||
get => (string)GetValue(SpeStrProperty);
|
||||
set => SetValue(SpeStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 选中时间
|
||||
/// </summary>
|
||||
private 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 = "间隔2小时";
|
||||
_speIndex = 0;
|
||||
return;
|
||||
}
|
||||
if (value > 6)
|
||||
{
|
||||
SpeStr = "间隔30秒";
|
||||
_speIndex = 6;
|
||||
return;
|
||||
}
|
||||
SetSpeTimeFormat("HH:mm");
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
SpeStr = "间隔2小时";
|
||||
break;
|
||||
case 1:
|
||||
SpeStr = "间隔1小时";
|
||||
break;
|
||||
case 2:
|
||||
SpeStr = "间隔30分钟";
|
||||
break;
|
||||
case 3:
|
||||
SpeStr = "间隔10分钟";
|
||||
break;
|
||||
case 4:
|
||||
SpeStr = "间隔5分钟";
|
||||
break;
|
||||
case 5:
|
||||
SpeStr = "间隔1分钟";
|
||||
break;
|
||||
case 6:
|
||||
SetSpeTimeFormat("HH:mm:ss");
|
||||
SpeStr = "间隔30秒";
|
||||
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;
|
||||
TextBlockSelected.Text = mlliseconds < 0
|
||||
? (SelectedTime - TimeSpan.FromMilliseconds(-mlliseconds)).ToString("yyyy-MM-dd HH:mm:ss")
|
||||
: (SelectedTime + TimeSpan.FromMilliseconds(mlliseconds)).ToString("yyyy-MM-dd HH:mm:ss");
|
||||
TextBlockSelected.Margin = new Thickness(p.X - TextBlockSelected.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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,10 @@
|
||||
<Compile Include="Controls\Pagination.xaml.cs">
|
||||
<DependentUpon>Pagination.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Controls\TimeBar\SpeTextBlock.cs" />
|
||||
<Compile Include="Controls\TimeBar\TimeBar.xaml.cs">
|
||||
<DependentUpon>TimeBar.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Data\ColorRange.cs" />
|
||||
<Compile Include="Data\Enum\IpType.cs" />
|
||||
<Compile Include="Data\Enum\TextType.cs" />
|
||||
@@ -89,6 +93,7 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Tools\AnimationHelper.cs" />
|
||||
<Compile Include="Tools\ArithmeticHelper.cs" />
|
||||
<Compile Include="Tools\Converter\Boolean2BooleanFeConverter.cs" />
|
||||
<Compile Include="Tools\Converter\Boolean2VisibilityFeConverter.cs" />
|
||||
<Compile Include="Tools\Converter\BooleanArr2VisibilityConverter.cs" />
|
||||
@@ -103,6 +108,7 @@
|
||||
<Compile Include="Tools\Converter\TreeViewItemMarginConverter.cs" />
|
||||
<Compile Include="Tools\Extension\ColorExtension.cs" />
|
||||
<Compile Include="Tools\Extension\UIElementExtension.cs" />
|
||||
<Compile Include="Tools\MouseDragElementBehaviorEx.cs" />
|
||||
<Compile Include="Tools\RegularJudgment.cs" />
|
||||
<Compile Include="Tools\RegularPatterns.cs" />
|
||||
</ItemGroup>
|
||||
@@ -130,6 +136,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Controls\TimeBar\TimeBar.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Themes\Basic\Basic.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
public class ArithmeticHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取布局范围框
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
/// <returns></returns>
|
||||
internal static Rect GetLayoutRect(FrameworkElement element)
|
||||
{
|
||||
var num1 = element.ActualWidth;
|
||||
var num2 = element.ActualHeight;
|
||||
if (element is Image || element is MediaElement)
|
||||
if (element.Parent is Canvas)
|
||||
{
|
||||
num1 = double.IsNaN(element.Width) ? num1 : element.Width;
|
||||
num2 = double.IsNaN(element.Height) ? num2 : element.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
num1 = element.RenderSize.Width;
|
||||
num2 = element.RenderSize.Height;
|
||||
}
|
||||
var width = element.Visibility == Visibility.Collapsed ? 0.0 : num1;
|
||||
var height = element.Visibility == Visibility.Collapsed ? 0.0 : num2;
|
||||
var margin = element.Margin;
|
||||
var layoutSlot = LayoutInformation.GetLayoutSlot(element);
|
||||
var x = 0.0;
|
||||
var y = 0.0;
|
||||
switch (element.HorizontalAlignment)
|
||||
{
|
||||
case HorizontalAlignment.Left:
|
||||
x = layoutSlot.Left + margin.Left;
|
||||
break;
|
||||
case HorizontalAlignment.Center:
|
||||
x = (layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - width / 2.0;
|
||||
break;
|
||||
case HorizontalAlignment.Right:
|
||||
x = layoutSlot.Right - margin.Right - width;
|
||||
break;
|
||||
case HorizontalAlignment.Stretch:
|
||||
x = Math.Max(layoutSlot.Left + margin.Left,
|
||||
(layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - width / 2.0);
|
||||
break;
|
||||
}
|
||||
switch (element.VerticalAlignment)
|
||||
{
|
||||
case VerticalAlignment.Top:
|
||||
y = layoutSlot.Top + margin.Top;
|
||||
break;
|
||||
case VerticalAlignment.Center:
|
||||
y = (layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - height / 2.0;
|
||||
break;
|
||||
case VerticalAlignment.Bottom:
|
||||
y = layoutSlot.Bottom - margin.Bottom - height;
|
||||
break;
|
||||
case VerticalAlignment.Stretch:
|
||||
y = Math.Max(layoutSlot.Top + margin.Top,
|
||||
(layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - height / 2.0);
|
||||
break;
|
||||
}
|
||||
return new Rect(x, y, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// 鼠标拖动行为,该类是反编译微软的System.Windows.Interactivity程序集得到的,并对其做了些扩展
|
||||
/// </summary>
|
||||
internal class MouseDragElementBehaviorEx : Behavior<FrameworkElement>
|
||||
{
|
||||
public static readonly DependencyProperty XProperty = DependencyProperty.Register(nameof(X), typeof(double),
|
||||
typeof(MouseDragElementBehaviorEx), new PropertyMetadata(double.NaN, OnXChanged));
|
||||
|
||||
public static readonly DependencyProperty YProperty = DependencyProperty.Register(nameof(Y), typeof(double),
|
||||
typeof(MouseDragElementBehaviorEx), new PropertyMetadata(double.NaN, OnYChanged));
|
||||
|
||||
public static readonly DependencyProperty ConstrainToParentBoundsProperty =
|
||||
DependencyProperty.Register(nameof(ConstrainToParentBounds), typeof(bool),
|
||||
typeof(MouseDragElementBehaviorEx), new PropertyMetadata(false, OnConstrainToParentBoundsChanged));
|
||||
|
||||
private Transform _cachedRenderTransform;
|
||||
private Point _relativePosition;
|
||||
private bool _settingPosition;
|
||||
|
||||
/// <summary>
|
||||
/// 是否固定住Y轴
|
||||
/// </summary>
|
||||
public bool LockY { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否固定住X轴
|
||||
/// </summary>
|
||||
public bool LockX { get; set; }
|
||||
|
||||
public double X
|
||||
{
|
||||
get => (double)GetValue(MouseDragElementBehavior.XProperty);
|
||||
set => SetValue(MouseDragElementBehavior.XProperty, value);
|
||||
}
|
||||
|
||||
public double Y
|
||||
{
|
||||
get => (double)GetValue(MouseDragElementBehavior.YProperty);
|
||||
set => SetValue(MouseDragElementBehavior.YProperty, value);
|
||||
}
|
||||
|
||||
public bool ConstrainToParentBounds
|
||||
{
|
||||
get => (bool)GetValue(MouseDragElementBehavior.ConstrainToParentBoundsProperty);
|
||||
set => SetValue(MouseDragElementBehavior.ConstrainToParentBoundsProperty, value);
|
||||
}
|
||||
|
||||
private Rect ElementBounds
|
||||
{
|
||||
get
|
||||
{
|
||||
var layoutRect = ArithmeticHelper.GetLayoutRect(AssociatedObject);
|
||||
return new Rect(new Point(0.0, 0.0), new Size(layoutRect.Width, layoutRect.Height));
|
||||
}
|
||||
}
|
||||
|
||||
private FrameworkElement ParentElement => AssociatedObject.Parent as FrameworkElement;
|
||||
|
||||
private UIElement RootElement
|
||||
{
|
||||
get
|
||||
{
|
||||
DependencyObject reference = AssociatedObject;
|
||||
for (var dependencyObject = reference;
|
||||
dependencyObject != null;
|
||||
dependencyObject = VisualTreeHelper.GetParent(reference))
|
||||
reference = dependencyObject;
|
||||
return reference as UIElement;
|
||||
}
|
||||
}
|
||||
|
||||
private Transform RenderTransform
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_cachedRenderTransform == null ||
|
||||
!ReferenceEquals(_cachedRenderTransform, AssociatedObject.RenderTransform))
|
||||
RenderTransform = CloneTransform(AssociatedObject.RenderTransform);
|
||||
return _cachedRenderTransform;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (Equals(_cachedRenderTransform, value))
|
||||
return;
|
||||
_cachedRenderTransform = value;
|
||||
AssociatedObject.RenderTransform = value;
|
||||
}
|
||||
}
|
||||
|
||||
public event MouseEventHandler DragBegun;
|
||||
|
||||
public event MouseEventHandler Dragging;
|
||||
|
||||
public event MouseEventHandler DragFinished;
|
||||
|
||||
private static void OnXChanged(object sender, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
var dragElementBehavior = (MouseDragElementBehaviorEx)sender;
|
||||
dragElementBehavior.UpdatePosition(new Point((double)args.NewValue, dragElementBehavior.Y));
|
||||
}
|
||||
|
||||
private static void OnYChanged(object sender, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
var dragElementBehavior = (MouseDragElementBehaviorEx)sender;
|
||||
dragElementBehavior.UpdatePosition(new Point(dragElementBehavior.X, (double)args.NewValue));
|
||||
}
|
||||
|
||||
private static void OnConstrainToParentBoundsChanged(object sender, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
var dragElementBehavior = (MouseDragElementBehaviorEx)sender;
|
||||
dragElementBehavior.UpdatePosition(new Point(dragElementBehavior.X, dragElementBehavior.Y));
|
||||
}
|
||||
|
||||
private void UpdatePosition(Point point)
|
||||
{
|
||||
if (_settingPosition || AssociatedObject == null)
|
||||
return;
|
||||
var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement));
|
||||
ApplyTranslation(double.IsNaN(point.X) ? 0.0 : point.X - transformOffset.X,
|
||||
double.IsNaN(point.Y) ? 0.0 : point.Y - transformOffset.Y);
|
||||
}
|
||||
|
||||
private void ApplyTranslation(double x, double y)
|
||||
{
|
||||
if (ParentElement == null)
|
||||
return;
|
||||
var point = TransformAsVector(RootElement.TransformToVisual(ParentElement), x, y);
|
||||
x = point.X;
|
||||
y = point.Y;
|
||||
if (ConstrainToParentBounds)
|
||||
{
|
||||
var parentElement = ParentElement;
|
||||
var rect1 = new Rect(0.0, 0.0, parentElement.ActualWidth, parentElement.ActualHeight);
|
||||
var rect2 = AssociatedObject.TransformToVisual(parentElement).TransformBounds(ElementBounds);
|
||||
rect2.X += x;
|
||||
rect2.Y += y;
|
||||
if (!RectContainsRect(rect1, rect2))
|
||||
{
|
||||
if (rect2.X < rect1.Left)
|
||||
{
|
||||
var num = rect2.X - rect1.Left;
|
||||
x -= num;
|
||||
}
|
||||
else if (rect2.Right > rect1.Right)
|
||||
{
|
||||
var num = rect2.Right - rect1.Right;
|
||||
x -= num;
|
||||
}
|
||||
if (rect2.Y < rect1.Top)
|
||||
{
|
||||
var num = rect2.Y - rect1.Top;
|
||||
y -= num;
|
||||
}
|
||||
else if (rect2.Bottom > rect1.Bottom)
|
||||
{
|
||||
var num = rect2.Bottom - rect1.Bottom;
|
||||
y -= num;
|
||||
}
|
||||
}
|
||||
}
|
||||
ApplyTranslationTransform(x, y);
|
||||
}
|
||||
|
||||
internal void ApplyTranslationTransform(double x, double y)
|
||||
{
|
||||
var renderTransform = RenderTransform;
|
||||
var translateTransform = renderTransform as TranslateTransform;
|
||||
if (translateTransform == null)
|
||||
{
|
||||
var matrixTransform = renderTransform as MatrixTransform;
|
||||
if (renderTransform is TransformGroup transformGroup1)
|
||||
{
|
||||
if (transformGroup1.Children.Count > 0)
|
||||
translateTransform =
|
||||
transformGroup1.Children[transformGroup1.Children.Count - 1] as TranslateTransform;
|
||||
if (translateTransform == null)
|
||||
{
|
||||
translateTransform = new TranslateTransform();
|
||||
transformGroup1.Children.Add(translateTransform);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (matrixTransform != null)
|
||||
{
|
||||
var matrix = matrixTransform.Matrix;
|
||||
//在该处对微软的类进行了修改
|
||||
if (!LockX)
|
||||
{
|
||||
matrix.OffsetX += x;
|
||||
}
|
||||
if (!LockY)
|
||||
{
|
||||
matrix.OffsetY += y;
|
||||
}
|
||||
//修改结束
|
||||
RenderTransform = new MatrixTransform
|
||||
{
|
||||
Matrix = matrix
|
||||
};
|
||||
return;
|
||||
}
|
||||
var transformGroup2 = new TransformGroup();
|
||||
translateTransform = new TranslateTransform();
|
||||
if (renderTransform != null)
|
||||
transformGroup2.Children.Add(renderTransform);
|
||||
transformGroup2.Children.Add(translateTransform);
|
||||
RenderTransform = transformGroup2;
|
||||
}
|
||||
}
|
||||
//在该处对微软的类进行了修改
|
||||
if (!LockX)
|
||||
{
|
||||
translateTransform.X += x;
|
||||
}
|
||||
if (!LockY)
|
||||
{
|
||||
translateTransform.Y += y;
|
||||
}
|
||||
//修改结束
|
||||
}
|
||||
|
||||
internal static Transform CloneTransform(Transform transform)
|
||||
{
|
||||
if (transform == null)
|
||||
return null;
|
||||
if (transform is ScaleTransform scaleTransform)
|
||||
return new ScaleTransform
|
||||
{
|
||||
CenterX = scaleTransform.CenterX,
|
||||
CenterY = scaleTransform.CenterY,
|
||||
ScaleX = scaleTransform.ScaleX,
|
||||
ScaleY = scaleTransform.ScaleY
|
||||
};
|
||||
if (transform is RotateTransform rotateTransform)
|
||||
return new RotateTransform
|
||||
{
|
||||
Angle = rotateTransform.Angle,
|
||||
CenterX = rotateTransform.CenterX,
|
||||
CenterY = rotateTransform.CenterY
|
||||
};
|
||||
if (transform is SkewTransform skewTransform)
|
||||
return new SkewTransform
|
||||
{
|
||||
AngleX = skewTransform.AngleX,
|
||||
AngleY = skewTransform.AngleY,
|
||||
CenterX = skewTransform.CenterX,
|
||||
CenterY = skewTransform.CenterY
|
||||
};
|
||||
if (transform is TranslateTransform translateTransform)
|
||||
return new TranslateTransform
|
||||
{
|
||||
X = translateTransform.X,
|
||||
Y = translateTransform.Y
|
||||
};
|
||||
if (transform is MatrixTransform matrixTransform)
|
||||
return new MatrixTransform
|
||||
{
|
||||
Matrix = matrixTransform.Matrix
|
||||
};
|
||||
if (!(transform is TransformGroup transformGroup1))
|
||||
return null;
|
||||
var transformGroup2 = new TransformGroup();
|
||||
foreach (var child in transformGroup1.Children)
|
||||
transformGroup2.Children.Add(CloneTransform(child));
|
||||
return transformGroup2;
|
||||
}
|
||||
|
||||
private void UpdatePosition()
|
||||
{
|
||||
var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement));
|
||||
X = transformOffset.X;
|
||||
Y = transformOffset.Y;
|
||||
}
|
||||
|
||||
internal void StartDrag(Point positionInElementCoordinates)
|
||||
{
|
||||
_relativePosition = positionInElementCoordinates;
|
||||
AssociatedObject.CaptureMouse();
|
||||
AssociatedObject.MouseMove += OnMouseMove;
|
||||
AssociatedObject.LostMouseCapture += OnLostMouseCapture;
|
||||
AssociatedObject.AddHandler(UIElement.MouseLeftButtonUpEvent,
|
||||
new MouseButtonEventHandler(OnMouseLeftButtonUp), false);
|
||||
}
|
||||
|
||||
internal void HandleDrag(Point newPositionInElementCoordinates)
|
||||
{
|
||||
var point = TransformAsVector(AssociatedObject.TransformToVisual(RootElement),
|
||||
newPositionInElementCoordinates.X - _relativePosition.X,
|
||||
newPositionInElementCoordinates.Y - _relativePosition.Y);
|
||||
_settingPosition = true;
|
||||
ApplyTranslation(point.X, point.Y);
|
||||
UpdatePosition();
|
||||
_settingPosition = false;
|
||||
}
|
||||
|
||||
internal void EndDrag()
|
||||
{
|
||||
AssociatedObject.MouseMove -= OnMouseMove;
|
||||
AssociatedObject.LostMouseCapture -= OnLostMouseCapture;
|
||||
AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonUpEvent,
|
||||
new MouseButtonEventHandler(OnMouseLeftButtonUp));
|
||||
}
|
||||
|
||||
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
StartDrag(e.GetPosition(AssociatedObject));
|
||||
DragBegun?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void OnLostMouseCapture(object sender, MouseEventArgs e)
|
||||
{
|
||||
EndDrag();
|
||||
DragFinished?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
AssociatedObject.ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
private void OnMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
HandleDrag(e.GetPosition(AssociatedObject));
|
||||
Dragging?.Invoke(this, e);
|
||||
}
|
||||
|
||||
private static bool RectContainsRect(Rect rect1, Rect rect2)
|
||||
{
|
||||
if (rect1.IsEmpty || rect2.IsEmpty || rect1.X > rect2.X || rect1.Y > rect2.Y ||
|
||||
rect1.X + rect1.Width < rect2.X + rect2.Width)
|
||||
return false;
|
||||
return rect1.Y + rect1.Height >= rect2.Y + rect2.Height;
|
||||
}
|
||||
|
||||
private static Point TransformAsVector(GeneralTransform transform, double x, double y)
|
||||
{
|
||||
var point1 = transform.Transform(new Point(0.0, 0.0));
|
||||
var point2 = transform.Transform(new Point(x, y));
|
||||
return new Point(point2.X - point1.X, point2.Y - point1.Y);
|
||||
}
|
||||
|
||||
private static Point GetTransformOffset(GeneralTransform transform)
|
||||
{
|
||||
return transform.Transform(new Point(0.0, 0.0));
|
||||
}
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
AssociatedObject.AddHandler(UIElement.MouseLeftButtonDownEvent,
|
||||
new MouseButtonEventHandler(OnMouseLeftButtonDown), false);
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonDownEvent,
|
||||
new MouseButtonEventHandler(OnMouseLeftButtonDown));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -354,7 +354,7 @@
|
||||
</Grid>
|
||||
</Border>-->
|
||||
<!--颜色拾取器-->
|
||||
<Border Visibility="Visible" Margin="0,10,0,0" Style="{StaticResource BorderRegionStyle}">
|
||||
<Border Visibility="Collapsed" Margin="0,10,0,0" Style="{StaticResource BorderRegionStyle}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Header"/>
|
||||
@@ -399,7 +399,7 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
<!--时间条-->
|
||||
<!--<Border Visibility="Collapsed" Margin="0,10,0,0" Style="{StaticResource BorderRegionStyle}">
|
||||
<Border Visibility="Collapsed" Margin="0,10,0,0" Style="{StaticResource BorderRegionStyle}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Header"/>
|
||||
@@ -411,7 +411,7 @@
|
||||
</StackPanel>
|
||||
<controls:TimeBar BorderThickness="0" Background="{StaticResource PrimaryBrush}" Grid.Column="1" Width="600" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="50,5,5,5" ></controls:TimeBar>
|
||||
</Grid>
|
||||
</Border>-->
|
||||
</Border>
|
||||
<!--输入-->
|
||||
<!--<Border Visibility="Collapsed" Margin="0,10,0,0" Style="{StaticResource BorderRegionStyle}">
|
||||
<Grid>
|
||||
@@ -620,7 +620,7 @@
|
||||
</controls:TabControl>
|
||||
</Grid>
|
||||
</Border>-->
|
||||
<Border Visibility="Visible" Margin="0,10,0,0" Style="{StaticResource BorderRegionStyle}">
|
||||
<Border Visibility="Collapsed" Margin="0,10,0,0" Style="{StaticResource BorderRegionStyle}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Header"/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||

|
||||
|
||||
  [](https://www.nuget.org/packages/HandyControl)
|
||||
  [](https://www.nuget.org/packages/HandyControl)
|
||||
|
||||
# 欢迎使用 HandyControl
|
||||
|
||||
@@ -26,4 +26,8 @@
|
||||
|
||||
### 5、展开折叠框Expander
|
||||
|
||||

|
||||

|
||||
|
||||
### 6、时间条TimeBar
|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 254 KiB |
|
After Width: | Height: | Size: 187 KiB |