Merge branch 'master' into Coverflow
This commit is contained in:
130 files changed
+6247
-3817
No files matched your search
@@ -75,5 +75,14 @@ namespace HandyControl.Controls
|
||||
|
||||
public static VerticalAlignment GetVerticalAlignment(DependencyObject element)
|
||||
=> (VerticalAlignment) element.GetValue(VerticalAlignmentProperty);
|
||||
|
||||
public static readonly DependencyProperty MarginOnTheLeftProperty = DependencyProperty.RegisterAttached(
|
||||
"MarginOnTheLeft", typeof(Thickness), typeof(TitleElement), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetMarginOnTheLeft(DependencyObject element, Thickness value)
|
||||
=> element.SetValue(MarginOnTheLeftProperty, value);
|
||||
|
||||
public static Thickness GetMarginOnTheLeft(DependencyObject element)
|
||||
=> (Thickness) element.GetValue(MarginOnTheLeftProperty);
|
||||
}
|
||||
}
|
||||
@@ -103,18 +103,13 @@ namespace HandyControl.Controls
|
||||
/// </summary>
|
||||
private int _lastShowIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 跳转编号
|
||||
/// </summary>
|
||||
private int _jumpToIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// </summary>
|
||||
public int PageIndex
|
||||
{
|
||||
get => (int) GetValue(PageIndexProperty);
|
||||
internal set => SetValue(PageIndexProperty, value);
|
||||
set => SetValue(PageIndexProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -147,11 +142,6 @@ namespace HandyControl.Controls
|
||||
_visualParent = GetTemplateChild(ElementVisualParent) as ModelVisual3D;
|
||||
|
||||
UpdateShowRange();
|
||||
if (_jumpToIndex > 0)
|
||||
{
|
||||
PageIndex = _jumpToIndex;
|
||||
_jumpToIndex = -1;
|
||||
}
|
||||
|
||||
_point3DAnimation = new Point3DAnimation(new Point3D(CoverFlowItem.Interval * PageIndex, _camera.Position.Y, _camera.Position.Z), new Duration(TimeSpan.FromMilliseconds(200)));
|
||||
_camera.BeginAnimation(ProjectionCamera.PositionProperty, _point3DAnimation);
|
||||
@@ -181,15 +171,10 @@ namespace HandyControl.Controls
|
||||
/// <param name="uri"></param>
|
||||
public void Add(Uri uri) => _contentDic.Add(_contentDic.Count, uri);
|
||||
|
||||
/// <summary>
|
||||
/// 跳转
|
||||
/// </summary>
|
||||
public void JumpTo(int index) => _jumpToIndex = index;
|
||||
|
||||
public void Next() => PageIndex++;
|
||||
|
||||
public void Prev() => PageIndex--;
|
||||
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
@@ -241,6 +226,11 @@ namespace HandyControl.Controls
|
||||
/// <param name="newIndex"></param>
|
||||
private void UpdateIndex(int newIndex)
|
||||
{
|
||||
if (!IsLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateShowRange();
|
||||
_itemShowDic.Do(item =>
|
||||
{
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Helper;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
[TemplatePart(Name = SearchTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
public class AutoCompleteTextBox : ComboBox
|
||||
{
|
||||
private const string SearchTextBox = "PART_SearchTextBox";
|
||||
|
||||
private bool ignoreTextChanging;
|
||||
|
||||
private System.Windows.Controls.TextBox _searchTextBox;
|
||||
|
||||
private object _selectedItem;
|
||||
|
||||
static AutoCompleteTextBox()
|
||||
{
|
||||
TextProperty.OverrideMetadata(typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
_searchTextBox.GotFocus -= SearchTextBoxGotFocus;
|
||||
_searchTextBox.KeyDown -= SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged -= SearchTextBoxTextChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_searchTextBox = GetTemplateChild(SearchTextBox) as System.Windows.Controls.TextBox;
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
_searchTextBox.GotFocus += SearchTextBoxGotFocus;
|
||||
_searchTextBox.PreviewKeyDown += SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged += SearchTextBoxTextChanged;
|
||||
}
|
||||
|
||||
UpdateTextBoxBySelectedItem(_selectedItem);
|
||||
}
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
base.OnSelectionChanged(e);
|
||||
|
||||
if (e.AddedItems.Count > 0)
|
||||
{
|
||||
_selectedItem = e.AddedItems[0];
|
||||
UpdateTextBoxBySelectedItem(_selectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is AutoCompleteTextBoxItem;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new AutoCompleteTextBoxItem();
|
||||
|
||||
private void SearchTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
_selectedItem = null;
|
||||
SelectedIndex = -1;
|
||||
|
||||
if (ignoreTextChanging)
|
||||
{
|
||||
ignoreTextChanging = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Text = _searchTextBox.Text;
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
_searchTextBox.Focus();
|
||||
}
|
||||
else if (_searchTextBox.IsFocused)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
|
||||
private void SearchTextBoxKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Up)
|
||||
{
|
||||
var index = SelectedIndex - 1;
|
||||
if (index < 0)
|
||||
{
|
||||
index = Items.Count - 1;
|
||||
}
|
||||
|
||||
UpdateTextBoxBySelectedIndex(index);
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
var index = SelectedIndex + 1;
|
||||
if (index >= Items.Count)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
|
||||
UpdateTextBoxBySelectedIndex(index);
|
||||
}
|
||||
else if (e.Key == Key.Enter)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTextBoxBySelectedIndex(int selectedIndex)
|
||||
{
|
||||
if (_searchTextBox == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ignoreTextChanging = true;
|
||||
|
||||
if (ItemContainerGenerator.ContainerFromIndex(selectedIndex) is AutoCompleteTextBoxItem boxItem)
|
||||
{
|
||||
_searchTextBox.Text = BindingHelper.GetString(boxItem.Content, DisplayMemberPath);
|
||||
_searchTextBox.CaretIndex = _searchTextBox.Text.Length;
|
||||
|
||||
SelectedIndex = selectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTextBoxBySelectedItem(object selectedItem)
|
||||
{
|
||||
if (_searchTextBox == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ignoreTextChanging = true;
|
||||
|
||||
_searchTextBox.Text = BindingHelper.GetString(selectedItem, DisplayMemberPath);
|
||||
_searchTextBox.CaretIndex = _searchTextBox.Text.Length;
|
||||
|
||||
ignoreTextChanging = true;
|
||||
|
||||
Text = _searchTextBox.Text;
|
||||
|
||||
ignoreTextChanging = false;
|
||||
}
|
||||
|
||||
private void SearchTextBoxGotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class AutoCompleteTextBoxItem : ComboBoxItem
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -196,7 +196,7 @@ namespace HandyControl.Controls
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -368,7 +368,7 @@ namespace HandyControl.Controls
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace HandyControl.Controls
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -447,7 +447,7 @@ namespace HandyControl.Controls
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -12,6 +12,16 @@ namespace HandyControl.Controls
|
||||
{
|
||||
public class ImageSelector : Control
|
||||
{
|
||||
public static readonly RoutedEvent ImageSelectedEvent =
|
||||
EventManager.RegisterRoutedEvent("ImageSelected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(ImageSelector));
|
||||
|
||||
public event RoutedEventHandler ImageSelected
|
||||
{
|
||||
add => AddHandler(ImageSelectedEvent, value);
|
||||
remove => RemoveHandler(ImageSelectedEvent, value);
|
||||
}
|
||||
|
||||
public ImageSelector() => CommandBindings.Add(new CommandBinding(ControlCommands.Switch, SwitchImage));
|
||||
|
||||
private void SwitchImage(object sender, ExecutedRoutedEventArgs e)
|
||||
@@ -34,6 +44,7 @@ namespace HandyControl.Controls
|
||||
});
|
||||
SetValue(HasValuePropertyKey, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ToolTipProperty, dialog.FileName);
|
||||
RaiseEvent(new RoutedEventArgs(ImageSelectedEvent, this));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace HandyControl.Controls
|
||||
|
||||
if (Validation.GetHasError(this))
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ namespace HandyControl.Controls
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -367,7 +367,7 @@ namespace HandyControl.Controls
|
||||
|
||||
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (VerifyData() && !IsSafeEnabled)
|
||||
if (!IsSafeEnabled)
|
||||
{
|
||||
SetCurrentValue(UnsafePasswordProperty, ActualPasswordBox.Password);
|
||||
|
||||
@@ -376,17 +376,19 @@ namespace HandyControl.Controls
|
||||
_textBox.Text = ActualPasswordBox.Password;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
VerifyData();
|
||||
|
||||
if (!IsSafeEnabled && ShowPassword)
|
||||
{
|
||||
Password = _textBox.Text;
|
||||
SetCurrentValue(UnsafePasswordProperty, Password);
|
||||
}
|
||||
|
||||
VerifyData();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ namespace HandyControl.Controls
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -406,7 +406,7 @@ namespace HandyControl.Controls
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Expression.Drawing;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
@@ -45,8 +44,7 @@ namespace HandyControl.Controls
|
||||
|
||||
public static readonly DependencyProperty SpacingProperty = DependencyProperty.Register(
|
||||
"Spacing", typeof(double), typeof(UniformSpacingPanel),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsMeasure),
|
||||
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
||||
new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure), IsSpacingValid);
|
||||
|
||||
public double Spacing
|
||||
{
|
||||
@@ -54,6 +52,26 @@ namespace HandyControl.Controls
|
||||
set => SetValue(SpacingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HorizontalSpacingProperty = DependencyProperty.Register(
|
||||
"HorizontalSpacing", typeof(double), typeof(UniformSpacingPanel),
|
||||
new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure), IsSpacingValid);
|
||||
|
||||
public double HorizontalSpacing
|
||||
{
|
||||
get => (double) GetValue(HorizontalSpacingProperty);
|
||||
set => SetValue(HorizontalSpacingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty VerticalSpacingProperty = DependencyProperty.Register(
|
||||
"VerticalSpacing", typeof(double), typeof(UniformSpacingPanel),
|
||||
new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure), IsSpacingValid);
|
||||
|
||||
public double VerticalSpacing
|
||||
{
|
||||
get => (double) GetValue(VerticalSpacingProperty);
|
||||
set => SetValue(VerticalSpacingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register(
|
||||
"ItemWidth", typeof(double), typeof(UniformSpacingPanel),
|
||||
new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsMeasure),
|
||||
@@ -78,12 +96,6 @@ namespace HandyControl.Controls
|
||||
set => SetValue(ItemHeightProperty, value);
|
||||
}
|
||||
|
||||
private static bool IsWidthHeightValid(object value)
|
||||
{
|
||||
var v = (double) value;
|
||||
return double.IsNaN(v) || v >= 0.0d && !double.IsPositiveInfinity(v);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemHorizontalAlignmentProperty = DependencyProperty.Register(
|
||||
"ItemHorizontalAlignment", typeof(HorizontalAlignment?), typeof(UniformSpacingPanel),
|
||||
new FrameworkPropertyMetadata(HorizontalAlignment.Stretch, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
@@ -104,6 +116,22 @@ namespace HandyControl.Controls
|
||||
set => SetValue(ItemVerticalAlignmentProperty, value);
|
||||
}
|
||||
|
||||
private static bool IsWidthHeightValid(object value)
|
||||
{
|
||||
var v = (double) value;
|
||||
return double.IsNaN(v) || v >= 0.0d && !double.IsPositiveInfinity(v);
|
||||
}
|
||||
|
||||
private static bool IsSpacingValid(object value)
|
||||
{
|
||||
if (value is double spacing)
|
||||
{
|
||||
return double.IsNaN(spacing) || spacing > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ArrangeWrapLine(double v, double lineV, int start, int end, bool useItemU, double itemU, double spacing)
|
||||
{
|
||||
double u = 0;
|
||||
@@ -115,7 +143,7 @@ namespace HandyControl.Controls
|
||||
var child = children[i];
|
||||
if (child == null) continue;
|
||||
|
||||
var childSize = new UVSize(_orientation, child.DesiredSize.Width, child.DesiredSize.Height);
|
||||
var childSize = new PanelUvSize(_orientation, child.DesiredSize);
|
||||
var layoutSlotU = useItemU ? itemU : childSize.U;
|
||||
|
||||
child.Arrange(isHorizontal ? new Rect(u, v, layoutSlotU, lineV) : new Rect(v, u, lineV, layoutSlotU));
|
||||
@@ -138,7 +166,7 @@ namespace HandyControl.Controls
|
||||
var child = children[i];
|
||||
if (child == null) continue;
|
||||
|
||||
var childSize = new UVSize(_orientation, child.DesiredSize.Width, child.DesiredSize.Height);
|
||||
var childSize = new PanelUvSize(_orientation, child.DesiredSize);
|
||||
var layoutSlotU = useItemU ? itemU : childSize.U;
|
||||
|
||||
child.Arrange(isHorizontal ? new Rect(u, 0, layoutSlotU, lineV) : new Rect(0, u, lineV, layoutSlotU));
|
||||
@@ -152,19 +180,19 @@ namespace HandyControl.Controls
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
var curLineSize = new UVSize(_orientation);
|
||||
var panelSize = new UVSize(_orientation);
|
||||
var uvConstraint = new UVSize(_orientation, constraint.Width, constraint.Height);
|
||||
var curLineSize = new PanelUvSize(_orientation);
|
||||
var panelSize = new PanelUvSize(_orientation);
|
||||
var uvConstraint = new PanelUvSize(_orientation, constraint);
|
||||
var itemWidth = ItemWidth;
|
||||
var itemHeight = ItemHeight;
|
||||
var itemWidthSet = !double.IsNaN(itemWidth);
|
||||
var itemHeightSet = !double.IsNaN(itemHeight);
|
||||
var spacing = Spacing;
|
||||
var childWrapping = ChildWrapping;
|
||||
var itemHorizontalAlignment = ItemHorizontalAlignment;
|
||||
var itemVerticalAlignment = ItemVerticalAlignment;
|
||||
var itemHorizontalAlignmentSet = itemHorizontalAlignment != null;
|
||||
var itemVerticalAlignmentSet = ItemVerticalAlignment != null;
|
||||
var spacingSize = GetSpacingSize();
|
||||
|
||||
var childConstraint = new Size(
|
||||
itemWidthSet ? itemWidth : constraint.Width,
|
||||
@@ -192,29 +220,29 @@ namespace HandyControl.Controls
|
||||
|
||||
child.Measure(childConstraint);
|
||||
|
||||
var sz = new UVSize(
|
||||
var sz = new PanelUvSize(
|
||||
_orientation,
|
||||
itemWidthSet ? itemWidth : child.DesiredSize.Width,
|
||||
itemHeightSet ? itemHeight : child.DesiredSize.Height);
|
||||
|
||||
if (MathHelper.GreaterThan(curLineSize.U + sz.U + spacing, uvConstraint.U))
|
||||
if (MathHelper.GreaterThan(curLineSize.U + sz.U + spacingSize.U, uvConstraint.U))
|
||||
{
|
||||
panelSize.U = Math.Max(curLineSize.U, panelSize.U);
|
||||
panelSize.V += curLineSize.V + spacing;
|
||||
panelSize.V += curLineSize.V + spacingSize.V;
|
||||
curLineSize = sz;
|
||||
|
||||
if (MathHelper.GreaterThan(sz.U, uvConstraint.U))
|
||||
{
|
||||
panelSize.U = Math.Max(sz.U, panelSize.U);
|
||||
panelSize.V += sz.V + spacing;
|
||||
curLineSize = new UVSize(_orientation);
|
||||
panelSize.V += sz.V + spacingSize.V;
|
||||
curLineSize = new PanelUvSize(_orientation);
|
||||
}
|
||||
|
||||
isFirst = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
curLineSize.U += isFirst ? sz.U : sz.U + spacing;
|
||||
curLineSize.U += isFirst ? sz.U : sz.U + spacingSize.U;
|
||||
curLineSize.V = Math.Max(sz.V, curLineSize.V);
|
||||
|
||||
isFirst = false;
|
||||
@@ -251,12 +279,12 @@ namespace HandyControl.Controls
|
||||
|
||||
child.Measure(layoutSlotSize);
|
||||
|
||||
var sz = new UVSize(
|
||||
var sz = new PanelUvSize(
|
||||
_orientation,
|
||||
itemWidthSet ? itemWidth : child.DesiredSize.Width,
|
||||
itemHeightSet ? itemHeight : child.DesiredSize.Height);
|
||||
|
||||
curLineSize.U += isFirst ? sz.U : sz.U + spacing;
|
||||
curLineSize.U += isFirst ? sz.U : sz.U + spacingSize.U;
|
||||
curLineSize.V = Math.Max(sz.V, curLineSize.V);
|
||||
|
||||
isFirst = false;
|
||||
@@ -269,6 +297,30 @@ namespace HandyControl.Controls
|
||||
return new Size(panelSize.Width, panelSize.Height);
|
||||
}
|
||||
|
||||
private PanelUvSize GetSpacingSize()
|
||||
{
|
||||
var spacing = Spacing;
|
||||
|
||||
if (!double.IsNaN(spacing))
|
||||
{
|
||||
return new PanelUvSize(_orientation, spacing, spacing);
|
||||
}
|
||||
|
||||
var horizontalSpacing = HorizontalSpacing;
|
||||
if (double.IsNaN(horizontalSpacing))
|
||||
{
|
||||
horizontalSpacing = 0;
|
||||
}
|
||||
|
||||
var verticalSpacing = VerticalSpacing;
|
||||
if (double.IsNaN(verticalSpacing))
|
||||
{
|
||||
verticalSpacing = 0;
|
||||
}
|
||||
|
||||
return new PanelUvSize(_orientation, horizontalSpacing, verticalSpacing);
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
var firstInLine = 0;
|
||||
@@ -276,13 +328,13 @@ namespace HandyControl.Controls
|
||||
var itemHeight = ItemHeight;
|
||||
double accumulatedV = 0;
|
||||
var itemU = _orientation == Orientation.Horizontal ? itemWidth : itemHeight;
|
||||
var curLineSize = new UVSize(_orientation);
|
||||
var uvFinalSize = new UVSize(_orientation, finalSize.Width, finalSize.Height);
|
||||
var curLineSize = new PanelUvSize(_orientation);
|
||||
var uvFinalSize = new PanelUvSize(_orientation, finalSize);
|
||||
var itemWidthSet = !double.IsNaN(itemWidth);
|
||||
var itemHeightSet = !double.IsNaN(itemHeight);
|
||||
var useItemU = _orientation == Orientation.Horizontal ? itemWidthSet : itemHeightSet;
|
||||
var spacing = Spacing;
|
||||
var childWrapping = ChildWrapping;
|
||||
var spacingSize = GetSpacingSize();
|
||||
|
||||
var children = InternalChildren;
|
||||
var isFirst = true;
|
||||
@@ -294,104 +346,40 @@ namespace HandyControl.Controls
|
||||
var child = children[i];
|
||||
if (child == null) continue;
|
||||
|
||||
var sz = new UVSize(
|
||||
var sz = new PanelUvSize(
|
||||
_orientation,
|
||||
itemWidthSet ? itemWidth : child.DesiredSize.Width,
|
||||
itemHeightSet ? itemHeight : child.DesiredSize.Height);
|
||||
|
||||
if (MathHelper.GreaterThan(curLineSize.U + sz.U + spacing, uvFinalSize.U))
|
||||
if (MathHelper.GreaterThan(curLineSize.U + (isFirst ? sz.U : sz.U + spacingSize.U), uvFinalSize.U))
|
||||
{
|
||||
ArrangeWrapLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU, spacing);
|
||||
ArrangeWrapLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU, spacingSize.U);
|
||||
|
||||
accumulatedV += curLineSize.V + spacing;
|
||||
accumulatedV += curLineSize.V + spacingSize.V;
|
||||
curLineSize = sz;
|
||||
|
||||
if (MathHelper.GreaterThan(sz.U, uvFinalSize.U))
|
||||
{
|
||||
ArrangeWrapLine(accumulatedV, sz.V, i, ++i, useItemU, itemU, spacing);
|
||||
|
||||
accumulatedV += sz.V + spacing;
|
||||
curLineSize = new UVSize(_orientation);
|
||||
}
|
||||
|
||||
firstInLine = i;
|
||||
isFirst = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
curLineSize.U += isFirst ? sz.U : sz.U + spacing;
|
||||
curLineSize.U += isFirst ? sz.U : sz.U + spacingSize.U;
|
||||
curLineSize.V = Math.Max(sz.V, curLineSize.V);
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
|
||||
if (firstInLine < children.Count)
|
||||
{
|
||||
ArrangeWrapLine(accumulatedV, curLineSize.V, firstInLine, children.Count, useItemU, itemU, spacing);
|
||||
ArrangeWrapLine(accumulatedV, curLineSize.V, firstInLine, children.Count, useItemU, itemU, spacingSize.U);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrangeLine(uvFinalSize.V, useItemU, itemU, spacing);
|
||||
ArrangeLine(uvFinalSize.V, useItemU, itemU, spacingSize.U);
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
private struct UVSize
|
||||
{
|
||||
internal UVSize(Orientation orientation, double width, double height)
|
||||
{
|
||||
U = V = 0d;
|
||||
_orientation = orientation;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
internal UVSize(Orientation orientation)
|
||||
{
|
||||
U = V = 0d;
|
||||
_orientation = orientation;
|
||||
}
|
||||
|
||||
public double U { get; set; }
|
||||
|
||||
public double V { get; set; }
|
||||
|
||||
private readonly Orientation _orientation;
|
||||
|
||||
public double Width
|
||||
{
|
||||
get => _orientation == Orientation.Horizontal ? U : V;
|
||||
private set
|
||||
{
|
||||
if (_orientation == Orientation.Horizontal)
|
||||
{
|
||||
U = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
V = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double Height
|
||||
{
|
||||
get => _orientation == Orientation.Horizontal ? V : U;
|
||||
private set
|
||||
{
|
||||
if (_orientation == Orientation.Horizontal)
|
||||
{
|
||||
V = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
U = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Expression.Drawing;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
@@ -19,9 +21,30 @@ namespace HandyControl.Controls
|
||||
|
||||
private static bool IsGroupsValid(object value) => (int) value >= 1;
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(WaterfallPanel), new FrameworkPropertyMetadata(
|
||||
Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
public static readonly DependencyProperty AutoGroupProperty = DependencyProperty.Register(
|
||||
"AutoGroup", typeof(bool), typeof(WaterfallPanel), new FrameworkPropertyMetadata(
|
||||
ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
public bool AutoGroup
|
||||
{
|
||||
get => (bool) GetValue(AutoGroupProperty);
|
||||
set => SetValue(AutoGroupProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DesiredLengthProperty = DependencyProperty.Register(
|
||||
"DesiredLength", typeof(double), typeof(WaterfallPanel), new FrameworkPropertyMetadata(ValueBoxes.Double0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure), ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
||||
|
||||
public double DesiredLength
|
||||
{
|
||||
get => (double) GetValue(DesiredLengthProperty);
|
||||
set => SetValue(DesiredLengthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty =
|
||||
StackPanel.OrientationProperty.AddOwner(typeof(WaterfallPanel),
|
||||
new FrameworkPropertyMetadata(Orientation.Horizontal,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
@@ -29,56 +52,98 @@ namespace HandyControl.Controls
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
private int CaculateGroupCount(Orientation orientation, PanelUvSize size)
|
||||
{
|
||||
if (!AutoGroup)
|
||||
{
|
||||
return Groups;
|
||||
}
|
||||
|
||||
var itemLength = DesiredLength;
|
||||
|
||||
if (MathHelper.IsVerySmall(itemLength))
|
||||
{
|
||||
return Groups;
|
||||
}
|
||||
|
||||
return (int) (size.U / itemLength);
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
var orientation = Orientation;
|
||||
var uvConstraint = new PanelUvSize(orientation, finalSize);
|
||||
|
||||
var groups = CaculateGroupCount(orientation, uvConstraint);
|
||||
if (groups < 1)
|
||||
{
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
var vArr = new double[groups].ToList();
|
||||
var itemU = uvConstraint.U / groups;
|
||||
|
||||
var children = InternalChildren;
|
||||
for (int i = 0, count = children.Count; i < count; i++)
|
||||
{
|
||||
var child = children[i];
|
||||
if (child == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var minIndex = vArr.IndexOf(vArr.Min());
|
||||
var minV = vArr[minIndex];
|
||||
var childUvSize = new PanelUvSize(orientation, child.DesiredSize);
|
||||
var childSize = new PanelUvSize(orientation, itemU, childUvSize.V);
|
||||
var childRectSize = new PanelUvSize(orientation, minIndex * itemU, minV);
|
||||
|
||||
child.Arrange(new Rect(new Point(childRectSize.U, childRectSize.V), childSize.ScreenSize));
|
||||
vArr[minIndex] = minV + childUvSize.V;
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
var groups = Groups;
|
||||
var orientation = Orientation;
|
||||
var uvConstraint = new PanelUvSize(orientation, constraint);
|
||||
|
||||
var groups = CaculateGroupCount(orientation, uvConstraint);
|
||||
if (groups < 1)
|
||||
{
|
||||
return constraint;
|
||||
}
|
||||
|
||||
var vArr = new double[groups].ToList();
|
||||
var itemU = uvConstraint.U / groups;
|
||||
if (double.IsNaN(itemU) || double.IsInfinity(itemU))
|
||||
{
|
||||
return constraint;
|
||||
}
|
||||
|
||||
if (groups < 1) return constraint;
|
||||
var children = InternalChildren;
|
||||
Size panelSize;
|
||||
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
for (int i = 0, count = children.Count; i < count; i++)
|
||||
{
|
||||
var heightArr = new double[groups].ToList();
|
||||
var itemWidth = constraint.Width / groups;
|
||||
if (double.IsNaN(itemWidth) || double.IsInfinity(itemWidth)) return constraint;
|
||||
|
||||
for (int i = 0, count = children.Count; i < count; i++)
|
||||
var child = children[i];
|
||||
if (child == null)
|
||||
{
|
||||
var child = children[i];
|
||||
if (child == null) continue;
|
||||
|
||||
child.Measure(constraint);
|
||||
var minIndex = heightArr.IndexOf(heightArr.Min());
|
||||
var minY = heightArr[minIndex];
|
||||
child.Arrange(new Rect(new Point(minIndex * itemWidth, minY), new Size(itemWidth, child.DesiredSize.Height)));
|
||||
|
||||
heightArr[minIndex] = minY + child.DesiredSize.Height;
|
||||
continue;
|
||||
}
|
||||
panelSize = new Size(constraint.Width, heightArr.Max());
|
||||
}
|
||||
else
|
||||
{
|
||||
var widthArr = new double[groups].ToList();
|
||||
var itemHeight = constraint.Height / groups;
|
||||
if (double.IsNaN(itemHeight) || double.IsInfinity(itemHeight)) return constraint;
|
||||
|
||||
for (int i = 0, count = children.Count; i < count; i++)
|
||||
{
|
||||
var child = children[i];
|
||||
if (child == null) continue;
|
||||
child.Measure(constraint);
|
||||
|
||||
child.Measure(constraint);
|
||||
var minIndex = widthArr.IndexOf(widthArr.Min());
|
||||
var minX = widthArr[minIndex];
|
||||
child.Arrange(new Rect(new Point(minX, minIndex * itemHeight), new Size(child.DesiredSize.Width, itemHeight)));
|
||||
var sz = new PanelUvSize(orientation, child.DesiredSize);
|
||||
var minIndex = vArr.IndexOf(vArr.Min());
|
||||
var minV = vArr[minIndex];
|
||||
|
||||
widthArr[minIndex] = minX + child.DesiredSize.Width;
|
||||
}
|
||||
panelSize = new Size(widthArr.Max(), constraint.Height);
|
||||
vArr[minIndex] = minV + sz.V;
|
||||
}
|
||||
|
||||
return panelSize;
|
||||
uvConstraint = new PanelUvSize(orientation, new Size(uvConstraint.ScreenSize.Width, vArr.Max()));
|
||||
|
||||
return uvConstraint.ScreenSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,7 @@ namespace HandyControl.Controls
|
||||
public bool IsIndeterminate
|
||||
{
|
||||
get => (bool) GetValue(IsIndeterminateProperty);
|
||||
set => SetValue(IsIndeterminateProperty, value);
|
||||
set => SetValue(IsIndeterminateProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private void SetProgressBarIndicatorAngle()
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace HandyControl.Controls
|
||||
public bool ShowSortButton
|
||||
{
|
||||
get => (bool) GetValue(ShowSortButtonProperty);
|
||||
set => SetValue(ShowSortButtonProperty, value);
|
||||
set => SetValue(ShowSortButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace HandyControl.Controls
|
||||
public bool ShowCloseButton
|
||||
{
|
||||
get => (bool) GetValue(ShowCloseButtonProperty);
|
||||
set => SetValue(ShowCloseButtonProperty, value);
|
||||
set => SetValue(ShowCloseButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -116,7 +116,7 @@ namespace HandyControl.Controls
|
||||
public bool ShowContextMenu
|
||||
{
|
||||
get => (bool) GetValue(ShowContextMenuProperty);
|
||||
set => SetValue(ShowContextMenuProperty, value);
|
||||
set => SetValue(ShowContextMenuProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace HandyControl.Controls
|
||||
public bool ShowCloseButton
|
||||
{
|
||||
get => (bool) GetValue(ShowCloseButtonProperty);
|
||||
set => SetValue(ShowCloseButtonProperty, value);
|
||||
set => SetValue(ShowCloseButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static void SetShowCloseButton(DependencyObject element, bool value)
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class HighlightTextBlock : TextBlock
|
||||
{
|
||||
public static readonly DependencyProperty SourceTextProperty =
|
||||
DependencyProperty.Register("SourceText", typeof(string), typeof(HighlightTextBlock),
|
||||
new PropertyMetadata(null, OnSourceTextChanged));
|
||||
|
||||
public static readonly DependencyProperty QueriesTextProperty =
|
||||
DependencyProperty.Register("QueriesText", typeof(string), typeof(HighlightTextBlock),
|
||||
new PropertyMetadata(null, OnQueriesTextChanged));
|
||||
|
||||
public static readonly DependencyProperty HighlightBrushProperty =
|
||||
DependencyProperty.Register("HighlightBrush", typeof(Brush), typeof(HighlightTextBlock),
|
||||
new PropertyMetadata(Brushes.Yellow));
|
||||
|
||||
private static void OnSourceTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
|
||||
((HighlightTextBlock) d).RefreshInlines();
|
||||
|
||||
private static void OnQueriesTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
|
||||
((HighlightTextBlock) d).RefreshInlines();
|
||||
|
||||
/// <summary>
|
||||
/// Replace the original property Text for binding text.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Don't use the <see cref="TextBlock.Text"/> property!
|
||||
/// Because the <see cref="TextBlock.Text"/> has some unique behaviors
|
||||
/// that is not needed at <see cref="HighlightTextBlock"/> at <see cref="TextBlock"/>,
|
||||
/// which will cause some unexpected issue.
|
||||
/// </remarks>
|
||||
public string SourceText
|
||||
{
|
||||
get => (string) GetValue(SourceTextProperty);
|
||||
set => SetValue(SourceTextProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text that need to be highlighted.
|
||||
/// It can be an array of text separated by spaces.
|
||||
/// </summary>
|
||||
public string QueriesText
|
||||
{
|
||||
get => (string) GetValue(QueriesTextProperty);
|
||||
set => SetValue(QueriesTextProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Brush"/> of the background of the highlight text.
|
||||
/// </summary>
|
||||
public Brush HighlightBrush
|
||||
{
|
||||
get => (Brush) GetValue(HighlightBrushProperty);
|
||||
set => SetValue(HighlightBrushProperty, value);
|
||||
}
|
||||
|
||||
private void RefreshInlines()
|
||||
{
|
||||
Inlines.Clear();
|
||||
|
||||
if (string.IsNullOrEmpty(SourceText)) return;
|
||||
if (string.IsNullOrEmpty(QueriesText))
|
||||
{
|
||||
Inlines.Add(SourceText);
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceText = SourceText;
|
||||
var queries = QueriesText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var intervals = from query in queries.Distinct()
|
||||
from interval in GetQueryIntervals(sourceText, query)
|
||||
select interval;
|
||||
var mergedIntervals = MergeIntervals(intervals.ToList());
|
||||
var fragments = SplitTextByOrderedDisjointIntervals(sourceText, mergedIntervals);
|
||||
|
||||
Inlines.AddRange(GenerateRunElement(fragments));
|
||||
}
|
||||
|
||||
private IEnumerable GenerateRunElement(IEnumerable<Fragment> fragments)
|
||||
{
|
||||
return from item in fragments
|
||||
select item.IsQuery
|
||||
? GetHighlightRun(item.Text)
|
||||
: new Run(item.Text);
|
||||
}
|
||||
|
||||
private Run GetHighlightRun(string highlightText)
|
||||
{
|
||||
var run = new Run(highlightText);
|
||||
run.SetBinding(TextElement.BackgroundProperty, new Binding
|
||||
{
|
||||
Source = this,
|
||||
Path = new PropertyPath(nameof(HighlightBrush)),
|
||||
Mode = BindingMode.OneWay
|
||||
});
|
||||
return run;
|
||||
}
|
||||
|
||||
private static IEnumerable<Fragment> SplitTextByOrderedDisjointIntervals(string sourceText, List<Range> mergedIntervals)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sourceText)) yield break;
|
||||
|
||||
if (!mergedIntervals?.Any() ?? true)
|
||||
{
|
||||
yield return new Fragment { Text = sourceText, IsQuery = false };
|
||||
yield break;
|
||||
}
|
||||
|
||||
var range0 = mergedIntervals.First();
|
||||
int start0 = range0.Start;
|
||||
int end0 = range0.End;
|
||||
|
||||
if (start0 > 0) yield return new Fragment { Text = sourceText.Substring(0, start0), IsQuery = false };
|
||||
yield return new Fragment { Text = sourceText.Substring(start0, end0 - start0), IsQuery = true };
|
||||
|
||||
int previousEnd = end0;
|
||||
foreach (var range in mergedIntervals.Skip(1))
|
||||
{
|
||||
int start = range.Start;
|
||||
int end = range.End;
|
||||
yield return new Fragment { Text = sourceText.Substring(previousEnd, start - previousEnd), IsQuery = false };
|
||||
yield return new Fragment { Text = sourceText.Substring(start, end - start), IsQuery = true };
|
||||
previousEnd = end;
|
||||
}
|
||||
|
||||
if (previousEnd < sourceText.Length)
|
||||
yield return new Fragment { Text = sourceText.Substring(previousEnd), IsQuery = false };
|
||||
}
|
||||
|
||||
private static List<Range> MergeIntervals(List<Range> intervals)
|
||||
{
|
||||
if (!intervals?.Any() ?? true) return new List<Range>();
|
||||
|
||||
intervals.Sort((x, y) => x.Start != y.Start ? x.Start - y.Start : x.End - y.End);
|
||||
|
||||
var pointer = intervals[0];
|
||||
int startPointer = pointer.Start;
|
||||
int endPointer = pointer.End;
|
||||
|
||||
var result = new List<Range>();
|
||||
foreach (var range in intervals.Skip(1))
|
||||
{
|
||||
int start = range.Start;
|
||||
int end = range.End;
|
||||
|
||||
if (start <= endPointer)
|
||||
{
|
||||
if (endPointer < end)
|
||||
{
|
||||
endPointer = end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(new Range { Start = startPointer, End = endPointer });
|
||||
startPointer = start;
|
||||
endPointer = end;
|
||||
}
|
||||
}
|
||||
result.Add(new Range { Start = startPointer, End = endPointer });
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<Range> GetQueryIntervals(string sourceText, string query)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sourceText) || string.IsNullOrEmpty(query)) yield break;
|
||||
|
||||
int nextStartIndex = 0;
|
||||
while (nextStartIndex < sourceText.Length)
|
||||
{
|
||||
int index = sourceText.IndexOf(query, nextStartIndex, StringComparison.CurrentCultureIgnoreCase);
|
||||
|
||||
if (index == -1) yield break;
|
||||
|
||||
nextStartIndex = index + query.Length;
|
||||
yield return new Range { Start = index, End = nextStartIndex };
|
||||
}
|
||||
}
|
||||
|
||||
private struct Fragment
|
||||
{
|
||||
public string Text { get; set; }
|
||||
|
||||
public bool IsQuery { get; set; }
|
||||
}
|
||||
|
||||
private struct Range
|
||||
{
|
||||
public int Start { get; set; }
|
||||
|
||||
public int End { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user