Merge branch 'master' into pr/75
This commit is contained in:
commit
9b0205a030
125 files changed
+5048
-832
No files matched your search
@@ -0,0 +1,16 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class HeaderedSimpleItemsControl : SimpleItemsControl
|
||||
{
|
||||
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
|
||||
"Header", typeof(object), typeof(HeaderedSimpleItemsControl), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Header
|
||||
{
|
||||
get => GetValue(HeaderProperty);
|
||||
set => SetValue(HeaderProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Markup;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
@@ -33,7 +34,14 @@ namespace HandyControl.Controls
|
||||
public SimpleItemsControl()
|
||||
{
|
||||
var items = new ObservableCollection<object>();
|
||||
items.CollectionChanged += OnItemsChanged;
|
||||
items.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (e.NewItems != null && e.NewItems.Count > 0)
|
||||
{
|
||||
SetValue(HasItemsPropertyKey, true);
|
||||
}
|
||||
OnItemsChanged(s, e);
|
||||
};
|
||||
Items = items;
|
||||
}
|
||||
|
||||
@@ -118,6 +126,14 @@ namespace HandyControl.Controls
|
||||
|
||||
protected virtual void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e) => Refresh();
|
||||
|
||||
internal static readonly DependencyPropertyKey HasItemsPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(nameof(HasItems), typeof(bool), typeof(SimpleItemsControl),
|
||||
new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static readonly DependencyProperty HasItemsProperty = HasItemsPropertyKey.DependencyProperty;
|
||||
|
||||
public bool HasItems => (bool) GetValue(HasItemsProperty);
|
||||
|
||||
protected virtual void Refresh()
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
@@ -45,9 +45,9 @@ namespace HandyControl.Controls
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (v >= ctl._uriList.Count)
|
||||
if (v >= ctl._contentDic.Count)
|
||||
{
|
||||
return ctl._uriList.Count - 1;
|
||||
return ctl._contentDic.Count - 1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@@ -65,9 +65,9 @@ namespace HandyControl.Controls
|
||||
"Loop", typeof(bool), typeof(CoverFlow), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有的资源标识符
|
||||
/// 存储所有的内容
|
||||
/// </summary>
|
||||
private readonly Dictionary<int, Uri> _uriList = new Dictionary<int, Uri>();
|
||||
private readonly Dictionary<int, object> _contentDic = new Dictionary<int, object>();
|
||||
|
||||
/// <summary>
|
||||
/// 当前在显示范围内的项
|
||||
@@ -154,12 +154,12 @@ namespace HandyControl.Controls
|
||||
/// <summary>
|
||||
/// 批量添加资源
|
||||
/// </summary>
|
||||
/// <param name="uriList"></param>
|
||||
public void AddRange(List<Uri> uriList)
|
||||
/// <param name="contentList"></param>
|
||||
public void AddRange(IEnumerable<object> contentList)
|
||||
{
|
||||
foreach (var uri in uriList)
|
||||
foreach (var content in contentList)
|
||||
{
|
||||
_uriList.Add(_uriList.Count, uri);
|
||||
_contentDic.Add(_contentDic.Count, content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,13 +167,13 @@ namespace HandyControl.Controls
|
||||
/// 添加一项资源
|
||||
/// </summary>
|
||||
/// <param name="uriString"></param>
|
||||
public void Add(string uriString) => _uriList.Add(_uriList.Count, new Uri(uriString));
|
||||
public void Add(string uriString) => _contentDic.Add(_contentDic.Count, new Uri(uriString));
|
||||
|
||||
/// <summary>
|
||||
/// 添加一项资源
|
||||
/// </summary>
|
||||
/// <param name="uri"></param>
|
||||
public void Add(Uri uri) => _uriList.Add(_uriList.Count, uri);
|
||||
public void Add(Uri uri) => _contentDic.Add(_contentDic.Count, uri);
|
||||
|
||||
/// <summary>
|
||||
/// 跳转
|
||||
@@ -187,13 +187,15 @@ namespace HandyControl.Controls
|
||||
if (e.Delta < 0)
|
||||
{
|
||||
var index = PageIndex + 1;
|
||||
PageIndex = index >= _uriList.Count ? (Loop ? 0 : _uriList.Count - 1) : index;
|
||||
PageIndex = index >= _contentDic.Count ? Loop ? 0 : _contentDic.Count - 1 : index;
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = PageIndex - 1;
|
||||
PageIndex = index < 0 ? (Loop ? _uriList.Count - 1 : 0) : index;
|
||||
PageIndex = index < 0 ? Loop ? _contentDic.Count - 1 : 0 : index;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -271,7 +273,7 @@ namespace HandyControl.Controls
|
||||
private void UpdateShowRange()
|
||||
{
|
||||
var newFirstShowIndex = Math.Max(PageIndex - MaxShowCountHalf, 0);
|
||||
var newLastShowIndex = Math.Min(PageIndex + MaxShowCountHalf, _uriList.Count - 1);
|
||||
var newLastShowIndex = Math.Min(PageIndex + MaxShowCountHalf, _contentDic.Count - 1);
|
||||
|
||||
if (_firstShowIndex < newFirstShowIndex)
|
||||
{
|
||||
@@ -292,7 +294,7 @@ namespace HandyControl.Controls
|
||||
{
|
||||
if (!_itemShowList.ContainsKey(i))
|
||||
{
|
||||
var cover = new CoverFlowItem(i, PageIndex, BitmapFrame.Create(_uriList[i]));
|
||||
var cover = CreateCoverFlowItem(i, _contentDic[i]);
|
||||
_itemShowList[i] = cover;
|
||||
_visualParent.Children.Add(cover);
|
||||
}
|
||||
@@ -301,5 +303,21 @@ namespace HandyControl.Controls
|
||||
_firstShowIndex = newFirstShowIndex;
|
||||
_lastShowIndex = newLastShowIndex;
|
||||
}
|
||||
|
||||
private CoverFlowItem CreateCoverFlowItem(int index, object content)
|
||||
{
|
||||
if (content is Uri uri)
|
||||
{
|
||||
return new CoverFlowItem(index, PageIndex, new Image
|
||||
{
|
||||
Source = BitmapFrame.Create(uri)
|
||||
});
|
||||
}
|
||||
|
||||
return new CoverFlowItem(index, PageIndex, new ContentControl
|
||||
{
|
||||
Content = content
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,14 +18,15 @@ namespace HandyControl.Controls
|
||||
|
||||
private readonly Model3DGroup _model3DGroup;
|
||||
|
||||
private readonly ImageSource _source;
|
||||
private readonly UIElement _uiElement;
|
||||
|
||||
internal int Index { get; set; }
|
||||
|
||||
public CoverFlowItem(int itemIndex, int currentIndex, ImageSource source)
|
||||
public CoverFlowItem(int itemIndex, int currentIndex, UIElement element)
|
||||
{
|
||||
Index = itemIndex;
|
||||
_source = source;
|
||||
_uiElement = element;
|
||||
_uiElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
|
||||
_rotation3D = new AxisAngleRotation3D(new Vector3D(0, 1, 0), GetAngleByPos(currentIndex));
|
||||
_transform3D = new TranslateTransform3D(GetXByPos(currentIndex), 0, GetZByPos(currentIndex));
|
||||
@@ -35,7 +36,7 @@ namespace HandyControl.Controls
|
||||
transformGroup.Children.Add(_transform3D);
|
||||
|
||||
_model3DGroup = new Model3DGroup();
|
||||
_model3DGroup.Children.Add(new GeometryModel3D(CreateItemGeometry(), new DiffuseMaterial(new ImageBrush(_source))));
|
||||
_model3DGroup.Children.Add(new GeometryModel3D(CreateItemGeometry(), new DiffuseMaterial(new VisualBrush(element))));
|
||||
_model3DGroup.Transform = transformGroup;
|
||||
|
||||
Content = _model3DGroup;
|
||||
@@ -103,8 +104,8 @@ namespace HandyControl.Controls
|
||||
/// <returns></returns>
|
||||
private Geometry3D CreateItemGeometry()
|
||||
{
|
||||
var sx = _source.Width > _source.Height ? 0 : 1 - _source.Width / _source.Height;
|
||||
var sy = _source.Width < _source.Height ? 0 : 1 - _source.Height / _source.Width;
|
||||
var sx = _uiElement.DesiredSize.Width > _uiElement.DesiredSize.Height ? 0 : 1 - _uiElement.DesiredSize.Width / _uiElement.DesiredSize.Height;
|
||||
var sy = _uiElement.DesiredSize.Width < _uiElement.DesiredSize.Height ? 0 : 1 - _uiElement.DesiredSize.Height / _uiElement.DesiredSize.Width;
|
||||
|
||||
var p0 = new Point3D(-1 + sx, -1 + sy, 0);
|
||||
var p1 = new Point3D(1 - sx, -1 + sy, 0);
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class Col : ContentControl
|
||||
{
|
||||
public static readonly DependencyProperty LayoutProperty = DependencyProperty.Register(
|
||||
"Layout", typeof(ColLayout), typeof(Col), new PropertyMetadata(default(ColLayout)));
|
||||
|
||||
public ColLayout Layout
|
||||
{
|
||||
get => (ColLayout)GetValue(LayoutProperty);
|
||||
set => SetValue(LayoutProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OffsetProperty = DependencyProperty.Register(
|
||||
"Offset", typeof(int), typeof(Col), new PropertyMetadata(ValueBoxes.Int0Box));
|
||||
|
||||
public int Offset
|
||||
{
|
||||
get => (int)GetValue(OffsetProperty);
|
||||
set => SetValue(OffsetProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SpanProperty = DependencyProperty.Register(
|
||||
"Span", typeof(int), typeof(Col), new PropertyMetadata(24), OnSpanValidate);
|
||||
|
||||
private static bool OnSpanValidate(object value)
|
||||
{
|
||||
var v = (int)value;
|
||||
return v >= 1 || v <= 24;
|
||||
}
|
||||
|
||||
public int Span
|
||||
{
|
||||
get => (int) GetValue(SpanProperty);
|
||||
set => SetValue(SpanProperty, value);
|
||||
}
|
||||
|
||||
internal int GetLayoutCellCount(ColLayoutStatus status)
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
if (Layout != null)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case ColLayoutStatus.Xs:
|
||||
result = Layout.Xs;
|
||||
break;
|
||||
case ColLayoutStatus.Sm:
|
||||
result = Layout.Sm;
|
||||
break;
|
||||
case ColLayoutStatus.Md:
|
||||
result = Layout.Md;
|
||||
break;
|
||||
case ColLayoutStatus.Lg:
|
||||
result = Layout.Lg;
|
||||
break;
|
||||
case ColLayoutStatus.Xl:
|
||||
result = Layout.Xl;
|
||||
break;
|
||||
case ColLayoutStatus.Xxl:
|
||||
result = Layout.Xxl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Span;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
using HandyControl.Tools.Extension;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class Row : Panel
|
||||
{
|
||||
private ColLayoutStatus _layoutStatus;
|
||||
|
||||
private double _maxChildDesiredHeight;
|
||||
|
||||
public static readonly DependencyProperty GutterProperty = DependencyProperty.Register(
|
||||
"Gutter", typeof(double), typeof(Row), new PropertyMetadata(ValueBoxes.Double0Box, null, OnGutterCoerce), OnGutterValidate);
|
||||
|
||||
private static object OnGutterCoerce(DependencyObject d, object basevalue) => OnGutterValidate(basevalue) ? basevalue : .0;
|
||||
|
||||
private static bool OnGutterValidate(object value) => ValidateHelper.IsInRangeOfPosDouble(value, true);
|
||||
|
||||
public double Gutter
|
||||
{
|
||||
get => (double)GetValue(GutterProperty);
|
||||
set => SetValue(GutterProperty, value);
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
var totalCellCount = 0;
|
||||
var totalRowCount = 1;
|
||||
var gutterHalf = Gutter / 2;
|
||||
|
||||
foreach (var child in InternalChildren.OfType<Col>())
|
||||
{
|
||||
child.Margin = new Thickness(gutterHalf);
|
||||
child.Measure(constraint);
|
||||
var childDesiredSize = child.DesiredSize;
|
||||
|
||||
if (_maxChildDesiredHeight < childDesiredSize.Height)
|
||||
{
|
||||
_maxChildDesiredHeight = childDesiredSize.Height;
|
||||
}
|
||||
}
|
||||
|
||||
var itemWidth = constraint.Width / ColLayout.ColMaxCellCount;
|
||||
var childBounds = new Rect(-gutterHalf, -gutterHalf, 0, _maxChildDesiredHeight);
|
||||
_layoutStatus = ColLayout.GetLayoutStatus(constraint.Width);
|
||||
|
||||
foreach (var child in InternalChildren.OfType<Col>())
|
||||
{
|
||||
var cellCount = child.GetLayoutCellCount(_layoutStatus);
|
||||
totalCellCount += cellCount;
|
||||
|
||||
if (totalCellCount > ColLayout.ColMaxCellCount)
|
||||
{
|
||||
childBounds.X = -gutterHalf;
|
||||
childBounds.Y += _maxChildDesiredHeight;
|
||||
totalCellCount = cellCount;
|
||||
totalRowCount++;
|
||||
}
|
||||
|
||||
var childWidth = cellCount * itemWidth;
|
||||
childBounds.Width = childWidth;
|
||||
childBounds.X += childWidth + child.Offset * itemWidth;
|
||||
}
|
||||
|
||||
return new Size(0, _maxChildDesiredHeight * totalRowCount - Gutter);
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
var totalCellCount = 0;
|
||||
var gutterHalf = Gutter / 2;
|
||||
var itemWidth = (finalSize.Width + Gutter) / ColLayout.ColMaxCellCount;
|
||||
var childBounds = new Rect(-gutterHalf, -gutterHalf, 0, _maxChildDesiredHeight);
|
||||
_layoutStatus = ColLayout.GetLayoutStatus(finalSize.Width);
|
||||
|
||||
foreach (var child in InternalChildren.OfType<Col>())
|
||||
{
|
||||
var cellCount = child.GetLayoutCellCount(_layoutStatus);
|
||||
totalCellCount += cellCount;
|
||||
|
||||
var childWidth = cellCount * itemWidth;
|
||||
childBounds.Width = childWidth;
|
||||
childBounds.X += child.Offset * itemWidth;
|
||||
if (totalCellCount > ColLayout.ColMaxCellCount)
|
||||
{
|
||||
childBounds.X = -gutterHalf;
|
||||
childBounds.Y += _maxChildDesiredHeight;
|
||||
totalCellCount = cellCount;
|
||||
}
|
||||
|
||||
child.Arrange(childBounds);
|
||||
childBounds.X += childWidth;
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,44 @@
|
||||
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;
|
||||
#if netle40
|
||||
using System.Windows.Threading;
|
||||
#endif
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
/// <inheritdoc cref="IDataInput" />
|
||||
[TemplatePart(Name = AutoCompletePanel, Type = typeof(Panel))]
|
||||
[TemplatePart(Name = EditableTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
[TemplatePart(Name = AutoPopupAutoComplete, Type = typeof(Popup))]
|
||||
public class ComboBox : System.Windows.Controls.ComboBox, IDataInput
|
||||
{
|
||||
#if netle40
|
||||
|
||||
private string _searchText;
|
||||
|
||||
private DispatcherTimer _autoCompleteTimer;
|
||||
|
||||
#endif
|
||||
private bool _isAutoCompleteAction = true;
|
||||
|
||||
private Panel _autoCompletePanel;
|
||||
|
||||
private System.Windows.Controls.TextBox _editableTextBox;
|
||||
|
||||
private Popup _autoPopupAutoComplete;
|
||||
|
||||
private const string AutoCompletePanel = "PART_AutoCompletePanel";
|
||||
|
||||
private const string AutoPopupAutoComplete = "PART_Popup_AutoComplete";
|
||||
|
||||
private const string EditableTextBox = "PART_EditableTextBox";
|
||||
|
||||
public ComboBox()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
@@ -21,23 +50,125 @@ namespace HandyControl.Controls
|
||||
}));
|
||||
}
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_editableTextBox != null)
|
||||
{
|
||||
BindingOperations.ClearBinding(_editableTextBox, System.Windows.Controls.TextBox.TextProperty);
|
||||
_editableTextBox.GotFocus -= EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus -= EditableTextBox_LostFocus;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (IsEditable)
|
||||
{
|
||||
_editableTextBox = GetTemplateChild(EditableTextBox) as System.Windows.Controls.TextBox;
|
||||
|
||||
if (_editableTextBox != null)
|
||||
{
|
||||
_editableTextBox.TextChanged += EditableTextBox_TextChanged;
|
||||
|
||||
if (AutoComplete)
|
||||
{
|
||||
#if netle40
|
||||
_autoCompleteTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(500)
|
||||
};
|
||||
_autoCompleteTimer.Tick += AutoCompleteTimer_Tick;
|
||||
#endif
|
||||
_autoPopupAutoComplete = GetTemplateChild(AutoPopupAutoComplete) as Popup;
|
||||
_autoCompletePanel = GetTemplateChild(AutoCompletePanel) as Panel;
|
||||
_editableTextBox.SetBinding(System.Windows.Controls.TextBox.TextProperty, new Binding(SearchTextProperty.Name)
|
||||
{
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
|
||||
Mode = BindingMode.OneWayToSource,
|
||||
#if !netle40
|
||||
Delay = 500,
|
||||
#endif
|
||||
Source = this
|
||||
});
|
||||
_editableTextBox.GotFocus += EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus += EditableTextBox_LostFocus;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if netle40
|
||||
|
||||
private void AutoCompleteTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSearchItems(_searchText);
|
||||
_autoCompleteTimer.Stop();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private void EditableTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
base.OnSelectionChanged(e);
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void EditableTextBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_autoPopupAutoComplete != null)
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if !netle40
|
||||
protected override void OnDropDownClosed(EventArgs e)
|
||||
{
|
||||
base.OnDropDownClosed(e);
|
||||
|
||||
_isAutoCompleteAction = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
private void EditableTextBox_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_autoPopupAutoComplete != null && _editableTextBox != null &&
|
||||
!string.IsNullOrEmpty(_editableTextBox.Text))
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
_isAutoCompleteAction = false;
|
||||
base.OnSelectionChanged(e);
|
||||
VerifyData();
|
||||
#if netle40
|
||||
_isAutoCompleteAction = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据验证委托
|
||||
/// </summary>
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据搜索委托
|
||||
/// </summary>
|
||||
public Func<ItemCollection, object, IEnumerable<object>> SearchFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
get => (bool)GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, value);
|
||||
}
|
||||
|
||||
@@ -47,12 +178,18 @@ namespace HandyControl.Controls
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(ComboBox), new PropertyMetadata(default(string)));
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
get => (string)GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyPropertyKey TextTypePropertyKey =
|
||||
DependencyProperty.RegisterReadOnly("TextType", typeof(TextType), typeof(ComboBox),
|
||||
new PropertyMetadata(default(TextType)));
|
||||
@@ -62,9 +199,12 @@ namespace HandyControl.Controls
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = TextTypePropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
get => (TextType)GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
@@ -74,23 +214,151 @@ namespace HandyControl.Controls
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
get => (bool)GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动完成输入
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AutoCompleteProperty = DependencyProperty.Register(
|
||||
"AutoComplete", typeof(bool), typeof(ComboBox), new PropertyMetadata(ValueBoxes.FalseBox, OnAutoCompleteChanged));
|
||||
|
||||
private static void OnAutoCompleteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ComboBox)d;
|
||||
if (ctl._editableTextBox != null)
|
||||
{
|
||||
ctl.UpdateSearchItems(ctl._editableTextBox.Text);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新搜索的项目
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
private void UpdateSearchItems(string key)
|
||||
{
|
||||
if (_editableTextBox != null && _autoPopupAutoComplete != null)
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = !string.IsNullOrEmpty(key);
|
||||
_autoCompletePanel.Children.Clear();
|
||||
|
||||
if (SearchFunc == null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
foreach (var item in Items)
|
||||
{
|
||||
var content = item?.ToString();
|
||||
if (content == null) continue;
|
||||
if (!content.Contains(key)) continue;
|
||||
|
||||
_autoCompletePanel.Children.Add(CreateSearchItem(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in SearchFunc.Invoke(Items, key))
|
||||
{
|
||||
_autoCompletePanel.Children.Add(CreateSearchItem(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ComboBoxItem CreateSearchItem(object content)
|
||||
{
|
||||
var item = new ComboBoxItem
|
||||
{
|
||||
Content = content,
|
||||
Style = ItemContainerStyle,
|
||||
ContentTemplate = ItemTemplate
|
||||
};
|
||||
|
||||
item.PreviewMouseLeftButtonDown += AutoCompleteItem_PreviewMouseLeftButtonDown;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private void AutoCompleteItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is ComboBoxItem comboBoxItem)
|
||||
{
|
||||
if (_autoPopupAutoComplete != null)
|
||||
{
|
||||
_autoPopupAutoComplete.IsOpen = false;
|
||||
}
|
||||
|
||||
_isAutoCompleteAction = false;
|
||||
SelectedValue = comboBoxItem.Content;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索文本
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty SearchTextProperty = DependencyProperty.Register(
|
||||
"SearchText", typeof(string), typeof(ComboBox), new PropertyMetadata(default(string), OnSearchTextChanged));
|
||||
|
||||
private static void OnSearchTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ComboBox)d;
|
||||
if (ctl._isAutoCompleteAction)
|
||||
{
|
||||
#if netle40
|
||||
ctl._searchText = e.NewValue as string;
|
||||
ctl._autoCompleteTimer.Stop();
|
||||
ctl._autoCompleteTimer.Start();
|
||||
#else
|
||||
ctl.UpdateSearchItems(e.NewValue as string);
|
||||
#endif
|
||||
}
|
||||
|
||||
ctl._isAutoCompleteAction = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索文本
|
||||
/// </summary>
|
||||
internal string SearchText
|
||||
{
|
||||
get => (string)GetValue(SearchTextProperty);
|
||||
set => SetValue(SearchTextProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动完成输入
|
||||
/// </summary>
|
||||
public bool AutoComplete
|
||||
{
|
||||
get => (bool)GetValue(AutoCompleteProperty);
|
||||
set => SetValue(AutoCompleteProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
var value = _editableTextBox == null ? Text : _editableTextBox.Text;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(Text);
|
||||
result = VerifyFunc.Invoke(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
|
||||
@@ -99,15 +99,6 @@ namespace HandyControl.Controls
|
||||
set => SetValue(DateTimeFormatProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ClockStyleProperty = DependencyProperty.Register(
|
||||
"ClockStyle", typeof(Style), typeof(DateTimePicker), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style ClockStyle
|
||||
{
|
||||
get => (Style) GetValue(ClockStyleProperty);
|
||||
set => SetValue(ClockStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CalendarStyleProperty = DependencyProperty.Register(
|
||||
"CalendarStyle", typeof(Style), typeof(DateTimePicker), new PropertyMetadata(default(Style)));
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace HandyControl.Controls
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
|
||||
"Value", typeof(double), typeof(NumericUpDown),
|
||||
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
OnValueChanged, CoerceValue), ArithmeticHelper.IsValidDoubleValue);
|
||||
|
||||
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
@@ -204,7 +204,7 @@ namespace HandyControl.Controls
|
||||
/// 最大值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
|
||||
"Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(100.0, OnMaximumChanged, CoerceMaximum), ArithmeticHelper.IsValidDoubleValue);
|
||||
"Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum), ArithmeticHelper.IsValidDoubleValue);
|
||||
|
||||
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
@@ -34,8 +34,6 @@ namespace HandyControl.Controls
|
||||
|
||||
#region Data
|
||||
|
||||
private Clock _clock;
|
||||
|
||||
private string _defaultText;
|
||||
|
||||
private ButtonBase _dropDownButton;
|
||||
@@ -79,7 +77,7 @@ namespace HandyControl.Controls
|
||||
|
||||
public TimePicker()
|
||||
{
|
||||
InitClock();
|
||||
Clock = new Clock();
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
ClearValue(SelectedTimeProperty);
|
||||
@@ -103,18 +101,6 @@ namespace HandyControl.Controls
|
||||
|
||||
#endregion TimeFormat
|
||||
|
||||
#region ClockStyle
|
||||
|
||||
public Style ClockStyle
|
||||
{
|
||||
get => (Style)GetValue(ClockStyleProperty);
|
||||
set => SetValue(ClockStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ClockStyleProperty = DependencyProperty.Register("ClockStyle", typeof(Style), typeof(TimePicker));
|
||||
|
||||
#endregion CalendarStyle
|
||||
|
||||
#region DisplayTime
|
||||
|
||||
public DateTime DisplayTime
|
||||
@@ -133,8 +119,8 @@ namespace HandyControl.Controls
|
||||
private static object CoerceDisplayTime(DependencyObject d, object value)
|
||||
{
|
||||
var dp = (TimePicker)d;
|
||||
dp._clock.DisplayTime = (DateTime)value;
|
||||
return dp._clock.DisplayTime;
|
||||
dp.Clock.DisplayTime = (DateTime)value;
|
||||
return dp.Clock.DisplayTime;
|
||||
}
|
||||
|
||||
#endregion DisplayTime
|
||||
@@ -170,7 +156,7 @@ namespace HandyControl.Controls
|
||||
|
||||
dp.Dispatcher.BeginInvoke(DispatcherPriority.Input, (Action)delegate
|
||||
{
|
||||
dp._clock.Focus();
|
||||
dp.Clock.Focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -212,8 +198,8 @@ namespace HandyControl.Controls
|
||||
private static object CoerceSelectedTime(DependencyObject d, object value)
|
||||
{
|
||||
var dp = (TimePicker)d;
|
||||
dp._clock.SelectedTime = (DateTime?)value;
|
||||
return dp._clock.SelectedTime;
|
||||
dp.Clock.SelectedTime = (DateTime?)value;
|
||||
return dp.Clock.SelectedTime;
|
||||
}
|
||||
|
||||
#endregion SelectedDate
|
||||
@@ -306,6 +292,35 @@ namespace HandyControl.Controls
|
||||
set => SetValue(ShowClearButtonProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ClockProperty = DependencyProperty.Register(
|
||||
"Clock", typeof(ClockBase), typeof(TimePicker), new FrameworkPropertyMetadata(default(Clock), FrameworkPropertyMetadataOptions.NotDataBindable, OnClockChanged));
|
||||
|
||||
private static void OnClockChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (TimePicker) d;
|
||||
var oldClock = e.OldValue as ClockBase;
|
||||
var newClock = e.NewValue as ClockBase;
|
||||
|
||||
if (oldClock != null)
|
||||
{
|
||||
oldClock.SelectedTimeChanged -= ctl.Clock_SelectedTimeChanged;
|
||||
oldClock.Confirmed -= ctl.Clock_Confirmed;
|
||||
}
|
||||
|
||||
if (newClock != null)
|
||||
{
|
||||
newClock.ShowConfirmButton = true;
|
||||
newClock.SelectedTimeChanged += ctl.Clock_SelectedTimeChanged;
|
||||
newClock.Confirmed += ctl.Clock_Confirmed;
|
||||
}
|
||||
}
|
||||
|
||||
public ClockBase Clock
|
||||
{
|
||||
get => (ClockBase) GetValue(ClockProperty);
|
||||
set => SetValue(ClockProperty, value);
|
||||
}
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
@@ -374,7 +389,7 @@ namespace HandyControl.Controls
|
||||
_popUp.PreviewMouseLeftButtonDown += PopUp_PreviewMouseLeftButtonDown;
|
||||
_popUp.Opened += PopUp_Opened;
|
||||
_popUp.Closed += PopUp_Closed;
|
||||
_popUp.Child = _clock;
|
||||
_popUp.Child = Clock;
|
||||
|
||||
if (IsDropDownOpen)
|
||||
{
|
||||
@@ -439,20 +454,7 @@ namespace HandyControl.Controls
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
private void InitClock()
|
||||
{
|
||||
_clock = new Clock
|
||||
{
|
||||
ShowConfirmButton = true
|
||||
};
|
||||
_clock.SelectedTimeChanged += Clock_SelectedTimeChanged;
|
||||
_clock.Confirmed += Clock_Confirmed;
|
||||
}
|
||||
|
||||
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SetSelectedTime();
|
||||
}
|
||||
private void TextBox_LostFocus(object sender, RoutedEventArgs e) => SetSelectedTime();
|
||||
|
||||
private void SetIsHandlerSuspended(DependencyProperty property, bool value)
|
||||
{
|
||||
@@ -560,7 +562,7 @@ namespace HandyControl.Controls
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
|
||||
_clock?.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
|
||||
Clock?.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
|
||||
|
||||
OnClockOpened(new RoutedEventArgs());
|
||||
}
|
||||
@@ -572,7 +574,7 @@ namespace HandyControl.Controls
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
}
|
||||
|
||||
if (_clock.IsKeyboardFocusWithin)
|
||||
if (Clock.IsKeyboardFocusWithin)
|
||||
{
|
||||
MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace HandyControl.Controls
|
||||
private bool _isLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// 故事版
|
||||
/// 故事板
|
||||
/// </summary>
|
||||
private Storyboard _storyboard;
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Windows;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
@@ -12,6 +14,8 @@ namespace HandyControl.Controls
|
||||
{
|
||||
private Adorner _container;
|
||||
|
||||
private static readonly Dictionary<string, System.Windows.Window> WindowDic = new Dictionary<string, System.Windows.Window>();
|
||||
|
||||
public static readonly DependencyProperty IsClosedProperty = DependencyProperty.Register(
|
||||
"IsClosed", typeof(bool), typeof(Dialog), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
@@ -21,21 +25,94 @@ namespace HandyControl.Controls
|
||||
internal set => SetValue(IsClosedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TokenProperty = DependencyProperty.RegisterAttached(
|
||||
"Token", typeof(string), typeof(Dialog), new PropertyMetadata(default(string), OnTokenChanged));
|
||||
|
||||
private static void OnTokenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is System.Windows.Window window)
|
||||
{
|
||||
if (e.NewValue == null)
|
||||
{
|
||||
Unregister(window);
|
||||
}
|
||||
else
|
||||
{
|
||||
Register(e.NewValue.ToString(), window);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetToken(DependencyObject element, string value)
|
||||
=> element.SetValue(TokenProperty, value);
|
||||
|
||||
public static string GetToken(DependencyObject element)
|
||||
=> (string) element.GetValue(TokenProperty);
|
||||
|
||||
public Dialog()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => Close()));
|
||||
}
|
||||
|
||||
public static Dialog Show<T>() where T : new() => Show(new T());
|
||||
public static void Register(string token, System.Windows.Window window)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || window == null) return;
|
||||
WindowDic[token] = window;
|
||||
}
|
||||
|
||||
public static Dialog Show(object content)
|
||||
public static void Unregister(string token, System.Windows.Window window)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || window == null) return;
|
||||
|
||||
if (WindowDic.ContainsKey(token))
|
||||
{
|
||||
if (ReferenceEquals(WindowDic[token], window))
|
||||
{
|
||||
WindowDic.Remove(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(System.Windows.Window window)
|
||||
{
|
||||
if (window == null) return;
|
||||
var first = WindowDic.FirstOrDefault(item => ReferenceEquals(window, item.Value));
|
||||
if (!string.IsNullOrEmpty(first.Key))
|
||||
{
|
||||
WindowDic.Remove(first.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token)) return;
|
||||
|
||||
if (WindowDic.ContainsKey(token))
|
||||
{
|
||||
WindowDic.Remove(token);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dialog Show<T>(string token = "") where T : new() => Show(new T(), token);
|
||||
|
||||
public static Dialog Show(object content, string token = "")
|
||||
{
|
||||
var dialog = new Dialog
|
||||
{
|
||||
Content = content
|
||||
};
|
||||
|
||||
var window = VisualHelper.GetActiveWindow();
|
||||
System.Windows.Window window;
|
||||
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
window = VisualHelper.GetActiveWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowDic.TryGetValue(token, out window);
|
||||
}
|
||||
|
||||
if (window != null)
|
||||
{
|
||||
var decorator = VisualHelper.GetChild<AdornerDecorator>(window);
|
||||
@@ -62,9 +139,23 @@ namespace HandyControl.Controls
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
public void Close(string token = "")
|
||||
{
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
if (WindowDic.TryGetValue(token, out var window))
|
||||
{
|
||||
Close(window);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Close(VisualHelper.GetActiveWindow());
|
||||
}
|
||||
}
|
||||
|
||||
private void Close(System.Windows.Window window)
|
||||
{
|
||||
var window = VisualHelper.GetActiveWindow();
|
||||
if (window != null)
|
||||
{
|
||||
var decorator = VisualHelper.GetChild<AdornerDecorator>(window);
|
||||
|
||||
@@ -98,6 +98,19 @@ namespace HandyControl.Controls
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token)) return;
|
||||
|
||||
if (PanelDic.ContainsKey(token))
|
||||
{
|
||||
var panel = PanelDic[token];
|
||||
PanelDic.Remove(token);
|
||||
panel.ContextMenu = null;
|
||||
panel.SetCurrentValue(PanelElement.FluidMoveBehaviorProperty, DependencyProperty.UnsetValue);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseEnter(e);
|
||||
|
||||
@@ -114,7 +114,8 @@ namespace HandyControl.Controls
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
BeginAnimation(CurrentVerticalOffsetProperty, animation);
|
||||
|
||||
BeginAnimation(CurrentVerticalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
internal void ScrollToHorizontalOffsetInternal(double offset, double milliseconds = 500)
|
||||
@@ -131,7 +132,8 @@ namespace HandyControl.Controls
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
BeginAnimation(CurrentHorizontalOffsetProperty, animation);
|
||||
|
||||
BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) =>
|
||||
@@ -150,7 +152,7 @@ namespace HandyControl.Controls
|
||||
|
||||
public static bool GetIsEnableInertia(DependencyObject element)
|
||||
{
|
||||
return (bool) element.GetValue(IsEnableInertiaProperty);
|
||||
return (bool)element.GetValue(IsEnableInertiaProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,7 +160,7 @@ namespace HandyControl.Controls
|
||||
/// </summary>
|
||||
public bool IsEnableInertia
|
||||
{
|
||||
get => (bool)GetValue(IsEnableInertiaProperty);
|
||||
get => (bool) GetValue(IsEnableInertiaProperty);
|
||||
set => SetValue(IsEnableInertiaProperty, value);
|
||||
}
|
||||
|
||||
@@ -173,7 +175,7 @@ namespace HandyControl.Controls
|
||||
/// </summary>
|
||||
public bool IsPenetrating
|
||||
{
|
||||
get => (bool)GetValue(IsPenetratingProperty);
|
||||
get => (bool) GetValue(IsPenetratingProperty);
|
||||
set => SetValue(IsPenetratingProperty, value);
|
||||
}
|
||||
|
||||
@@ -190,7 +192,7 @@ namespace HandyControl.Controls
|
||||
/// <summary>
|
||||
/// 当前垂直滚动偏移
|
||||
/// </summary>
|
||||
private static readonly DependencyProperty CurrentVerticalOffsetProperty = DependencyProperty.Register(
|
||||
internal static readonly DependencyProperty CurrentVerticalOffsetProperty = DependencyProperty.Register(
|
||||
"CurrentVerticalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentVerticalOffsetChanged));
|
||||
|
||||
private static void OnCurrentVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
@@ -204,7 +206,7 @@ namespace HandyControl.Controls
|
||||
/// <summary>
|
||||
/// 当前垂直滚动偏移
|
||||
/// </summary>
|
||||
private double CurrentVerticalOffset
|
||||
internal double CurrentVerticalOffset
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
get => (double) GetValue(CurrentVerticalOffsetProperty);
|
||||
@@ -214,7 +216,7 @@ namespace HandyControl.Controls
|
||||
/// <summary>
|
||||
/// 当前水平滚动偏移
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CurrentHorizontalOffsetProperty = DependencyProperty.Register(
|
||||
internal static readonly DependencyProperty CurrentHorizontalOffsetProperty = DependencyProperty.Register(
|
||||
"CurrentHorizontalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentHorizontalOffsetChanged));
|
||||
|
||||
private static void OnCurrentHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
@@ -228,7 +230,7 @@ namespace HandyControl.Controls
|
||||
/// <summary>
|
||||
/// 当前水平滚动偏移
|
||||
/// </summary>
|
||||
public double CurrentHorizontalOffset
|
||||
internal double CurrentHorizontalOffset
|
||||
{
|
||||
get => (double) GetValue(CurrentHorizontalOffsetProperty);
|
||||
set => SetValue(CurrentHorizontalOffsetProperty, value);
|
||||
|
||||
@@ -15,11 +15,9 @@ namespace HandyControl.Controls
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var maxSize = new Size();
|
||||
var children = InternalChildren;
|
||||
|
||||
for (int i = 0, count = children.Count; i < count; ++i)
|
||||
foreach (UIElement child in InternalChildren)
|
||||
{
|
||||
var child = children[i];
|
||||
if (child != null)
|
||||
{
|
||||
child.Measure(availableSize);
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class SideMenu : HeaderedSimpleItemsControl
|
||||
{
|
||||
private SideMenuItem _selectedItem;
|
||||
|
||||
private SideMenuItem _selectedHeader;
|
||||
|
||||
private bool _isItemSelected;
|
||||
|
||||
public SideMenu()
|
||||
{
|
||||
AddHandler(SideMenuItem.SelectedEvent, new RoutedEventHandler(SideMenuItemSelected));
|
||||
|
||||
Loaded += (s, e) => Init();
|
||||
}
|
||||
|
||||
protected override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
OnExpandModeChanged(ExpandMode);
|
||||
}
|
||||
|
||||
private void SideMenuItemSelected(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is SideMenuItem item)
|
||||
{
|
||||
if (item.Role == SideMenuItemRole.Item)
|
||||
{
|
||||
if (Equals(item, _selectedItem)) return;
|
||||
|
||||
if (_selectedItem != null)
|
||||
{
|
||||
_selectedItem.IsSelected = false;
|
||||
}
|
||||
|
||||
_selectedItem = item;
|
||||
_selectedItem.IsSelected = true;
|
||||
RaiseEvent(new FunctionEventArgs<object>(SelectionChangedEvent, this)
|
||||
{
|
||||
Info = e.OriginalSource
|
||||
});
|
||||
_isItemSelected = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Equals(item, _selectedHeader))
|
||||
{
|
||||
if (_selectedHeader != null)
|
||||
{
|
||||
if (ExpandMode == ExpandMode.Freedom && item.ItemsHost.IsVisible && !_isItemSelected)
|
||||
{
|
||||
item.IsSelected = false;
|
||||
SwitchPanelArea(item);
|
||||
return;
|
||||
}
|
||||
|
||||
_selectedHeader.IsSelected = false;
|
||||
if (ExpandMode != ExpandMode.Freedom)
|
||||
{
|
||||
SwitchPanelArea(_selectedHeader);
|
||||
}
|
||||
}
|
||||
|
||||
_selectedHeader = item;
|
||||
_selectedHeader.IsSelected = true;
|
||||
SwitchPanelArea(_selectedHeader);
|
||||
}
|
||||
else if (ExpandMode == ExpandMode.Freedom && !_isItemSelected)
|
||||
{
|
||||
_selectedHeader.IsSelected = false;
|
||||
SwitchPanelArea(_selectedHeader);
|
||||
_selectedHeader = null;
|
||||
}
|
||||
|
||||
if (_isItemSelected)
|
||||
{
|
||||
_isItemSelected = false;
|
||||
}
|
||||
else if(_selectedHeader != null)
|
||||
{
|
||||
_selectedHeader.SelectDefaultItem();
|
||||
_isItemSelected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchPanelArea(SideMenuItem oldItem)
|
||||
{
|
||||
switch (ExpandMode)
|
||||
{
|
||||
case ExpandMode.ShowAll:
|
||||
return;
|
||||
case ExpandMode.ShowOne:
|
||||
case ExpandMode.Freedom:
|
||||
case ExpandMode.Accordion:
|
||||
oldItem.SwitchPanelArea(oldItem.IsSelected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new SideMenuItem();
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is SideMenuItem;
|
||||
|
||||
public static readonly DependencyProperty ExpandModeProperty = DependencyProperty.Register(
|
||||
"ExpandMode", typeof(ExpandMode), typeof(SideMenu), new PropertyMetadata(default(ExpandMode), OnExpandModeChanged));
|
||||
|
||||
private static void OnExpandModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (SideMenu) d;
|
||||
var v = (ExpandMode) e.NewValue;
|
||||
|
||||
if (ctl.ItemsHost == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ctl.OnExpandModeChanged(v);
|
||||
}
|
||||
|
||||
private void OnExpandModeChanged(ExpandMode mode)
|
||||
{
|
||||
if (mode == ExpandMode.ShowAll)
|
||||
{
|
||||
ShowAll();
|
||||
}
|
||||
else if (mode == ExpandMode.ShowOne)
|
||||
{
|
||||
var sideMenuItem = ItemsHost.Children.OfType<SideMenuItem>().FirstOrDefault(item => item.IsSelected);
|
||||
ShowSelectedOne(sideMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
public ExpandMode ExpandMode
|
||||
{
|
||||
get => (ExpandMode) GetValue(ExpandModeProperty);
|
||||
set => SetValue(ExpandModeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PanelAreaLengthProperty = DependencyProperty.Register(
|
||||
"PanelAreaLength", typeof(double), typeof(SideMenu), new PropertyMetadata(double.NaN));
|
||||
|
||||
public double PanelAreaLength
|
||||
{
|
||||
get => (double) GetValue(PanelAreaLengthProperty);
|
||||
set => SetValue(PanelAreaLengthProperty, value);
|
||||
}
|
||||
|
||||
private void ShowAll()
|
||||
{
|
||||
foreach (var sideMenuItem in ItemsHost.Children.OfType<SideMenuItem>())
|
||||
{
|
||||
sideMenuItem.SwitchPanelArea(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowSelectedOne(SideMenuItem item)
|
||||
{
|
||||
foreach (var sideMenuItem in ItemsHost.Children.OfType<SideMenuItem>())
|
||||
{
|
||||
sideMenuItem.SwitchPanelArea(Equals(sideMenuItem, item));
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent SelectionChangedEvent = EventManager.RegisterRoutedEvent(
|
||||
"SelectionChanged", RoutingStrategy.Bubble, typeof(EventHandler<FunctionEventArgs<object>>), typeof(SideMenu));
|
||||
|
||||
public event EventHandler<FunctionEventArgs<object>> SelectionChanged
|
||||
{
|
||||
add => AddHandler(SelectionChangedEvent, value);
|
||||
remove => RemoveHandler(SelectionChangedEvent, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class SideMenuItem : HeaderedSimpleItemsControl, ISelectable
|
||||
{
|
||||
private bool _isMouseLeftButtonDown;
|
||||
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
|
||||
"Icon", typeof(object), typeof(SideMenuItem), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Icon
|
||||
{
|
||||
get => GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
public SideMenuItem()
|
||||
{
|
||||
SetBinding(ExpandModeProperty, new Binding(SideMenu.ExpandModeProperty.Name)
|
||||
{
|
||||
RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(SideMenu), 1)
|
||||
});
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty ExpandModeProperty =
|
||||
SideMenu.ExpandModeProperty.AddOwner(typeof(SideMenuItem), new PropertyMetadata(default(ExpandMode)));
|
||||
|
||||
internal ExpandMode ExpandMode
|
||||
{
|
||||
get => (ExpandMode) GetValue(ExpandModeProperty);
|
||||
set => SetValue(ExpandModeProperty, value);
|
||||
}
|
||||
|
||||
protected override void Refresh()
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
ItemsHost.Children.Clear();
|
||||
foreach (var item in Items)
|
||||
{
|
||||
DependencyObject container;
|
||||
if (IsItemItsOwnContainerOverride(item))
|
||||
{
|
||||
container = item as DependencyObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
container = GetContainerForItemOverride();
|
||||
PrepareContainerForItemOverride(container, item);
|
||||
}
|
||||
|
||||
if (container is FrameworkElement element)
|
||||
{
|
||||
element.Style = ItemContainerStyle;
|
||||
ItemsHost.Children.Add(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsLoaded)
|
||||
{
|
||||
SwitchPanelArea(ExpandMode == ExpandMode.ShowAll || IsSelected);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnSelected(RoutedEventArgs e) => RaiseEvent(e);
|
||||
|
||||
public static readonly RoutedEvent SelectedEvent =
|
||||
EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(SideMenuItem));
|
||||
|
||||
public event RoutedEventHandler Selected
|
||||
{
|
||||
add => AddHandler(SelectedEvent, value);
|
||||
remove => RemoveHandler(SelectedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
|
||||
"IsSelected", typeof(bool), typeof(SideMenuItem), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get => (bool) GetValue(IsSelectedProperty);
|
||||
set => SetValue(IsSelectedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RoleProperty = DependencyProperty.Register(
|
||||
"Role", typeof(SideMenuItemRole), typeof(SideMenuItem), new PropertyMetadata(default(SideMenuItemRole)));
|
||||
|
||||
public SideMenuItemRole Role
|
||||
{
|
||||
get => (SideMenuItemRole) GetValue(RoleProperty);
|
||||
internal set => SetValue(RoleProperty, value);
|
||||
}
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new SideMenuItem();
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is SideMenuItem;
|
||||
|
||||
protected override void OnMouseLeave(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseLeave(e);
|
||||
|
||||
_isMouseLeftButtonDown = false;
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonDown(e);
|
||||
|
||||
_isMouseLeftButtonDown = true;
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonUp(e);
|
||||
|
||||
if (_isMouseLeftButtonDown)
|
||||
{
|
||||
IsSelected = true;
|
||||
OnSelected(new RoutedEventArgs(SelectedEvent, this));
|
||||
_isMouseLeftButtonDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SelectDefaultItem()
|
||||
{
|
||||
if (Role == SideMenuItemRole.Header && ItemsHost.Children.Count > 0)
|
||||
{
|
||||
var item = ItemsHost.Children.OfType<SideMenuItem>().FirstOrDefault();
|
||||
if (item != null && !item.IsSelected)
|
||||
{
|
||||
item.OnSelected(new RoutedEventArgs(SelectedEvent, item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void SwitchPanelArea(bool isShow)
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
if (Role == SideMenuItemRole.Header)
|
||||
{
|
||||
ItemsHost.Show(isShow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
@@ -10,16 +11,31 @@ namespace HandyControl.Controls
|
||||
{
|
||||
[TemplatePart(Name = OverflowButtonKey, Type = typeof(ContextMenuToggleButton))]
|
||||
[TemplatePart(Name = HeaderPanelKey, Type = typeof(TabPanel))]
|
||||
[TemplatePart(Name = OverflowScrollviewer, Type = typeof(ScrollViewer))]
|
||||
[TemplatePart(Name = ScrollButtonLeft, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ScrollButtonRight, Type = typeof(Button))]
|
||||
public class TabControl : System.Windows.Controls.TabControl
|
||||
{
|
||||
private const string OverflowButtonKey = "PART_OverflowButton";
|
||||
|
||||
private const string HeaderPanelKey = "PART_HeaderPanel";
|
||||
|
||||
private const string OverflowScrollviewer = "PART_OverflowScrollviewer";
|
||||
|
||||
private const string ScrollButtonLeft = "PART_ScrollButtonLeft";
|
||||
|
||||
private const string ScrollButtonRight = "PART_ScrollButtonRight";
|
||||
|
||||
private ContextMenuToggleButton _buttonOverflow;
|
||||
|
||||
private TabPanel _headerPanel;
|
||||
|
||||
private ScrollViewer _scrollviewerOverflow;
|
||||
|
||||
private Button _buttonScrollLeft;
|
||||
|
||||
private Button _buttonScrollRight;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为内部操作
|
||||
/// </summary>
|
||||
@@ -115,6 +131,21 @@ namespace HandyControl.Controls
|
||||
set => SetValue(TabItemHeightProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以滚动
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsScrollableProperty = DependencyProperty.Register(
|
||||
"IsScrollable", typeof(bool), typeof(TabControl), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以滚动
|
||||
/// </summary>
|
||||
public bool IsScrollable
|
||||
{
|
||||
get => (bool) GetValue(IsScrollableProperty);
|
||||
set => SetValue(IsScrollableProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 可见的标签数量
|
||||
/// </summary>
|
||||
@@ -133,7 +164,7 @@ namespace HandyControl.Controls
|
||||
if (!IsEnableTabFill)
|
||||
{
|
||||
_itemShowCount = (int)(ActualWidth / TabItemWidth);
|
||||
_buttonOverflow.Show(Items.Count > 0 && Items.Count >= _itemShowCount);
|
||||
_buttonOverflow.Show(Items.Count > 0 && Items.Count >= _itemShowCount);
|
||||
}
|
||||
|
||||
if (IsInternalAction)
|
||||
@@ -163,12 +194,33 @@ namespace HandyControl.Controls
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_buttonOverflow != null)
|
||||
{
|
||||
if (_buttonOverflow.Menu != null)
|
||||
{
|
||||
_buttonOverflow.Menu.Closed -= Menu_Closed;
|
||||
_buttonOverflow.Menu = null;
|
||||
}
|
||||
|
||||
_buttonOverflow.Click -= ButtonOverflow_Click;
|
||||
}
|
||||
|
||||
if (_buttonScrollLeft != null) _buttonScrollLeft.Click -= ButtonScrollLeft_Click;
|
||||
if (_buttonScrollRight != null) _buttonScrollRight.Click -= ButtonScrollRight_Click;
|
||||
|
||||
base.OnApplyTemplate();
|
||||
_headerPanel = Template.FindName(HeaderPanelKey, this) as TabPanel;
|
||||
_headerPanel = GetTemplateChild(HeaderPanelKey) as TabPanel;
|
||||
|
||||
if (IsEnableTabFill) return;
|
||||
|
||||
_buttonOverflow = Template.FindName(OverflowButtonKey, this) as ContextMenuToggleButton;
|
||||
_buttonOverflow = GetTemplateChild(OverflowButtonKey) as ContextMenuToggleButton;
|
||||
_scrollviewerOverflow = GetTemplateChild(OverflowScrollviewer) as ScrollViewer;
|
||||
_buttonScrollLeft = GetTemplateChild(ScrollButtonLeft) as Button;
|
||||
_buttonScrollRight = GetTemplateChild(ScrollButtonRight) as Button;
|
||||
|
||||
if (_buttonScrollLeft != null) _buttonScrollLeft.Click += ButtonScrollLeft_Click;
|
||||
if (_buttonScrollRight != null) _buttonScrollRight.Click += ButtonScrollRight_Click;
|
||||
|
||||
if (_buttonOverflow != null)
|
||||
{
|
||||
_itemShowCount = (int)(ActualWidth / TabItemWidth);
|
||||
@@ -179,49 +231,68 @@ namespace HandyControl.Controls
|
||||
Placement = PlacementMode.Bottom,
|
||||
PlacementTarget = _buttonOverflow
|
||||
};
|
||||
menu.Closed += (s, e) => _buttonOverflow.IsChecked = false;
|
||||
menu.Closed += Menu_Closed;
|
||||
_buttonOverflow.Menu = menu;
|
||||
_buttonOverflow.Click += (s, e) =>
|
||||
{
|
||||
if (_buttonOverflow.IsChecked == true)
|
||||
{
|
||||
_buttonOverflow.Menu.Items.Clear();
|
||||
foreach (TabItem item in Items)
|
||||
{
|
||||
var menuItem = new MenuItem
|
||||
{
|
||||
Header = item.Header,
|
||||
Width = TabItemWidth,
|
||||
IsChecked = item.IsSelected,
|
||||
IsCheckable = true
|
||||
};
|
||||
menuItem.Click += delegate
|
||||
{
|
||||
_buttonOverflow.IsChecked = false;
|
||||
var index = Items.IndexOf(item);
|
||||
if (index >= _itemShowCount)
|
||||
{
|
||||
Items.Remove(item);
|
||||
Items.Insert(0, item);
|
||||
if (IsEnableAnimation)
|
||||
{
|
||||
_headerPanel.ClearValue(TabPanel.FluidMoveDurationProperty);
|
||||
}
|
||||
else
|
||||
{
|
||||
_headerPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
|
||||
}
|
||||
_headerPanel.ForceUpdate = true;
|
||||
_headerPanel.Measure(new Size(_headerPanel.DesiredSize.Width, ActualHeight));
|
||||
_headerPanel.ForceUpdate = false;
|
||||
}
|
||||
item.IsSelected = true;
|
||||
};
|
||||
_buttonOverflow.Menu.Items.Add(menuItem);
|
||||
}
|
||||
}
|
||||
};
|
||||
_buttonOverflow.Click += ButtonOverflow_Click;
|
||||
}
|
||||
}
|
||||
|
||||
private void Menu_Closed(object sender, RoutedEventArgs e) => _buttonOverflow.IsChecked = false;
|
||||
|
||||
private void ButtonScrollRight_Click(object sender, RoutedEventArgs e) =>
|
||||
_scrollviewerOverflow.ScrollToHorizontalOffsetInternal(Math.Min(
|
||||
_scrollviewerOverflow.CurrentHorizontalOffset + TabItemWidth, _scrollviewerOverflow.ScrollableWidth));
|
||||
|
||||
private void ButtonScrollLeft_Click(object sender, RoutedEventArgs e) =>
|
||||
_scrollviewerOverflow.ScrollToHorizontalOffsetInternal(Math.Max(
|
||||
_scrollviewerOverflow.CurrentHorizontalOffset - TabItemWidth, 0));
|
||||
|
||||
private void ButtonOverflow_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_buttonOverflow.IsChecked == true)
|
||||
{
|
||||
_buttonOverflow.Menu.Items.Clear();
|
||||
foreach (TabItem item in Items)
|
||||
{
|
||||
var menuItem = new MenuItem
|
||||
{
|
||||
Header = item.Header,
|
||||
Width = TabItemWidth,
|
||||
IsChecked = item.IsSelected,
|
||||
IsCheckable = true
|
||||
};
|
||||
menuItem.Click += delegate
|
||||
{
|
||||
_buttonOverflow.IsChecked = false;
|
||||
var index = Items.IndexOf(item);
|
||||
if (index >= _itemShowCount)
|
||||
{
|
||||
Items.Remove(item);
|
||||
Items.Insert(0, item);
|
||||
if (IsEnableAnimation)
|
||||
{
|
||||
_headerPanel.ClearValue(TabPanel.FluidMoveDurationProperty);
|
||||
}
|
||||
else
|
||||
{
|
||||
_headerPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
|
||||
}
|
||||
_headerPanel.ForceUpdate = true;
|
||||
_headerPanel.Measure(new Size(_headerPanel.DesiredSize.Width, ActualHeight));
|
||||
_headerPanel.ForceUpdate = false;
|
||||
}
|
||||
item.IsSelected = true;
|
||||
};
|
||||
_buttonOverflow.Menu.Items.Add(menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal double GetHorizontalOffset() => _scrollviewerOverflow?.CurrentHorizontalOffset ?? 0;
|
||||
|
||||
internal void UpdateScroll() => _scrollviewerOverflow?.RaiseEvent(new MouseWheelEventArgs(Mouse.PrimaryDevice, Environment.TickCount, 0)
|
||||
{
|
||||
RoutedEvent = MouseWheelEvent
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,11 @@ namespace HandyControl.Controls
|
||||
/// </summary>
|
||||
private int _currentIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 标签容器横向滚动距离
|
||||
/// </summary>
|
||||
private double _scrollHorizontalOffset;
|
||||
|
||||
/// <summary>
|
||||
/// 标签容器
|
||||
/// </summary>
|
||||
@@ -178,17 +183,21 @@ namespace HandyControl.Controls
|
||||
base.OnMouseLeftButtonDown(e);
|
||||
if (TabControlParent.IsDraggable && !ItemIsDragging && !_isDragging)
|
||||
{
|
||||
TabControlParent.UpdateScroll();
|
||||
TabPanel.FluidMoveDuration = new Duration(TimeSpan.FromSeconds(0));
|
||||
_mouseDownOffsetX = RenderTransform.Value.OffsetX;
|
||||
var mx = TranslatePoint(new Point(), TabControlParent).X;
|
||||
_scrollHorizontalOffset = TabControlParent.GetHorizontalOffset();
|
||||
var mx = TranslatePoint(new Point(), TabControlParent).X + _scrollHorizontalOffset;
|
||||
_mouseDownIndex = CalLocationIndex(mx);
|
||||
_maxMoveLeft = -_mouseDownIndex * ItemWidth;
|
||||
var subIndex = _mouseDownIndex - CalLocationIndex(_scrollHorizontalOffset);
|
||||
_maxMoveLeft = -subIndex * ItemWidth;
|
||||
_maxMoveRight = TabControlParent.ActualWidth - ActualWidth + _maxMoveLeft;
|
||||
|
||||
_isDragging = true;
|
||||
ItemIsDragging = true;
|
||||
_isWaiting = true;
|
||||
_dragPoint = e.GetPosition(TabControlParent);
|
||||
_dragPoint = new Point(_dragPoint.X + +_scrollHorizontalOffset, _dragPoint.Y);
|
||||
_mouseDownPoint = _dragPoint;
|
||||
CaptureMouse();
|
||||
}
|
||||
@@ -199,9 +208,10 @@ namespace HandyControl.Controls
|
||||
base.OnMouseMove(e);
|
||||
if (ItemIsDragging && _isDragging)
|
||||
{
|
||||
var subX = TranslatePoint(new Point(), TabControlParent).X;
|
||||
var subX = TranslatePoint(new Point(), TabControlParent).X + _scrollHorizontalOffset;
|
||||
CurrentIndex = CalLocationIndex(subX);
|
||||
var p = e.GetPosition(TabControlParent);
|
||||
p = new Point(p.X + _scrollHorizontalOffset, p.Y);
|
||||
var subLeft = p.X - _dragPoint.X;
|
||||
var totalLeft = p.X - _mouseDownPoint.X;
|
||||
|
||||
@@ -229,7 +239,7 @@ namespace HandyControl.Controls
|
||||
ReleaseMouseCapture();
|
||||
if (_isDragged)
|
||||
{
|
||||
var subX = TranslatePoint(new Point(), TabControlParent).X;
|
||||
var subX = TranslatePoint(new Point(), TabControlParent).X + _scrollHorizontalOffset;
|
||||
var index = CalLocationIndex(subX);
|
||||
var left = index * ItemWidth;
|
||||
var offsetX = RenderTransform.Value.OffsetX;
|
||||
@@ -273,7 +283,7 @@ namespace HandyControl.Controls
|
||||
animation.Completed += (s1, e1) => AnimationCompleted();
|
||||
var f = new TranslateTransform(offsetX, 0);
|
||||
RenderTransform = f;
|
||||
f.BeginAnimation(TranslateTransform.XProperty, animation);
|
||||
f.BeginAnimation(TranslateTransform.XProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,26 +6,23 @@ 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
|
||||
public class Clock : ClockBase
|
||||
{
|
||||
#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";
|
||||
@@ -40,8 +37,6 @@ namespace HandyControl.Controls
|
||||
|
||||
private RadioButton _buttonPm;
|
||||
|
||||
private Button _buttonConfirm;
|
||||
|
||||
private Canvas _canvas;
|
||||
|
||||
private Border _borderTitle;
|
||||
@@ -60,59 +55,10 @@ namespace HandyControl.Controls
|
||||
|
||||
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)));
|
||||
|
||||
@@ -122,32 +68,6 @@ namespace HandyControl.Controls
|
||||
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;
|
||||
@@ -174,7 +94,7 @@ namespace HandyControl.Controls
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
_appliedTemplate = false;
|
||||
AppliedTemplate = false;
|
||||
if (_buttonAm != null)
|
||||
{
|
||||
_buttonAm.Click -= ButtonAm_OnClick;
|
||||
@@ -185,9 +105,9 @@ namespace HandyControl.Controls
|
||||
_buttonPm.Click -= ButtonPm_OnClick;
|
||||
}
|
||||
|
||||
if (_buttonConfirm != null)
|
||||
if (ButtonConfirm != null)
|
||||
{
|
||||
_buttonConfirm.Click -= ButtonConfirm_OnClick;
|
||||
ButtonConfirm.Click -= ButtonConfirm_OnClick;
|
||||
}
|
||||
|
||||
if (_borderTitle != null)
|
||||
@@ -206,18 +126,18 @@ namespace HandyControl.Controls
|
||||
|
||||
_buttonAm = GetTemplateChild(ElementButtonAm) as RadioButton;
|
||||
_buttonPm = GetTemplateChild(ElementButtonPm) as RadioButton;
|
||||
_buttonConfirm = GetTemplateChild(ElementButtonConfirm) as Button;
|
||||
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();
|
||||
if (!CheckNull()) return;
|
||||
|
||||
_buttonAm.Click += ButtonAm_OnClick;
|
||||
_buttonPm.Click += ButtonPm_OnClick;
|
||||
_buttonConfirm.Click += ButtonConfirm_OnClick;
|
||||
ButtonConfirm.Click += ButtonConfirm_OnClick;
|
||||
_borderTitle.MouseWheel += BorderTitle_OnMouseWheel;
|
||||
|
||||
_canvas.MouseWheel += Canvas_OnMouseWheel;
|
||||
@@ -241,7 +161,7 @@ namespace HandyControl.Controls
|
||||
_circlePanel.Children.Add(button);
|
||||
}
|
||||
|
||||
_appliedTemplate = true;
|
||||
AppliedTemplate = true;
|
||||
if (SelectedTime.HasValue)
|
||||
{
|
||||
Update(SelectedTime.Value);
|
||||
@@ -255,26 +175,15 @@ namespace HandyControl.Controls
|
||||
|
||||
#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()
|
||||
private bool CheckNull()
|
||||
{
|
||||
|
||||
if (_buttonPm == null || _buttonAm == null || _buttonConfirm == null || _canvas == null ||
|
||||
if (_buttonPm == null || _buttonAm == null || ButtonConfirm == null || _canvas == null ||
|
||||
_borderTitle == null || _borderClock == null || _circlePanel == null ||
|
||||
_blockTime == null) throw new Exception();
|
||||
_blockTime == null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void BorderTitle_OnMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
@@ -339,7 +248,7 @@ namespace HandyControl.Controls
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!_appliedTemplate) return;
|
||||
if (!AppliedTemplate) return;
|
||||
var hValue = _currentButton.Num;
|
||||
if (_buttonPm.IsChecked == true)
|
||||
{
|
||||
@@ -367,9 +276,9 @@ namespace HandyControl.Controls
|
||||
/// 更新
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
internal void Update(DateTime time)
|
||||
internal override void Update(DateTime time)
|
||||
{
|
||||
if (!_appliedTemplate) return;
|
||||
if (!AppliedTemplate) return;
|
||||
var h = time.Hour;
|
||||
var m = time.Minute;
|
||||
|
||||
@@ -396,12 +305,6 @@ namespace HandyControl.Controls
|
||||
Update();
|
||||
}
|
||||
|
||||
private void ButtonConfirm_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SelectedTime = DisplayTime;
|
||||
Confirmed?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取显示时间
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
[TemplatePart(Name = ElementButtonConfirm, Type = typeof(Button))]
|
||||
public abstract class ClockBase : Control
|
||||
{
|
||||
protected const string ElementButtonConfirm = "PART_ButtonConfirm";
|
||||
|
||||
protected Button ButtonConfirm;
|
||||
|
||||
protected bool AppliedTemplate;
|
||||
|
||||
public event Action Confirmed;
|
||||
|
||||
public event EventHandler<FunctionEventArgs<DateTime>> DisplayTimeChanged;
|
||||
|
||||
public static readonly RoutedEvent SelectedTimeChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("SelectedTimeChanged", RoutingStrategy.Direct,
|
||||
typeof(EventHandler<FunctionEventArgs<DateTime?>>), typeof(ClockBase));
|
||||
|
||||
public event EventHandler<FunctionEventArgs<DateTime?>> SelectedTimeChanged
|
||||
{
|
||||
add => AddHandler(SelectedTimeChangedEvent, value);
|
||||
remove => RemoveHandler(SelectedTimeChangedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TimeFormatProperty = DependencyProperty.Register(
|
||||
"TimeFormat", typeof(string), typeof(ClockBase), new PropertyMetadata("HH:mm:ss"));
|
||||
|
||||
public string TimeFormat
|
||||
{
|
||||
get => (string)GetValue(TimeFormatProperty);
|
||||
set => SetValue(TimeFormatProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectedTimeProperty = DependencyProperty.Register(
|
||||
"SelectedTime", typeof(DateTime?), typeof(ClockBase), new PropertyMetadata(default(DateTime?), OnSelectedTimeChanged));
|
||||
|
||||
private static void OnSelectedTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ClockBase)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 DisplayTimeProperty = DependencyProperty.Register(
|
||||
"DisplayTime", typeof(DateTime), typeof(ClockBase),
|
||||
new FrameworkPropertyMetadata(DateTime.Now, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
OnDisplayTimeChanged));
|
||||
|
||||
private static void OnDisplayTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ClockBase)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(ClockBase), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
internal bool ShowConfirmButton
|
||||
{
|
||||
get => (bool) GetValue(ShowConfirmButtonProperty);
|
||||
set => SetValue(ShowConfirmButtonProperty, value);
|
||||
}
|
||||
|
||||
protected virtual void OnSelectedTimeChanged(FunctionEventArgs<DateTime?> e) => RaiseEvent(e);
|
||||
|
||||
protected virtual void OnDisplayTimeChanged(FunctionEventArgs<DateTime> e)
|
||||
{
|
||||
var handler = DisplayTimeChanged;
|
||||
handler?.Invoke(this, e);
|
||||
}
|
||||
|
||||
protected void ButtonConfirm_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SelectedTime = DisplayTime;
|
||||
Confirmed?.Invoke();
|
||||
}
|
||||
|
||||
internal abstract void Update(DateTime time);
|
||||
|
||||
protected void Clock_SelectedTimeChanged(object sender, FunctionEventArgs<DateTime?> e) => SelectedTime = e.Info;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
[TemplatePart(Name = ElementHourList, Type = typeof(ListBox))]
|
||||
[TemplatePart(Name = ElementMinuteList, Type = typeof(ListBox))]
|
||||
[TemplatePart(Name = ElementSecondList, Type = typeof(ListBox))]
|
||||
public class ListClock : ClockBase
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string ElementHourList = "PART_HourList";
|
||||
private const string ElementMinuteList = "PART_MinuteList";
|
||||
private const string ElementSecondList = "PART_SecondList";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Data
|
||||
|
||||
private ListBox _hourList;
|
||||
|
||||
private ListBox _minuteList;
|
||||
|
||||
private ListBox _secondList;
|
||||
|
||||
#endregion Data
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
AppliedTemplate = false;
|
||||
if (ButtonConfirm != null)
|
||||
{
|
||||
ButtonConfirm.Click -= ButtonConfirm_OnClick;
|
||||
}
|
||||
|
||||
if (_hourList != null)
|
||||
{
|
||||
_hourList.SelectionChanged -= HourList_SelectionChanged;
|
||||
}
|
||||
|
||||
if (_minuteList != null)
|
||||
{
|
||||
_minuteList.SelectionChanged -= MinuteList_SelectionChanged;
|
||||
}
|
||||
|
||||
if (_secondList != null)
|
||||
{
|
||||
_secondList.SelectionChanged -= SecondList_SelectionChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_hourList = GetTemplateChild(ElementHourList) as ListBox;
|
||||
if (_hourList != null)
|
||||
{
|
||||
CreateItemsSource(_hourList, 24);
|
||||
_hourList.SelectionChanged += HourList_SelectionChanged;
|
||||
}
|
||||
|
||||
_minuteList = GetTemplateChild(ElementMinuteList) as ListBox;
|
||||
if (_minuteList != null)
|
||||
{
|
||||
CreateItemsSource(_minuteList, 60);
|
||||
_minuteList.SelectionChanged += MinuteList_SelectionChanged;
|
||||
}
|
||||
|
||||
_secondList = GetTemplateChild(ElementSecondList) as ListBox;
|
||||
if (_secondList != null)
|
||||
{
|
||||
CreateItemsSource(_secondList, 60);
|
||||
_secondList.SelectionChanged += SecondList_SelectionChanged;
|
||||
}
|
||||
|
||||
ButtonConfirm = GetTemplateChild(ElementButtonConfirm) as Button;
|
||||
|
||||
if (ButtonConfirm != null)
|
||||
{
|
||||
ButtonConfirm.Click += ButtonConfirm_OnClick;
|
||||
}
|
||||
|
||||
AppliedTemplate = true;
|
||||
if (SelectedTime.HasValue)
|
||||
{
|
||||
Update(SelectedTime.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayTime = DateTime.Now;
|
||||
Update(DisplayTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void HourList_SelectionChanged(object sender, SelectionChangedEventArgs e) => Update();
|
||||
|
||||
private void MinuteList_SelectionChanged(object sender, SelectionChangedEventArgs e) => Update();
|
||||
|
||||
private void SecondList_SelectionChanged(object sender, SelectionChangedEventArgs e) => Update();
|
||||
|
||||
private void CreateItemsSource(ItemsControl selector, int count)
|
||||
{
|
||||
var list = new List<string>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
list.Add(i.ToString("#00"));
|
||||
}
|
||||
|
||||
selector.ItemsSource = list;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_hourList.SelectedIndex >= 0 && _hourList.SelectedIndex < 24 &&
|
||||
_minuteList.SelectedIndex >= 0 && _minuteList.SelectedIndex < 60 &&
|
||||
_secondList.SelectedIndex >= 0 && _secondList.SelectedIndex < 60)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
DisplayTime = new DateTime(now.Year, now.Month, now.Day, _hourList.SelectedIndex,
|
||||
_minuteList.SelectedIndex, _secondList.SelectedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
internal override void Update(DateTime time)
|
||||
{
|
||||
if (!AppliedTemplate) return;
|
||||
|
||||
var h = time.Hour;
|
||||
var m = time.Minute;
|
||||
var s = time.Second;
|
||||
|
||||
_hourList.SelectedIndex = h;
|
||||
_minuteList.SelectedIndex = m;
|
||||
_secondList.SelectedIndex = s;
|
||||
|
||||
_hourList.ScrollIntoView(_hourList.SelectedItem);
|
||||
_minuteList.ScrollIntoView(_minuteList.SelectedItem);
|
||||
_secondList.ScrollIntoView(_secondList.SelectedItem);
|
||||
|
||||
DisplayTime = time;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,10 @@ namespace HandyControl.Controls
|
||||
|
||||
private IEnumerable _itemsSourceInternal;
|
||||
|
||||
private IEnumerable _initEnumerable;
|
||||
|
||||
private NotifyCollectionChangedEventArgs _initArgs;
|
||||
|
||||
public static readonly RoutedEvent SelectionChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("SelectionChanged", RoutingStrategy.Bubble,
|
||||
typeof(SelectionChangedEventHandler), typeof(Transfer));
|
||||
@@ -71,7 +75,22 @@ namespace HandyControl.Controls
|
||||
_itemsOrigin = GetTemplateChild(ElementItemsOrigin) as SimpleItemsControl;
|
||||
_itemsSelected = GetTemplateChild(ElementItemsSelected) as SimpleItemsControl;
|
||||
|
||||
Refresh();
|
||||
if (_itemsOrigin != null && _itemsSelected != null)
|
||||
{
|
||||
if (_initEnumerable != null)
|
||||
{
|
||||
OnItemsSourceChanged(null, _itemsSourceInternal);
|
||||
_itemsSourceInternal = null;
|
||||
}
|
||||
|
||||
if (_initArgs != null)
|
||||
{
|
||||
InternalCollectionChanged(null, _initArgs);
|
||||
_initArgs = null;
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddItem(object item)
|
||||
@@ -114,6 +133,12 @@ namespace HandyControl.Controls
|
||||
|
||||
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
|
||||
{
|
||||
if (_itemsOrigin == null || _itemsSelected == null)
|
||||
{
|
||||
_initEnumerable = newValue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_itemsSourceInternal != null)
|
||||
{
|
||||
if (_itemsSourceInternal is INotifyCollectionChanged s)
|
||||
@@ -139,6 +164,12 @@ namespace HandyControl.Controls
|
||||
|
||||
private void InternalCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (_itemsOrigin == null || _itemsSelected == null)
|
||||
{
|
||||
_initArgs = e;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (var item in e.OldItems)
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace HandyControl.Controls
|
||||
|
||||
public static readonly DependencyProperty NonClientAreaHeightProperty = DependencyProperty.Register(
|
||||
"NonClientAreaHeight", typeof(double), typeof(Window),
|
||||
new PropertyMetadata(28.0));
|
||||
new PropertyMetadata(26.0));
|
||||
|
||||
public static readonly DependencyProperty ShowNonClientAreaProperty = DependencyProperty.Register(
|
||||
"ShowNonClientArea", typeof(bool), typeof(Window),
|
||||
@@ -288,19 +288,25 @@ namespace HandyControl.Controls
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
BorderThickness = new Thickness();
|
||||
_tempNonClientAreaHeight = NonClientAreaHeight;
|
||||
NonClientAreaHeight += 8;
|
||||
}
|
||||
else if (WindowState == WindowState.Normal)
|
||||
{
|
||||
BorderThickness = _actualBorderThickness;
|
||||
NonClientAreaHeight = _tempNonClientAreaHeight;
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnLoaded(RoutedEventArgs args)
|
||||
{
|
||||
_actualBorderThickness = BorderThickness;
|
||||
_tempNonClientAreaHeight = NonClientAreaHeight;
|
||||
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
BorderThickness = new Thickness();
|
||||
_tempNonClientAreaHeight += 8;
|
||||
}
|
||||
|
||||
CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand,
|
||||
@@ -312,7 +318,6 @@ namespace HandyControl.Controls
|
||||
CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, (s, e) => Close()));
|
||||
CommandBindings.Add(new CommandBinding(SystemCommands.ShowSystemMenuCommand, ShowSystemMenu));
|
||||
|
||||
_tempNonClientAreaHeight = NonClientAreaHeight;
|
||||
_tempWindowState = WindowState;
|
||||
_tempWindowStyle = WindowStyle;
|
||||
_tempResizeMode = ResizeMode;
|
||||
@@ -320,6 +325,11 @@ namespace HandyControl.Controls
|
||||
SwitchIsFullScreen(_isFullScreen);
|
||||
SwitchShowNonClientArea(_showNonClientArea);
|
||||
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
_tempNonClientAreaHeight -= 8;
|
||||
}
|
||||
|
||||
if (SizeToContent != SizeToContent.WidthAndHeight)
|
||||
return;
|
||||
|
||||
|
||||
Reference in new issue
Block a user