Merge branch 'master' into patch-2
This commit is contained in:
986 files changed
+63640
-61515
No files matched your search
@@ -1,22 +1,21 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class BackgroundSwitchElement
|
||||
{
|
||||
public class BackgroundSwitchElement
|
||||
{
|
||||
public static readonly DependencyProperty MouseHoverBackgroundProperty = DependencyProperty.RegisterAttached(
|
||||
"MouseHoverBackground", typeof(Brush), typeof(BackgroundSwitchElement), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty MouseHoverBackgroundProperty = DependencyProperty.RegisterAttached(
|
||||
"MouseHoverBackground", typeof(Brush), typeof(BackgroundSwitchElement), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetMouseHoverBackground(DependencyObject element, Brush value) => element.SetValue(MouseHoverBackgroundProperty, value);
|
||||
public static void SetMouseHoverBackground(DependencyObject element, Brush value) => element.SetValue(MouseHoverBackgroundProperty, value);
|
||||
|
||||
public static Brush GetMouseHoverBackground(DependencyObject element) => (Brush) element.GetValue(MouseHoverBackgroundProperty);
|
||||
public static Brush GetMouseHoverBackground(DependencyObject element) => (Brush) element.GetValue(MouseHoverBackgroundProperty);
|
||||
|
||||
public static readonly DependencyProperty MouseDownBackgroundProperty = DependencyProperty.RegisterAttached(
|
||||
"MouseDownBackground", typeof(Brush), typeof(BackgroundSwitchElement), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty MouseDownBackgroundProperty = DependencyProperty.RegisterAttached(
|
||||
"MouseDownBackground", typeof(Brush), typeof(BackgroundSwitchElement), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetMouseDownBackground(DependencyObject element, Brush value) => element.SetValue(MouseDownBackgroundProperty, value);
|
||||
public static void SetMouseDownBackground(DependencyObject element, Brush value) => element.SetValue(MouseDownBackgroundProperty, value);
|
||||
|
||||
public static Brush GetMouseDownBackground(DependencyObject element) => (Brush) element.GetValue(MouseDownBackgroundProperty);
|
||||
}
|
||||
public static Brush GetMouseDownBackground(DependencyObject element) => (Brush) element.GetValue(MouseDownBackgroundProperty);
|
||||
}
|
||||
@@ -4,47 +4,46 @@ using System.Windows.Data;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Converter;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class BorderElement
|
||||
{
|
||||
public class BorderElement
|
||||
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached(
|
||||
"CornerRadius", typeof(CornerRadius), typeof(BorderElement), new FrameworkPropertyMetadata(default(CornerRadius), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetCornerRadius(DependencyObject element, CornerRadius value) => element.SetValue(CornerRadiusProperty, value);
|
||||
|
||||
public static CornerRadius GetCornerRadius(DependencyObject element) => (CornerRadius) element.GetValue(CornerRadiusProperty);
|
||||
|
||||
public static readonly DependencyProperty CircularProperty = DependencyProperty.RegisterAttached(
|
||||
"Circular", typeof(bool), typeof(BorderElement), new PropertyMetadata(ValueBoxes.FalseBox, OnCircularChanged));
|
||||
|
||||
private static void OnCircularChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached(
|
||||
"CornerRadius", typeof(CornerRadius), typeof(BorderElement), new FrameworkPropertyMetadata(default(CornerRadius), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetCornerRadius(DependencyObject element, CornerRadius value) => element.SetValue(CornerRadiusProperty, value);
|
||||
|
||||
public static CornerRadius GetCornerRadius(DependencyObject element) => (CornerRadius) element.GetValue(CornerRadiusProperty);
|
||||
|
||||
public static readonly DependencyProperty CircularProperty = DependencyProperty.RegisterAttached(
|
||||
"Circular", typeof(bool), typeof(BorderElement), new PropertyMetadata(ValueBoxes.FalseBox, OnCircularChanged));
|
||||
|
||||
private static void OnCircularChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (d is Border border)
|
||||
{
|
||||
if (d is Border border)
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
if ((bool) e.NewValue)
|
||||
var binding = new MultiBinding
|
||||
{
|
||||
var binding = new MultiBinding
|
||||
{
|
||||
Converter = new BorderCircularConverter()
|
||||
};
|
||||
binding.Bindings.Add(new Binding(FrameworkElement.ActualWidthProperty.Name) { Source = border });
|
||||
binding.Bindings.Add(new Binding(FrameworkElement.ActualHeightProperty.Name) { Source = border });
|
||||
border.SetBinding(Border.CornerRadiusProperty, binding);
|
||||
}
|
||||
else
|
||||
{
|
||||
BindingOperations.ClearBinding(border, FrameworkElement.ActualWidthProperty);
|
||||
BindingOperations.ClearBinding(border, FrameworkElement.ActualHeightProperty);
|
||||
BindingOperations.ClearBinding(border, Border.CornerRadiusProperty);
|
||||
}
|
||||
Converter = new BorderCircularConverter()
|
||||
};
|
||||
binding.Bindings.Add(new Binding(FrameworkElement.ActualWidthProperty.Name) { Source = border });
|
||||
binding.Bindings.Add(new Binding(FrameworkElement.ActualHeightProperty.Name) { Source = border });
|
||||
border.SetBinding(Border.CornerRadiusProperty, binding);
|
||||
}
|
||||
else
|
||||
{
|
||||
BindingOperations.ClearBinding(border, FrameworkElement.ActualWidthProperty);
|
||||
BindingOperations.ClearBinding(border, FrameworkElement.ActualHeightProperty);
|
||||
BindingOperations.ClearBinding(border, Border.CornerRadiusProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCircular(DependencyObject element, bool value)
|
||||
=> element.SetValue(CircularProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetCircular(DependencyObject element)
|
||||
=> (bool) element.GetValue(CircularProperty);
|
||||
}
|
||||
|
||||
public static void SetCircular(DependencyObject element, bool value)
|
||||
=> element.SetValue(CircularProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetCircular(DependencyObject element)
|
||||
=> (bool) element.GetValue(CircularProperty);
|
||||
}
|
||||
@@ -5,345 +5,344 @@ using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class DataGridAttach
|
||||
{
|
||||
public class DataGridAttach
|
||||
public static readonly DependencyProperty ApplyDefaultStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"ApplyDefaultStyle", typeof(bool), typeof(DataGridAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnApplyDefaultStyleChanged));
|
||||
|
||||
private static void OnApplyDefaultStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
public static readonly DependencyProperty ApplyDefaultStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"ApplyDefaultStyle", typeof(bool), typeof(DataGridAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnApplyDefaultStyleChanged));
|
||||
|
||||
private static void OnApplyDefaultStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
var grid = (DataGrid) d;
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
var grid = (DataGrid) d;
|
||||
if ((bool) e.NewValue)
|
||||
if (grid.AutoGenerateColumns)
|
||||
{
|
||||
if (grid.AutoGenerateColumns)
|
||||
{
|
||||
grid.AutoGeneratedColumns += Grid_AutoGeneratedColumns;
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateTextColumnStyles(grid);
|
||||
UpdateComboBoxColumnStyles(grid);
|
||||
UpdateCheckBoxColumnStyles(grid);
|
||||
grid.AutoGeneratedColumns += Grid_AutoGeneratedColumns;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.AutoGeneratedColumns -= Grid_AutoGeneratedColumns;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Grid_AutoGeneratedColumns(object sender, System.EventArgs e)
|
||||
{
|
||||
var grid = (DataGrid) sender;
|
||||
UpdateTextColumnStyles(grid);
|
||||
UpdateComboBoxColumnStyles(grid);
|
||||
UpdateCheckBoxColumnStyles(grid);
|
||||
}
|
||||
|
||||
public static void SetApplyDefaultStyle(DependencyObject element, bool value)
|
||||
=> element.SetValue(ApplyDefaultStyleProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetApplyDefaultStyle(DependencyObject element)
|
||||
=> (bool) element.GetValue(ApplyDefaultStyleProperty);
|
||||
|
||||
public static readonly DependencyProperty TextColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"TextColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnTextColumnStyleChanged));
|
||||
|
||||
private static void OnTextColumnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
else
|
||||
{
|
||||
var grid = (DataGrid) d;
|
||||
if (e.OldValue == null && e.NewValue != null)
|
||||
grid.AutoGeneratedColumns -= Grid_AutoGeneratedColumns;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Grid_AutoGeneratedColumns(object sender, System.EventArgs e)
|
||||
{
|
||||
var grid = (DataGrid) sender;
|
||||
UpdateTextColumnStyles(grid);
|
||||
UpdateComboBoxColumnStyles(grid);
|
||||
UpdateCheckBoxColumnStyles(grid);
|
||||
}
|
||||
|
||||
public static void SetApplyDefaultStyle(DependencyObject element, bool value)
|
||||
=> element.SetValue(ApplyDefaultStyleProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetApplyDefaultStyle(DependencyObject element)
|
||||
=> (bool) element.GetValue(ApplyDefaultStyleProperty);
|
||||
|
||||
public static readonly DependencyProperty TextColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"TextColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnTextColumnStyleChanged));
|
||||
|
||||
private static void OnTextColumnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var grid = (DataGrid) d;
|
||||
if (e.OldValue == null && e.NewValue != null)
|
||||
{
|
||||
UpdateTextColumnStyles(grid);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetTextColumnStyle(DependencyObject element, Style value) => element.SetValue(TextColumnStyleProperty, value);
|
||||
|
||||
public static Style GetTextColumnStyle(DependencyObject element) => (Style) element.GetValue(TextColumnStyleProperty);
|
||||
|
||||
public static readonly DependencyProperty EditingTextColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"EditingTextColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnTextColumnStyleChanged));
|
||||
|
||||
public static void SetEditingTextColumnStyle(DependencyObject element, Style value) => element.SetValue(EditingTextColumnStyleProperty, value);
|
||||
|
||||
public static Style GetEditingTextColumnStyle(DependencyObject element) => (Style) element.GetValue(EditingTextColumnStyleProperty);
|
||||
|
||||
private static void UpdateTextColumnStyles(DataGrid grid)
|
||||
{
|
||||
var textColumnStyle = GetTextColumnStyle(grid);
|
||||
var editingTextColumnStyle = GetEditingTextColumnStyle(grid);
|
||||
|
||||
if (textColumnStyle != null)
|
||||
{
|
||||
foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
|
||||
{
|
||||
UpdateTextColumnStyles(grid);
|
||||
var elementStyle = new Style
|
||||
{
|
||||
BasedOn = column.ElementStyle,
|
||||
TargetType = textColumnStyle.TargetType
|
||||
};
|
||||
|
||||
foreach (var setter in textColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
elementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.ElementStyle = elementStyle;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetTextColumnStyle(DependencyObject element, Style value) => element.SetValue(TextColumnStyleProperty, value);
|
||||
|
||||
public static Style GetTextColumnStyle(DependencyObject element) => (Style) element.GetValue(TextColumnStyleProperty);
|
||||
|
||||
public static readonly DependencyProperty EditingTextColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"EditingTextColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnTextColumnStyleChanged));
|
||||
|
||||
public static void SetEditingTextColumnStyle(DependencyObject element, Style value) => element.SetValue(EditingTextColumnStyleProperty, value);
|
||||
|
||||
public static Style GetEditingTextColumnStyle(DependencyObject element) => (Style) element.GetValue(EditingTextColumnStyleProperty);
|
||||
|
||||
private static void UpdateTextColumnStyles(DataGrid grid)
|
||||
if (editingTextColumnStyle != null)
|
||||
{
|
||||
var textColumnStyle = GetTextColumnStyle(grid);
|
||||
var editingTextColumnStyle = GetEditingTextColumnStyle(grid);
|
||||
|
||||
if (textColumnStyle != null)
|
||||
foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
|
||||
{
|
||||
foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
|
||||
var editingElementStyle = new Style
|
||||
{
|
||||
var elementStyle = new Style
|
||||
{
|
||||
BasedOn = column.ElementStyle,
|
||||
TargetType = textColumnStyle.TargetType
|
||||
};
|
||||
BasedOn = column.EditingElementStyle,
|
||||
TargetType = editingTextColumnStyle.TargetType
|
||||
};
|
||||
|
||||
foreach (var setter in textColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
elementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.ElementStyle = elementStyle;
|
||||
foreach (var setter in editingTextColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
editingElementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.EditingElementStyle = editingElementStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (editingTextColumnStyle != null)
|
||||
public static readonly DependencyProperty ComboBoxColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"ComboBoxColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnComboBoxColumnStyleChanged));
|
||||
|
||||
private static void OnComboBoxColumnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var grid = (DataGrid) d;
|
||||
if (e.OldValue == null && e.NewValue != null)
|
||||
{
|
||||
UpdateComboBoxColumnStyles(grid);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetComboBoxColumnStyle(DependencyObject element, Style value) => element.SetValue(ComboBoxColumnStyleProperty, value);
|
||||
|
||||
public static Style GetComboBoxColumnStyle(DependencyObject element) => (Style) element.GetValue(ComboBoxColumnStyleProperty);
|
||||
|
||||
public static readonly DependencyProperty EditingComboBoxColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"EditingComboBoxColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnComboBoxColumnStyleChanged));
|
||||
|
||||
public static void SetEditingComboBoxColumnStyle(DependencyObject element, Style value) => element.SetValue(EditingComboBoxColumnStyleProperty, value);
|
||||
|
||||
public static Style GetEditingComboBoxColumnStyle(DependencyObject element) => (Style) element.GetValue(EditingComboBoxColumnStyleProperty);
|
||||
|
||||
private static void UpdateComboBoxColumnStyles(DataGrid grid)
|
||||
{
|
||||
var comboBoxColumnStyle = GetComboBoxColumnStyle(grid);
|
||||
var editingComboBoxColumnStyle = GetEditingComboBoxColumnStyle(grid);
|
||||
|
||||
if (comboBoxColumnStyle != null)
|
||||
{
|
||||
foreach (var column in grid.Columns.OfType<DataGridComboBoxColumn>())
|
||||
{
|
||||
foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
|
||||
var elementStyle = new Style
|
||||
{
|
||||
var editingElementStyle = new Style
|
||||
{
|
||||
BasedOn = column.EditingElementStyle,
|
||||
TargetType = editingTextColumnStyle.TargetType
|
||||
};
|
||||
BasedOn = column.ElementStyle,
|
||||
TargetType = comboBoxColumnStyle.TargetType
|
||||
};
|
||||
|
||||
foreach (var setter in editingTextColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
editingElementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.EditingElementStyle = editingElementStyle;
|
||||
foreach (var setter in comboBoxColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
elementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.ElementStyle = elementStyle;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ComboBoxColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"ComboBoxColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnComboBoxColumnStyleChanged));
|
||||
|
||||
private static void OnComboBoxColumnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (editingComboBoxColumnStyle != null)
|
||||
{
|
||||
var grid = (DataGrid) d;
|
||||
if (e.OldValue == null && e.NewValue != null)
|
||||
foreach (var column in grid.Columns.OfType<DataGridComboBoxColumn>())
|
||||
{
|
||||
UpdateComboBoxColumnStyles(grid);
|
||||
var editingElementStyle = new Style
|
||||
{
|
||||
BasedOn = column.EditingElementStyle,
|
||||
TargetType = editingComboBoxColumnStyle.TargetType
|
||||
};
|
||||
|
||||
foreach (var setter in editingComboBoxColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
editingElementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.EditingElementStyle = editingElementStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CheckBoxColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"CheckBoxColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnCheckBoxColumnStyleChanged));
|
||||
|
||||
private static void OnCheckBoxColumnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var grid = (DataGrid) d;
|
||||
if (e.OldValue == null && e.NewValue != null)
|
||||
{
|
||||
UpdateCheckBoxColumnStyles(grid);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCheckBoxColumnStyle(DependencyObject element, Style value) => element.SetValue(CheckBoxColumnStyleProperty, value);
|
||||
|
||||
public static Style GetCheckBoxColumnStyle(DependencyObject element) => (Style) element.GetValue(CheckBoxColumnStyleProperty);
|
||||
|
||||
public static readonly DependencyProperty EditingCheckBoxColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"EditingCheckBoxColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnCheckBoxColumnStyleChanged));
|
||||
|
||||
public static void SetEditingCheckBoxColumnStyle(DependencyObject element, Style value) => element.SetValue(EditingCheckBoxColumnStyleProperty, value);
|
||||
|
||||
public static Style GetEditingCheckBoxColumnStyle(DependencyObject element) => (Style) element.GetValue(EditingCheckBoxColumnStyleProperty);
|
||||
|
||||
private static void UpdateCheckBoxColumnStyles(DataGrid grid)
|
||||
{
|
||||
var checkBoxColumnStyle = GetCheckBoxColumnStyle(grid);
|
||||
var editingCheckBoxColumnStyle = GetEditingCheckBoxColumnStyle(grid);
|
||||
|
||||
if (checkBoxColumnStyle != null)
|
||||
{
|
||||
foreach (var column in grid.Columns.OfType<DataGridCheckBoxColumn>())
|
||||
{
|
||||
var elementStyle = new Style
|
||||
{
|
||||
BasedOn = column.ElementStyle,
|
||||
TargetType = checkBoxColumnStyle.TargetType
|
||||
};
|
||||
|
||||
foreach (var setter in checkBoxColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
elementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.ElementStyle = elementStyle;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetComboBoxColumnStyle(DependencyObject element, Style value) => element.SetValue(ComboBoxColumnStyleProperty, value);
|
||||
|
||||
public static Style GetComboBoxColumnStyle(DependencyObject element) => (Style) element.GetValue(ComboBoxColumnStyleProperty);
|
||||
|
||||
public static readonly DependencyProperty EditingComboBoxColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"EditingComboBoxColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnComboBoxColumnStyleChanged));
|
||||
|
||||
public static void SetEditingComboBoxColumnStyle(DependencyObject element, Style value) => element.SetValue(EditingComboBoxColumnStyleProperty, value);
|
||||
|
||||
public static Style GetEditingComboBoxColumnStyle(DependencyObject element) => (Style) element.GetValue(EditingComboBoxColumnStyleProperty);
|
||||
|
||||
private static void UpdateComboBoxColumnStyles(DataGrid grid)
|
||||
if (editingCheckBoxColumnStyle != null)
|
||||
{
|
||||
var comboBoxColumnStyle = GetComboBoxColumnStyle(grid);
|
||||
var editingComboBoxColumnStyle = GetEditingComboBoxColumnStyle(grid);
|
||||
|
||||
if (comboBoxColumnStyle != null)
|
||||
foreach (var column in grid.Columns.OfType<DataGridCheckBoxColumn>())
|
||||
{
|
||||
foreach (var column in grid.Columns.OfType<DataGridComboBoxColumn>())
|
||||
var editingElementStyle = new Style
|
||||
{
|
||||
var elementStyle = new Style
|
||||
{
|
||||
BasedOn = column.ElementStyle,
|
||||
TargetType = comboBoxColumnStyle.TargetType
|
||||
};
|
||||
BasedOn = column.EditingElementStyle,
|
||||
TargetType = editingCheckBoxColumnStyle.TargetType
|
||||
};
|
||||
|
||||
foreach (var setter in comboBoxColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
elementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.ElementStyle = elementStyle;
|
||||
}
|
||||
}
|
||||
|
||||
if (editingComboBoxColumnStyle != null)
|
||||
{
|
||||
foreach (var column in grid.Columns.OfType<DataGridComboBoxColumn>())
|
||||
foreach (var setter in editingCheckBoxColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
var editingElementStyle = new Style
|
||||
{
|
||||
BasedOn = column.EditingElementStyle,
|
||||
TargetType = editingComboBoxColumnStyle.TargetType
|
||||
};
|
||||
|
||||
foreach (var setter in editingComboBoxColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
editingElementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.EditingElementStyle = editingElementStyle;
|
||||
editingElementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.EditingElementStyle = editingElementStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CheckBoxColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"CheckBoxColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnCheckBoxColumnStyleChanged));
|
||||
public static DependencyProperty ShowRowNumberProperty = DependencyProperty.RegisterAttached("ShowRowNumber",
|
||||
typeof(bool), typeof(DataGridAttach),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits, OnShowRowNumberChanged));
|
||||
|
||||
private static void OnCheckBoxColumnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
public static bool GetShowRowNumber(DependencyObject target) => (bool) target.GetValue(ShowRowNumberProperty);
|
||||
|
||||
public static void SetShowRowNumber(DependencyObject target, bool value) => target.SetValue(ShowRowNumberProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
private static void OnShowRowNumberChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (target is not DataGrid dataGrid) return;
|
||||
var show = (bool) e.NewValue;
|
||||
|
||||
if (show)
|
||||
{
|
||||
var grid = (DataGrid) d;
|
||||
if (e.OldValue == null && e.NewValue != null)
|
||||
{
|
||||
UpdateCheckBoxColumnStyles(grid);
|
||||
}
|
||||
dataGrid.LoadingRow += DataGrid_LoadingRow;
|
||||
dataGrid.ItemContainerGenerator.ItemsChanged += ItemContainerGeneratorItemsChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
dataGrid.LoadingRow -= DataGrid_LoadingRow;
|
||||
dataGrid.ItemContainerGenerator.ItemsChanged -= ItemContainerGeneratorItemsChanged;
|
||||
}
|
||||
|
||||
public static void SetCheckBoxColumnStyle(DependencyObject element, Style value) => element.SetValue(CheckBoxColumnStyleProperty, value);
|
||||
|
||||
public static Style GetCheckBoxColumnStyle(DependencyObject element) => (Style) element.GetValue(CheckBoxColumnStyleProperty);
|
||||
|
||||
public static readonly DependencyProperty EditingCheckBoxColumnStyleProperty = DependencyProperty.RegisterAttached(
|
||||
"EditingCheckBoxColumnStyle", typeof(Style), typeof(DataGridAttach), new PropertyMetadata(default(Style), OnCheckBoxColumnStyleChanged));
|
||||
|
||||
public static void SetEditingCheckBoxColumnStyle(DependencyObject element, Style value) => element.SetValue(EditingCheckBoxColumnStyleProperty, value);
|
||||
|
||||
public static Style GetEditingCheckBoxColumnStyle(DependencyObject element) => (Style) element.GetValue(EditingCheckBoxColumnStyleProperty);
|
||||
|
||||
private static void UpdateCheckBoxColumnStyles(DataGrid grid)
|
||||
void ItemContainerGeneratorItemsChanged(object sender, ItemsChangedEventArgs e)
|
||||
{
|
||||
var checkBoxColumnStyle = GetCheckBoxColumnStyle(grid);
|
||||
var editingCheckBoxColumnStyle = GetEditingCheckBoxColumnStyle(grid);
|
||||
|
||||
if (checkBoxColumnStyle != null)
|
||||
{
|
||||
foreach (var column in grid.Columns.OfType<DataGridCheckBoxColumn>())
|
||||
{
|
||||
var elementStyle = new Style
|
||||
{
|
||||
BasedOn = column.ElementStyle,
|
||||
TargetType = checkBoxColumnStyle.TargetType
|
||||
};
|
||||
|
||||
foreach (var setter in checkBoxColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
elementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.ElementStyle = elementStyle;
|
||||
}
|
||||
}
|
||||
|
||||
if (editingCheckBoxColumnStyle != null)
|
||||
{
|
||||
foreach (var column in grid.Columns.OfType<DataGridCheckBoxColumn>())
|
||||
{
|
||||
var editingElementStyle = new Style
|
||||
{
|
||||
BasedOn = column.EditingElementStyle,
|
||||
TargetType = editingCheckBoxColumnStyle.TargetType
|
||||
};
|
||||
|
||||
foreach (var setter in editingCheckBoxColumnStyle.Setters.OfType<Setter>())
|
||||
{
|
||||
editingElementStyle.Setters.Add(setter);
|
||||
}
|
||||
|
||||
column.EditingElementStyle = editingElementStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static DependencyProperty ShowRowNumberProperty = DependencyProperty.RegisterAttached("ShowRowNumber",
|
||||
typeof(bool), typeof(DataGridAttach),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits, OnShowRowNumberChanged));
|
||||
|
||||
public static bool GetShowRowNumber(DependencyObject target) => (bool) target.GetValue(ShowRowNumberProperty);
|
||||
|
||||
public static void SetShowRowNumber(DependencyObject target, bool value) => target.SetValue(ShowRowNumberProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
private static void OnShowRowNumberChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (target is not DataGrid dataGrid) return;
|
||||
var show = (bool) e.NewValue;
|
||||
var generator = dataGrid.ItemContainerGenerator;
|
||||
var itemsCount = dataGrid.Items.Count;
|
||||
|
||||
if (show)
|
||||
{
|
||||
dataGrid.LoadingRow += DataGrid_LoadingRow;
|
||||
dataGrid.ItemContainerGenerator.ItemsChanged += ItemContainerGeneratorItemsChanged;
|
||||
for (var i = 0; i < itemsCount; i++)
|
||||
{
|
||||
var row = (DataGridRow) generator.ContainerFromIndex(i);
|
||||
if (row != null)
|
||||
{
|
||||
row.Header = (i + 1).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataGrid.LoadingRow -= DataGrid_LoadingRow;
|
||||
dataGrid.ItemContainerGenerator.ItemsChanged -= ItemContainerGeneratorItemsChanged;
|
||||
}
|
||||
|
||||
void ItemContainerGeneratorItemsChanged(object sender, ItemsChangedEventArgs e)
|
||||
{
|
||||
var generator = dataGrid.ItemContainerGenerator;
|
||||
var itemsCount = dataGrid.Items.Count;
|
||||
|
||||
if (show)
|
||||
for (var i = 0; i < itemsCount; i++)
|
||||
{
|
||||
for (var i = 0; i < itemsCount; i++)
|
||||
var row = (DataGridRow) generator.ContainerFromIndex(i);
|
||||
if (row != null)
|
||||
{
|
||||
var row = (DataGridRow) generator.ContainerFromIndex(i);
|
||||
if (row != null)
|
||||
{
|
||||
row.Header = (i + 1).ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < itemsCount; i++)
|
||||
{
|
||||
var row = (DataGridRow) generator.ContainerFromIndex(i);
|
||||
if (row != null)
|
||||
{
|
||||
row.Header = null;
|
||||
}
|
||||
row.Header = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e) => e.Row.Header = (e.Row.GetIndex() + 1).ToString();
|
||||
|
||||
public static readonly DependencyProperty CanUnselectAllWithBlankAreaProperty = DependencyProperty.RegisterAttached(
|
||||
"CanUnselectAllWithBlankArea", typeof(bool), typeof(DataGridAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnCanUnselectAllWithBlankAreaChanged));
|
||||
|
||||
private static void OnCanUnselectAllWithBlankAreaChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is DataGrid dataGrid)
|
||||
{
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
dataGrid.PreviewMouseDown += DataGrid_PreviewMouseDown;
|
||||
}
|
||||
else
|
||||
{
|
||||
dataGrid.PreviewMouseDown -= DataGrid_PreviewMouseDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DataGrid_PreviewMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is DataGrid dataGrid && e.OriginalSource is System.Windows.Controls.ScrollViewer)
|
||||
{
|
||||
dataGrid.CommitEdit();
|
||||
dataGrid.UnselectAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCanUnselectAllWithBlankArea(DependencyObject element, bool value)
|
||||
=> element.SetValue(CanUnselectAllWithBlankAreaProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetCanUnselectAllWithBlankArea(DependencyObject element)
|
||||
=> (bool) element.GetValue(CanUnselectAllWithBlankAreaProperty);
|
||||
|
||||
public static readonly DependencyProperty ShowSelectAllButtonProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowSelectAllButton", typeof(bool), typeof(DataGridAttach), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public static void SetShowSelectAllButton(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowSelectAllButtonProperty, value);
|
||||
|
||||
public static bool GetShowSelectAllButton(DependencyObject element)
|
||||
=> (bool) element.GetValue(ShowSelectAllButtonProperty);
|
||||
}
|
||||
|
||||
private static void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e) => e.Row.Header = (e.Row.GetIndex() + 1).ToString();
|
||||
|
||||
public static readonly DependencyProperty CanUnselectAllWithBlankAreaProperty = DependencyProperty.RegisterAttached(
|
||||
"CanUnselectAllWithBlankArea", typeof(bool), typeof(DataGridAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnCanUnselectAllWithBlankAreaChanged));
|
||||
|
||||
private static void OnCanUnselectAllWithBlankAreaChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is DataGrid dataGrid)
|
||||
{
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
dataGrid.PreviewMouseDown += DataGrid_PreviewMouseDown;
|
||||
}
|
||||
else
|
||||
{
|
||||
dataGrid.PreviewMouseDown -= DataGrid_PreviewMouseDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DataGrid_PreviewMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is DataGrid dataGrid && e.OriginalSource is System.Windows.Controls.ScrollViewer)
|
||||
{
|
||||
dataGrid.CommitEdit();
|
||||
dataGrid.UnselectAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCanUnselectAllWithBlankArea(DependencyObject element, bool value)
|
||||
=> element.SetValue(CanUnselectAllWithBlankAreaProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetCanUnselectAllWithBlankArea(DependencyObject element)
|
||||
=> (bool) element.GetValue(CanUnselectAllWithBlankAreaProperty);
|
||||
|
||||
public static readonly DependencyProperty ShowSelectAllButtonProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowSelectAllButton", typeof(bool), typeof(DataGridAttach), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public static void SetShowSelectAllButton(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowSelectAllButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetShowSelectAllButton(DependencyObject element)
|
||||
=> (bool) element.GetValue(ShowSelectAllButtonProperty);
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class DropDownElement
|
||||
{
|
||||
public class DropDownElement
|
||||
{
|
||||
public static readonly DependencyProperty ConsistentWidthProperty = DependencyProperty.RegisterAttached(
|
||||
"ConsistentWidth", typeof(bool), typeof(DropDownElement),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty ConsistentWidthProperty = DependencyProperty.RegisterAttached(
|
||||
"ConsistentWidth", typeof(bool), typeof(DropDownElement),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetConsistentWidth(DependencyObject element, bool value)
|
||||
=> element.SetValue(ConsistentWidthProperty, ValueBoxes.BooleanBox(value));
|
||||
public static void SetConsistentWidth(DependencyObject element, bool value)
|
||||
=> element.SetValue(ConsistentWidthProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetConsistentWidth(DependencyObject element)
|
||||
=> (bool) element.GetValue(ConsistentWidthProperty);
|
||||
public static bool GetConsistentWidth(DependencyObject element)
|
||||
=> (bool) element.GetValue(ConsistentWidthProperty);
|
||||
|
||||
public static readonly DependencyProperty AutoWidthProperty = DependencyProperty.RegisterAttached(
|
||||
"AutoWidth", typeof(bool), typeof(DropDownElement),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty AutoWidthProperty = DependencyProperty.RegisterAttached(
|
||||
"AutoWidth", typeof(bool), typeof(DropDownElement),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetAutoWidth(DependencyObject element, bool value)
|
||||
=> element.SetValue(AutoWidthProperty, ValueBoxes.BooleanBox(value));
|
||||
public static void SetAutoWidth(DependencyObject element, bool value)
|
||||
=> element.SetValue(AutoWidthProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetAutoWidth(DependencyObject element)
|
||||
=> (bool) element.GetValue(AutoWidthProperty);
|
||||
}
|
||||
public static bool GetAutoWidth(DependencyObject element)
|
||||
=> (bool) element.GetValue(AutoWidthProperty);
|
||||
}
|
||||
@@ -1,47 +1,46 @@
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class EdgeElement
|
||||
{
|
||||
public class EdgeElement
|
||||
{
|
||||
public static readonly DependencyProperty LeftContentProperty = DependencyProperty.RegisterAttached(
|
||||
"LeftContent", typeof(object), typeof(EdgeElement), new PropertyMetadata(default(object), OnEdgeContentChanged));
|
||||
public static readonly DependencyProperty LeftContentProperty = DependencyProperty.RegisterAttached(
|
||||
"LeftContent", typeof(object), typeof(EdgeElement), new PropertyMetadata(default(object), OnEdgeContentChanged));
|
||||
|
||||
public static void SetLeftContent(DependencyObject element, object value) => element.SetValue(LeftContentProperty, value);
|
||||
public static void SetLeftContent(DependencyObject element, object value) => element.SetValue(LeftContentProperty, value);
|
||||
|
||||
public static object GetLeftContent(DependencyObject element) => element.GetValue(LeftContentProperty);
|
||||
public static object GetLeftContent(DependencyObject element) => element.GetValue(LeftContentProperty);
|
||||
|
||||
public static readonly DependencyProperty TopContentProperty = DependencyProperty.RegisterAttached(
|
||||
"TopContent", typeof(object), typeof(EdgeElement), new PropertyMetadata(default(object), OnEdgeContentChanged));
|
||||
public static readonly DependencyProperty TopContentProperty = DependencyProperty.RegisterAttached(
|
||||
"TopContent", typeof(object), typeof(EdgeElement), new PropertyMetadata(default(object), OnEdgeContentChanged));
|
||||
|
||||
public static void SetTopContent(DependencyObject element, object value) => element.SetValue(TopContentProperty, value);
|
||||
public static void SetTopContent(DependencyObject element, object value) => element.SetValue(TopContentProperty, value);
|
||||
|
||||
public static object GetTopContent(DependencyObject element) => element.GetValue(TopContentProperty);
|
||||
public static object GetTopContent(DependencyObject element) => element.GetValue(TopContentProperty);
|
||||
|
||||
public static readonly DependencyProperty RightContentProperty = DependencyProperty.RegisterAttached(
|
||||
"RightContent", typeof(object), typeof(EdgeElement), new PropertyMetadata(default(object), OnEdgeContentChanged));
|
||||
public static readonly DependencyProperty RightContentProperty = DependencyProperty.RegisterAttached(
|
||||
"RightContent", typeof(object), typeof(EdgeElement), new PropertyMetadata(default(object), OnEdgeContentChanged));
|
||||
|
||||
public static void SetRightContent(DependencyObject element, object value) => element.SetValue(RightContentProperty, value);
|
||||
public static void SetRightContent(DependencyObject element, object value) => element.SetValue(RightContentProperty, value);
|
||||
|
||||
public static object GetRightContent(DependencyObject element) => element.GetValue(RightContentProperty);
|
||||
public static object GetRightContent(DependencyObject element) => element.GetValue(RightContentProperty);
|
||||
|
||||
public static readonly DependencyProperty BottomContentProperty = DependencyProperty.RegisterAttached(
|
||||
"BottomContent", typeof(object), typeof(EdgeElement), new PropertyMetadata(default(object), OnEdgeContentChanged));
|
||||
public static readonly DependencyProperty BottomContentProperty = DependencyProperty.RegisterAttached(
|
||||
"BottomContent", typeof(object), typeof(EdgeElement), new PropertyMetadata(default(object), OnEdgeContentChanged));
|
||||
|
||||
public static void SetBottomContent(DependencyObject element, object value) => element.SetValue(BottomContentProperty, value);
|
||||
public static void SetBottomContent(DependencyObject element, object value) => element.SetValue(BottomContentProperty, value);
|
||||
|
||||
public static object GetBottomContent(DependencyObject element) => element.GetValue(BottomContentProperty);
|
||||
public static object GetBottomContent(DependencyObject element) => element.GetValue(BottomContentProperty);
|
||||
|
||||
public static readonly DependencyProperty ShowEdgeContentProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowEdgeContent", typeof(bool), typeof(EdgeElement), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
public static readonly DependencyProperty ShowEdgeContentProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowEdgeContent", typeof(bool), typeof(EdgeElement), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static void SetShowEdgeContent(DependencyObject element, bool value) => element.SetValue(ShowEdgeContentProperty, ValueBoxes.BooleanBox(value));
|
||||
public static void SetShowEdgeContent(DependencyObject element, bool value) => element.SetValue(ShowEdgeContentProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetShowEdgeContent(DependencyObject element) => (bool) element.GetValue(ShowEdgeContentProperty);
|
||||
public static bool GetShowEdgeContent(DependencyObject element) => (bool) element.GetValue(ShowEdgeContentProperty);
|
||||
|
||||
private static void OnEdgeContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
|
||||
SetShowEdgeContent(d, !(GetLeftContent(d) == null && GetTopContent(d) == null &&
|
||||
GetRightContent(d) == null && GetBottomContent(d) == null));
|
||||
}
|
||||
private static void OnEdgeContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
|
||||
SetShowEdgeContent(d, !(GetLeftContent(d) == null && GetTopContent(d) == null &&
|
||||
GetRightContent(d) == null && GetBottomContent(d) == null));
|
||||
}
|
||||
@@ -2,95 +2,94 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class GridAttach
|
||||
{
|
||||
public class GridAttach
|
||||
public static readonly DependencyProperty NameProperty = DependencyProperty.RegisterAttached(
|
||||
"Name", typeof(string), typeof(GridAttach), new PropertyMetadata(default(string)));
|
||||
|
||||
public static void SetName(DependencyObject element, string value)
|
||||
=> element.SetValue(NameProperty, value);
|
||||
|
||||
public static string GetName(DependencyObject element)
|
||||
=> (string) element.GetValue(NameProperty);
|
||||
|
||||
public static readonly DependencyProperty RowNameProperty = DependencyProperty.RegisterAttached(
|
||||
"RowName", typeof(string), typeof(GridAttach), new PropertyMetadata(default(string), OnRowNameChanged));
|
||||
|
||||
private static void OnRowNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
public static readonly DependencyProperty NameProperty = DependencyProperty.RegisterAttached(
|
||||
"Name", typeof(string), typeof(GridAttach), new PropertyMetadata(default(string)));
|
||||
|
||||
public static void SetName(DependencyObject element, string value)
|
||||
=> element.SetValue(NameProperty, value);
|
||||
|
||||
public static string GetName(DependencyObject element)
|
||||
=> (string) element.GetValue(NameProperty);
|
||||
|
||||
public static readonly DependencyProperty RowNameProperty = DependencyProperty.RegisterAttached(
|
||||
"RowName", typeof(string), typeof(GridAttach), new PropertyMetadata(default(string), OnRowNameChanged));
|
||||
|
||||
private static void OnRowNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (d is FrameworkElement frameworkElement)
|
||||
{
|
||||
if (d is FrameworkElement frameworkElement)
|
||||
if (e.NewValue is string rowName)
|
||||
{
|
||||
if (e.NewValue is string rowName)
|
||||
if (string.IsNullOrEmpty(rowName))
|
||||
{
|
||||
if (string.IsNullOrEmpty(rowName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (frameworkElement.Parent is Grid grid)
|
||||
if (frameworkElement.Parent is Grid grid)
|
||||
{
|
||||
for (var i = 0; i < grid.RowDefinitions.Count; i++)
|
||||
{
|
||||
for (var i = 0; i < grid.RowDefinitions.Count; i++)
|
||||
var gridRowDefinition = grid.RowDefinitions[i];
|
||||
var gridRowName = GetName(gridRowDefinition);
|
||||
|
||||
if (!string.IsNullOrEmpty(gridRowName) &&
|
||||
gridRowName.Equals(rowName, StringComparison.Ordinal))
|
||||
{
|
||||
var gridRowDefinition = grid.RowDefinitions[i];
|
||||
var gridRowName = GetName(gridRowDefinition);
|
||||
|
||||
if (!string.IsNullOrEmpty(gridRowName) &&
|
||||
gridRowName.Equals(rowName, StringComparison.Ordinal))
|
||||
{
|
||||
Grid.SetRow(frameworkElement, i);
|
||||
return;
|
||||
}
|
||||
Grid.SetRow(frameworkElement, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetRowName(DependencyObject element, string value)
|
||||
=> element.SetValue(RowNameProperty, value);
|
||||
|
||||
public static string GetRowName(DependencyObject element)
|
||||
=> (string) element.GetValue(RowNameProperty);
|
||||
|
||||
public static readonly DependencyProperty ColumnNameProperty = DependencyProperty.RegisterAttached(
|
||||
"ColumnName", typeof(string), typeof(GridAttach), new PropertyMetadata(default(string), OnColumnNameChanged));
|
||||
|
||||
private static void OnColumnNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is FrameworkElement frameworkElement)
|
||||
{
|
||||
if (e.NewValue is string columnName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(columnName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (frameworkElement.Parent is Grid grid)
|
||||
{
|
||||
for (var i = 0; i < grid.ColumnDefinitions.Count; i++)
|
||||
{
|
||||
var gridColumnDefinition = grid.ColumnDefinitions[i];
|
||||
var gridColumnName = GetName(gridColumnDefinition);
|
||||
|
||||
if (!string.IsNullOrEmpty(gridColumnName) &&
|
||||
gridColumnName.Equals(columnName, StringComparison.Ordinal))
|
||||
{
|
||||
Grid.SetColumn(frameworkElement, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetColumnName(DependencyObject element, string value)
|
||||
=> element.SetValue(ColumnNameProperty, value);
|
||||
|
||||
public static string GetColumnName(DependencyObject element)
|
||||
=> (string) element.GetValue(ColumnNameProperty);
|
||||
}
|
||||
|
||||
public static void SetRowName(DependencyObject element, string value)
|
||||
=> element.SetValue(RowNameProperty, value);
|
||||
|
||||
public static string GetRowName(DependencyObject element)
|
||||
=> (string) element.GetValue(RowNameProperty);
|
||||
|
||||
public static readonly DependencyProperty ColumnNameProperty = DependencyProperty.RegisterAttached(
|
||||
"ColumnName", typeof(string), typeof(GridAttach), new PropertyMetadata(default(string), OnColumnNameChanged));
|
||||
|
||||
private static void OnColumnNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is FrameworkElement frameworkElement)
|
||||
{
|
||||
if (e.NewValue is string columnName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(columnName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (frameworkElement.Parent is Grid grid)
|
||||
{
|
||||
for (var i = 0; i < grid.ColumnDefinitions.Count; i++)
|
||||
{
|
||||
var gridColumnDefinition = grid.ColumnDefinitions[i];
|
||||
var gridColumnName = GetName(gridColumnDefinition);
|
||||
|
||||
if (!string.IsNullOrEmpty(gridColumnName) &&
|
||||
gridColumnName.Equals(columnName, StringComparison.Ordinal))
|
||||
{
|
||||
Grid.SetColumn(frameworkElement, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetColumnName(DependencyObject element, string value)
|
||||
=> element.SetValue(ColumnNameProperty, value);
|
||||
|
||||
public static string GetColumnName(DependencyObject element)
|
||||
=> (string) element.GetValue(ColumnNameProperty);
|
||||
}
|
||||
@@ -1,35 +1,34 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class IconElement
|
||||
{
|
||||
public class IconElement
|
||||
{
|
||||
public static readonly DependencyProperty GeometryProperty = DependencyProperty.RegisterAttached(
|
||||
"Geometry", typeof(Geometry), typeof(IconElement), new PropertyMetadata(default(Geometry)));
|
||||
public static readonly DependencyProperty GeometryProperty = DependencyProperty.RegisterAttached(
|
||||
"Geometry", typeof(Geometry), typeof(IconElement), new PropertyMetadata(default(Geometry)));
|
||||
|
||||
public static void SetGeometry(DependencyObject element, Geometry value)
|
||||
=> element.SetValue(GeometryProperty, value);
|
||||
public static void SetGeometry(DependencyObject element, Geometry value)
|
||||
=> element.SetValue(GeometryProperty, value);
|
||||
|
||||
public static Geometry GetGeometry(DependencyObject element)
|
||||
=> (Geometry) element.GetValue(GeometryProperty);
|
||||
public static Geometry GetGeometry(DependencyObject element)
|
||||
=> (Geometry) element.GetValue(GeometryProperty);
|
||||
|
||||
public static readonly DependencyProperty WidthProperty = DependencyProperty.RegisterAttached(
|
||||
"Width", typeof(double), typeof(IconElement), new PropertyMetadata(double.NaN));
|
||||
public static readonly DependencyProperty WidthProperty = DependencyProperty.RegisterAttached(
|
||||
"Width", typeof(double), typeof(IconElement), new PropertyMetadata(double.NaN));
|
||||
|
||||
public static void SetWidth(DependencyObject element, double value)
|
||||
=> element.SetValue(WidthProperty, value);
|
||||
public static void SetWidth(DependencyObject element, double value)
|
||||
=> element.SetValue(WidthProperty, value);
|
||||
|
||||
public static double GetWidth(DependencyObject element)
|
||||
=> (double) element.GetValue(WidthProperty);
|
||||
public static double GetWidth(DependencyObject element)
|
||||
=> (double) element.GetValue(WidthProperty);
|
||||
|
||||
public static readonly DependencyProperty HeightProperty = DependencyProperty.RegisterAttached(
|
||||
"Height", typeof(double), typeof(IconElement), new PropertyMetadata(double.NaN));
|
||||
public static readonly DependencyProperty HeightProperty = DependencyProperty.RegisterAttached(
|
||||
"Height", typeof(double), typeof(IconElement), new PropertyMetadata(double.NaN));
|
||||
|
||||
public static void SetHeight(DependencyObject element, double value)
|
||||
=> element.SetValue(HeightProperty, value);
|
||||
public static void SetHeight(DependencyObject element, double value)
|
||||
=> element.SetValue(HeightProperty, value);
|
||||
|
||||
public static double GetHeight(DependencyObject element)
|
||||
=> (double) element.GetValue(HeightProperty);
|
||||
}
|
||||
public static double GetHeight(DependencyObject element)
|
||||
=> (double) element.GetValue(HeightProperty);
|
||||
}
|
||||
@@ -1,21 +1,20 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class IconSwitchElement : IconElement
|
||||
{
|
||||
public class IconSwitchElement : IconElement
|
||||
public static readonly DependencyProperty GeometrySelectedProperty = DependencyProperty.RegisterAttached(
|
||||
"GeometrySelected", typeof(Geometry), typeof(IconSwitchElement), new PropertyMetadata(default(Geometry)));
|
||||
|
||||
public static void SetGeometrySelected(DependencyObject element, Geometry value)
|
||||
{
|
||||
public static readonly DependencyProperty GeometrySelectedProperty = DependencyProperty.RegisterAttached(
|
||||
"GeometrySelected", typeof(Geometry), typeof(IconSwitchElement), new PropertyMetadata(default(Geometry)));
|
||||
element.SetValue(GeometrySelectedProperty, value);
|
||||
}
|
||||
|
||||
public static void SetGeometrySelected(DependencyObject element, Geometry value)
|
||||
{
|
||||
element.SetValue(GeometrySelectedProperty, value);
|
||||
}
|
||||
|
||||
public static Geometry GetGeometrySelected(DependencyObject element)
|
||||
{
|
||||
return (Geometry) element.GetValue(GeometrySelectedProperty);
|
||||
}
|
||||
public static Geometry GetGeometrySelected(DependencyObject element)
|
||||
{
|
||||
return (Geometry) element.GetValue(GeometrySelectedProperty);
|
||||
}
|
||||
}
|
||||
@@ -2,41 +2,40 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ImageAttach
|
||||
{
|
||||
public class ImageAttach
|
||||
public static readonly DependencyProperty SourceFailedProperty = DependencyProperty.RegisterAttached(
|
||||
"SourceFailed", typeof(ImageSource), typeof(ImageAttach), new FrameworkPropertyMetadata(default(ImageSource), FrameworkPropertyMetadataOptions.Inherits, OnSourceFailedChanged));
|
||||
|
||||
private static void OnSourceFailedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
public static readonly DependencyProperty SourceFailedProperty = DependencyProperty.RegisterAttached(
|
||||
"SourceFailed", typeof(ImageSource), typeof(ImageAttach), new FrameworkPropertyMetadata(default(ImageSource), FrameworkPropertyMetadataOptions.Inherits, OnSourceFailedChanged));
|
||||
|
||||
private static void OnSourceFailedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (d is Image image)
|
||||
{
|
||||
if (d is Image image)
|
||||
if (e.NewValue is ImageSource)
|
||||
{
|
||||
if (e.NewValue is ImageSource)
|
||||
{
|
||||
image.ImageFailed += Image_ImageFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
image.ImageFailed -= Image_ImageFailed;
|
||||
}
|
||||
image.ImageFailed += Image_ImageFailed;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Image_ImageFailed(object sender, ExceptionRoutedEventArgs e)
|
||||
{
|
||||
if (sender is Image image)
|
||||
else
|
||||
{
|
||||
image.SetCurrentValue(Image.SourceProperty, GetSourceFailed(image));
|
||||
image.ImageFailed -= Image_ImageFailed;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetSourceFailed(DependencyObject element, ImageSource value)
|
||||
=> element.SetValue(SourceFailedProperty, value);
|
||||
|
||||
public static ImageSource GetSourceFailed(DependencyObject element)
|
||||
=> (ImageSource) element.GetValue(SourceFailedProperty);
|
||||
}
|
||||
|
||||
private static void Image_ImageFailed(object sender, ExceptionRoutedEventArgs e)
|
||||
{
|
||||
if (sender is Image image)
|
||||
{
|
||||
image.SetCurrentValue(Image.SourceProperty, GetSourceFailed(image));
|
||||
image.ImageFailed -= Image_ImageFailed;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetSourceFailed(DependencyObject element, ImageSource value)
|
||||
=> element.SetValue(SourceFailedProperty, value);
|
||||
|
||||
public static ImageSource GetSourceFailed(DependencyObject element)
|
||||
=> (ImageSource) element.GetValue(SourceFailedProperty);
|
||||
}
|
||||
@@ -1,84 +1,92 @@
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class InfoElement : TitleElement
|
||||
{
|
||||
public class InfoElement : TitleElement
|
||||
{
|
||||
/// <summary>
|
||||
/// 占位符
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.RegisterAttached(
|
||||
"Placeholder", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.Inherits));
|
||||
/// <summary>
|
||||
/// 占位符
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.RegisterAttached(
|
||||
"Placeholder", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetPlaceholder(DependencyObject element, string value) => element.SetValue(PlaceholderProperty, value);
|
||||
public static void SetPlaceholder(DependencyObject element, string value) => element.SetValue(PlaceholderProperty, value);
|
||||
|
||||
public static string GetPlaceholder(DependencyObject element) => (string) element.GetValue(PlaceholderProperty);
|
||||
public static string GetPlaceholder(DependencyObject element) => (string) element.GetValue(PlaceholderProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 是否必填
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty NecessaryProperty = DependencyProperty.RegisterAttached(
|
||||
"Necessary", typeof(bool), typeof(InfoElement), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
/// <summary>
|
||||
/// 是否必填
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty NecessaryProperty = DependencyProperty.RegisterAttached(
|
||||
"Necessary", typeof(bool), typeof(InfoElement), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetNecessary(DependencyObject element, bool value) => element.SetValue(NecessaryProperty, ValueBoxes.BooleanBox(value));
|
||||
public static void SetNecessary(DependencyObject element, bool value) => element.SetValue(NecessaryProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetNecessary(DependencyObject element) => (bool) element.GetValue(NecessaryProperty);
|
||||
public static bool GetNecessary(DependencyObject element) => (bool) element.GetValue(NecessaryProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 标记
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SymbolProperty = DependencyProperty.RegisterAttached(
|
||||
"Symbol", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.Inherits));
|
||||
/// <summary>
|
||||
/// 标记
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SymbolProperty = DependencyProperty.RegisterAttached(
|
||||
"Symbol", typeof(string), typeof(InfoElement), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetSymbol(DependencyObject element, string value) => element.SetValue(SymbolProperty, value);
|
||||
public static void SetSymbol(DependencyObject element, string value) => element.SetValue(SymbolProperty, value);
|
||||
|
||||
public static string GetSymbol(DependencyObject element) => (string) element.GetValue(SymbolProperty);
|
||||
public static string GetSymbol(DependencyObject element) => (string) element.GetValue(SymbolProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 内容高度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.RegisterAttached(
|
||||
"ContentHeight", typeof(double), typeof(InfoElement), new FrameworkPropertyMetadata(30.0, FrameworkPropertyMetadataOptions.Inherits));
|
||||
/// <summary>
|
||||
/// 内容高度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.RegisterAttached(
|
||||
"ContentHeight", typeof(double), typeof(InfoElement), new FrameworkPropertyMetadata(30.0, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetContentHeight(DependencyObject element, double value) => element.SetValue(ContentHeightProperty, value);
|
||||
public static void SetContentHeight(DependencyObject element, double value) => element.SetValue(ContentHeightProperty, value);
|
||||
|
||||
public static double GetContentHeight(DependencyObject element) => (double) element.GetValue(ContentHeightProperty);
|
||||
public static double GetContentHeight(DependencyObject element) => (double) element.GetValue(ContentHeightProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 最小内容高度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MinContentHeightProperty = DependencyProperty.RegisterAttached(
|
||||
"MinContentHeight", typeof(double), typeof(InfoElement), new PropertyMetadata(30.0));
|
||||
/// <summary>
|
||||
/// 最小内容高度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MinContentHeightProperty = DependencyProperty.RegisterAttached(
|
||||
"MinContentHeight", typeof(double), typeof(InfoElement), new PropertyMetadata(30.0));
|
||||
|
||||
public static void SetMinContentHeight(DependencyObject element, double value)
|
||||
=> element.SetValue(MinContentHeightProperty, value);
|
||||
public static void SetMinContentHeight(DependencyObject element, double value)
|
||||
=> element.SetValue(MinContentHeightProperty, value);
|
||||
|
||||
public static double GetMinContentHeight(DependencyObject element)
|
||||
=> (double) element.GetValue(MinContentHeightProperty);
|
||||
public static double GetMinContentHeight(DependencyObject element)
|
||||
=> (double) element.GetValue(MinContentHeightProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 最大内容高度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxContentHeightProperty = DependencyProperty.RegisterAttached(
|
||||
"MaxContentHeight", typeof(double), typeof(InfoElement), new PropertyMetadata(double.PositiveInfinity));
|
||||
/// <summary>
|
||||
/// 最大内容高度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxContentHeightProperty = DependencyProperty.RegisterAttached(
|
||||
"MaxContentHeight", typeof(double), typeof(InfoElement), new PropertyMetadata(double.PositiveInfinity));
|
||||
|
||||
public static void SetMaxContentHeight(DependencyObject element, double value)
|
||||
=> element.SetValue(MaxContentHeightProperty, value);
|
||||
public static void SetMaxContentHeight(DependencyObject element, double value)
|
||||
=> element.SetValue(MaxContentHeightProperty, value);
|
||||
|
||||
public static double GetMaxContentHeight(DependencyObject element)
|
||||
=> (double) element.GetValue(MaxContentHeightProperty);
|
||||
public static double GetMaxContentHeight(DependencyObject element)
|
||||
=> (double) element.GetValue(MaxContentHeightProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 正则表达式
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty RegexPatternProperty = DependencyProperty.RegisterAttached(
|
||||
"RegexPattern", typeof(string), typeof(InfoElement), new PropertyMetadata(default(string)));
|
||||
/// <summary>
|
||||
/// 正则表达式
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty RegexPatternProperty = DependencyProperty.RegisterAttached(
|
||||
"RegexPattern", typeof(string), typeof(InfoElement), new PropertyMetadata(default(string)));
|
||||
|
||||
public static void SetRegexPattern(DependencyObject element, string value)
|
||||
=> element.SetValue(RegexPatternProperty, value);
|
||||
public static void SetRegexPattern(DependencyObject element, string value)
|
||||
=> element.SetValue(RegexPatternProperty, value);
|
||||
|
||||
public static string GetRegexPattern(DependencyObject element)
|
||||
=> (string) element.GetValue(RegexPatternProperty);
|
||||
}
|
||||
public static string GetRegexPattern(DependencyObject element)
|
||||
=> (string) element.GetValue(RegexPatternProperty);
|
||||
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowClearButton", typeof(bool), typeof(InfoElement), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static void SetShowClearButton(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetShowClearButton(DependencyObject element)
|
||||
=> (bool) element.GetValue(ShowClearButtonProperty);
|
||||
}
|
||||
@@ -5,103 +5,102 @@ using System.Windows.Controls.Primitives;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class MenuTopLineAttach
|
||||
{
|
||||
public class MenuTopLineAttach
|
||||
public static readonly DependencyProperty PopupProperty = DependencyProperty.RegisterAttached(
|
||||
"Popup", typeof(Popup), typeof(MenuTopLineAttach), new PropertyMetadata(default(Popup), OnPopupChanged));
|
||||
|
||||
private static void OnPopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
public static readonly DependencyProperty PopupProperty = DependencyProperty.RegisterAttached(
|
||||
"Popup", typeof(Popup), typeof(MenuTopLineAttach), new PropertyMetadata(default(Popup), OnPopupChanged));
|
||||
var topLine = (FrameworkElement) d;
|
||||
|
||||
private static void OnPopupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (e.NewValue is Popup { TemplatedParent: MenuItem menuItem })
|
||||
{
|
||||
var topLine = (FrameworkElement) d;
|
||||
|
||||
if (e.NewValue is Popup { TemplatedParent: MenuItem menuItem })
|
||||
{
|
||||
SetTopLine(menuItem, topLine);
|
||||
menuItem.Loaded += MenuItem_Loaded;
|
||||
}
|
||||
SetTopLine(menuItem, topLine);
|
||||
menuItem.Loaded += MenuItem_Loaded;
|
||||
}
|
||||
|
||||
private static void MenuItem_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = (FrameworkElement) sender;
|
||||
menuItem.Unloaded += MenuItem_Unloaded;
|
||||
var topLine = GetTopLine(menuItem);
|
||||
var popup = GetPopup(topLine);
|
||||
if (popup != null)
|
||||
{
|
||||
popup.Opened += Popup_Opened;
|
||||
}
|
||||
}
|
||||
|
||||
private static void MenuItem_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = (FrameworkElement) sender;
|
||||
menuItem.Unloaded -= MenuItem_Unloaded;
|
||||
var topLine = GetTopLine(menuItem);
|
||||
var popup = GetPopup(topLine);
|
||||
if (popup != null)
|
||||
{
|
||||
popup.Opened -= Popup_Opened;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Popup_Opened(object sender, EventArgs e)
|
||||
{
|
||||
var popup = (Popup) sender;
|
||||
if (popup.TemplatedParent is MenuItem menuItem)
|
||||
{
|
||||
var topLine = GetTopLine(menuItem);
|
||||
if (topLine == null) return;
|
||||
|
||||
topLine.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
topLine.Width = menuItem.ActualWidth;
|
||||
topLine.Margin = new Thickness();
|
||||
|
||||
var positionLeftTop = menuItem.PointToScreen(new Point());
|
||||
var positionRightBottom = menuItem.PointToScreen(new Point(menuItem.ActualWidth, menuItem.ActualHeight));
|
||||
ScreenHelper.FindMonitorRectsFromPoint(InteropMethods.GetCursorPos(), out _, out var workAreaRect);
|
||||
var panel = VisualHelper.GetParent<Panel>(topLine);
|
||||
|
||||
if (positionLeftTop.X < 0)
|
||||
{
|
||||
|
||||
topLine.Margin = new Thickness(positionLeftTop.X - panel.Margin.Left, 0, 0, 0);
|
||||
}
|
||||
else if (positionLeftTop.X + panel.ActualWidth > workAreaRect.Right)
|
||||
{
|
||||
var overflowWidth = positionRightBottom.X - workAreaRect.Right;
|
||||
if (overflowWidth > 0)
|
||||
{
|
||||
topLine.Width -= overflowWidth + panel.Margin.Right;
|
||||
}
|
||||
topLine.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
topLine.Margin = new Thickness(positionLeftTop.X + panel.ActualWidth - workAreaRect.Right + panel.Margin.Right, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (positionRightBottom.Y > workAreaRect.Bottom)
|
||||
{
|
||||
topLine.Width = 0;
|
||||
topLine.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
topLine.Margin = new Thickness();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetPopup(DependencyObject element, Popup value)
|
||||
=> element.SetValue(PopupProperty, value);
|
||||
|
||||
public static Popup GetPopup(DependencyObject element)
|
||||
=> (Popup) element.GetValue(PopupProperty);
|
||||
|
||||
internal static readonly DependencyProperty TopLineProperty = DependencyProperty.RegisterAttached(
|
||||
"TopLine", typeof(FrameworkElement), typeof(MenuTopLineAttach), new PropertyMetadata(default(FrameworkElement)));
|
||||
|
||||
internal static void SetTopLine(DependencyObject element, FrameworkElement value)
|
||||
=> element.SetValue(TopLineProperty, value);
|
||||
|
||||
internal static FrameworkElement GetTopLine(DependencyObject element)
|
||||
=> (FrameworkElement) element.GetValue(TopLineProperty);
|
||||
}
|
||||
|
||||
private static void MenuItem_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = (FrameworkElement) sender;
|
||||
menuItem.Unloaded += MenuItem_Unloaded;
|
||||
var topLine = GetTopLine(menuItem);
|
||||
var popup = GetPopup(topLine);
|
||||
if (popup != null)
|
||||
{
|
||||
popup.Opened += Popup_Opened;
|
||||
}
|
||||
}
|
||||
|
||||
private static void MenuItem_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = (FrameworkElement) sender;
|
||||
menuItem.Unloaded -= MenuItem_Unloaded;
|
||||
var topLine = GetTopLine(menuItem);
|
||||
var popup = GetPopup(topLine);
|
||||
if (popup != null)
|
||||
{
|
||||
popup.Opened -= Popup_Opened;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Popup_Opened(object sender, EventArgs e)
|
||||
{
|
||||
var popup = (Popup) sender;
|
||||
if (popup.TemplatedParent is MenuItem menuItem)
|
||||
{
|
||||
var topLine = GetTopLine(menuItem);
|
||||
if (topLine == null) return;
|
||||
|
||||
topLine.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
topLine.Width = menuItem.ActualWidth;
|
||||
topLine.Margin = new Thickness();
|
||||
|
||||
var positionLeftTop = menuItem.PointToScreen(new Point());
|
||||
var positionRightBottom = menuItem.PointToScreen(new Point(menuItem.ActualWidth, menuItem.ActualHeight));
|
||||
ScreenHelper.FindMonitorRectsFromPoint(InteropMethods.GetCursorPos(), out _, out var workAreaRect);
|
||||
var panel = VisualHelper.GetParent<Panel>(topLine);
|
||||
|
||||
if (positionLeftTop.X < 0)
|
||||
{
|
||||
|
||||
topLine.Margin = new Thickness(positionLeftTop.X - panel.Margin.Left, 0, 0, 0);
|
||||
}
|
||||
else if (positionLeftTop.X + panel.ActualWidth > workAreaRect.Right)
|
||||
{
|
||||
var overflowWidth = positionRightBottom.X - workAreaRect.Right;
|
||||
if (overflowWidth > 0)
|
||||
{
|
||||
topLine.Width -= overflowWidth + panel.Margin.Right;
|
||||
}
|
||||
topLine.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
topLine.Margin = new Thickness(positionLeftTop.X + panel.ActualWidth - workAreaRect.Right + panel.Margin.Right, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (positionRightBottom.Y > workAreaRect.Bottom)
|
||||
{
|
||||
topLine.Width = 0;
|
||||
topLine.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
topLine.Margin = new Thickness();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetPopup(DependencyObject element, Popup value)
|
||||
=> element.SetValue(PopupProperty, value);
|
||||
|
||||
public static Popup GetPopup(DependencyObject element)
|
||||
=> (Popup) element.GetValue(PopupProperty);
|
||||
|
||||
internal static readonly DependencyProperty TopLineProperty = DependencyProperty.RegisterAttached(
|
||||
"TopLine", typeof(FrameworkElement), typeof(MenuTopLineAttach), new PropertyMetadata(default(FrameworkElement)));
|
||||
|
||||
internal static void SetTopLine(DependencyObject element, FrameworkElement value)
|
||||
=> element.SetValue(TopLineProperty, value);
|
||||
|
||||
internal static FrameworkElement GetTopLine(DependencyObject element)
|
||||
=> (FrameworkElement) element.GetValue(TopLineProperty);
|
||||
}
|
||||
@@ -2,43 +2,42 @@
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class PanelElement
|
||||
{
|
||||
public class PanelElement
|
||||
public static readonly DependencyProperty FluidMoveBehaviorProperty = DependencyProperty.RegisterAttached(
|
||||
"FluidMoveBehavior", typeof(FluidMoveBehavior), typeof(PanelElement), new PropertyMetadata(default(FluidMoveBehavior), OnFluidMoveBehaviorChanged));
|
||||
|
||||
private static void OnFluidMoveBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
public static readonly DependencyProperty FluidMoveBehaviorProperty = DependencyProperty.RegisterAttached(
|
||||
"FluidMoveBehavior", typeof(FluidMoveBehavior), typeof(PanelElement), new PropertyMetadata(default(FluidMoveBehavior), OnFluidMoveBehaviorChanged));
|
||||
|
||||
private static void OnFluidMoveBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (d is Panel panel)
|
||||
{
|
||||
if (d is Panel panel)
|
||||
{
|
||||
var collection = Interaction.GetBehaviors(panel);
|
||||
var oldBehavior = GetTempFluidMoveBehavior(panel);
|
||||
collection.ItemRemoved(oldBehavior);
|
||||
panel.SetCurrentValue(TempFluidMoveBehaviorProperty, DependencyProperty.UnsetValue);
|
||||
var collection = Interaction.GetBehaviors(panel);
|
||||
var oldBehavior = GetTempFluidMoveBehavior(panel);
|
||||
collection.ItemRemoved(oldBehavior);
|
||||
panel.SetCurrentValue(TempFluidMoveBehaviorProperty, DependencyProperty.UnsetValue);
|
||||
|
||||
if (e.NewValue is FluidMoveBehavior behavior)
|
||||
{
|
||||
collection.ItemAdded(behavior);
|
||||
SetTempFluidMoveBehavior(panel, behavior);
|
||||
}
|
||||
if (e.NewValue is FluidMoveBehavior behavior)
|
||||
{
|
||||
collection.ItemAdded(behavior);
|
||||
SetTempFluidMoveBehavior(panel, behavior);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetFluidMoveBehavior(DependencyObject element, FluidMoveBehavior value)
|
||||
=> element.SetValue(FluidMoveBehaviorProperty, value);
|
||||
|
||||
public static FluidMoveBehavior GetFluidMoveBehavior(DependencyObject element)
|
||||
=> (FluidMoveBehavior) element.GetValue(FluidMoveBehaviorProperty);
|
||||
|
||||
private static readonly DependencyProperty TempFluidMoveBehaviorProperty = DependencyProperty.RegisterAttached(
|
||||
"TempFluidMoveBehavior", typeof(FluidMoveBehavior), typeof(PanelElement), new PropertyMetadata(default(FluidMoveBehavior)));
|
||||
|
||||
private static void SetTempFluidMoveBehavior(DependencyObject element, FluidMoveBehavior value)
|
||||
=> element.SetValue(TempFluidMoveBehaviorProperty, value);
|
||||
|
||||
private static FluidMoveBehavior GetTempFluidMoveBehavior(DependencyObject element)
|
||||
=> (FluidMoveBehavior) element.GetValue(TempFluidMoveBehaviorProperty);
|
||||
}
|
||||
|
||||
public static void SetFluidMoveBehavior(DependencyObject element, FluidMoveBehavior value)
|
||||
=> element.SetValue(FluidMoveBehaviorProperty, value);
|
||||
|
||||
public static FluidMoveBehavior GetFluidMoveBehavior(DependencyObject element)
|
||||
=> (FluidMoveBehavior) element.GetValue(FluidMoveBehaviorProperty);
|
||||
|
||||
private static readonly DependencyProperty TempFluidMoveBehaviorProperty = DependencyProperty.RegisterAttached(
|
||||
"TempFluidMoveBehavior", typeof(FluidMoveBehavior), typeof(PanelElement), new PropertyMetadata(default(FluidMoveBehavior)));
|
||||
|
||||
private static void SetTempFluidMoveBehavior(DependencyObject element, FluidMoveBehavior value)
|
||||
=> element.SetValue(TempFluidMoveBehaviorProperty, value);
|
||||
|
||||
private static FluidMoveBehavior GetTempFluidMoveBehavior(DependencyObject element)
|
||||
=> (FluidMoveBehavior) element.GetValue(TempFluidMoveBehaviorProperty);
|
||||
}
|
||||
@@ -1,54 +1,53 @@
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class PasswordBoxAttach
|
||||
{
|
||||
public class PasswordBoxAttach
|
||||
/// <summary>
|
||||
/// 密码长度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordLengthProperty = DependencyProperty.RegisterAttached(
|
||||
"PasswordLength", typeof(int), typeof(PasswordBoxAttach), new PropertyMetadata(ValueBoxes.Int0Box));
|
||||
|
||||
public static void SetPasswordLength(DependencyObject element, int value) => element.SetValue(PasswordLengthProperty, value);
|
||||
|
||||
public static int GetPasswordLength(DependencyObject element) => (int) element.GetValue(PasswordLengthProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 是否监测
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsMonitoringProperty = DependencyProperty.RegisterAttached(
|
||||
"IsMonitoring", typeof(bool), typeof(PasswordBoxAttach), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits, OnIsMonitoringChanged));
|
||||
|
||||
private static void OnIsMonitoringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
/// <summary>
|
||||
/// 密码长度
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordLengthProperty = DependencyProperty.RegisterAttached(
|
||||
"PasswordLength", typeof(int), typeof(PasswordBoxAttach), new PropertyMetadata(ValueBoxes.Int0Box));
|
||||
|
||||
public static void SetPasswordLength(DependencyObject element, int value) => element.SetValue(PasswordLengthProperty, value);
|
||||
|
||||
public static int GetPasswordLength(DependencyObject element) => (int) element.GetValue(PasswordLengthProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 是否监测
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsMonitoringProperty = DependencyProperty.RegisterAttached(
|
||||
"IsMonitoring", typeof(bool), typeof(PasswordBoxAttach), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits, OnIsMonitoringChanged));
|
||||
|
||||
private static void OnIsMonitoringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (d is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
if (d is System.Windows.Controls.PasswordBox passwordBox)
|
||||
if (e.NewValue is bool boolValue)
|
||||
{
|
||||
if (e.NewValue is bool boolValue)
|
||||
if (boolValue)
|
||||
{
|
||||
if (boolValue)
|
||||
{
|
||||
passwordBox.PasswordChanged += PasswordChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
passwordBox.PasswordChanged -= PasswordChanged;
|
||||
}
|
||||
passwordBox.PasswordChanged += PasswordChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
passwordBox.PasswordChanged -= PasswordChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetIsMonitoring(DependencyObject element, bool value) => element.SetValue(IsMonitoringProperty, ValueBoxes.BooleanBox(value));
|
||||
public static void SetIsMonitoring(DependencyObject element, bool value) => element.SetValue(IsMonitoringProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsMonitoring(DependencyObject element) => (bool) element.GetValue(IsMonitoringProperty);
|
||||
public static bool GetIsMonitoring(DependencyObject element) => (bool) element.GetValue(IsMonitoringProperty);
|
||||
|
||||
private static void PasswordChanged(object sender, RoutedEventArgs e)
|
||||
private static void PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
if (sender is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
SetPasswordLength(passwordBox, passwordBox.Password.Length);
|
||||
}
|
||||
SetPasswordLength(passwordBox, passwordBox.Password.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,42 +4,41 @@ using System.Windows.Shapes;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Converter;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class RectangleAttach
|
||||
{
|
||||
public static readonly DependencyProperty CircularProperty = DependencyProperty.RegisterAttached(
|
||||
"Circular", typeof(bool), typeof(RectangleAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnCircularChanged));
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
private static void OnCircularChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
public class RectangleAttach
|
||||
{
|
||||
public static readonly DependencyProperty CircularProperty = DependencyProperty.RegisterAttached(
|
||||
"Circular", typeof(bool), typeof(RectangleAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnCircularChanged));
|
||||
|
||||
private static void OnCircularChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Rectangle rectangle)
|
||||
{
|
||||
if (d is Rectangle rectangle)
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
if ((bool) e.NewValue)
|
||||
var binding = new MultiBinding
|
||||
{
|
||||
var binding = new MultiBinding
|
||||
{
|
||||
Converter = new RectangleCircularConverter()
|
||||
};
|
||||
binding.Bindings.Add(new Binding(FrameworkElement.ActualWidthProperty.Name) { Source = rectangle });
|
||||
binding.Bindings.Add(new Binding(FrameworkElement.ActualHeightProperty.Name) { Source = rectangle });
|
||||
rectangle.SetBinding(Rectangle.RadiusXProperty, binding);
|
||||
rectangle.SetBinding(Rectangle.RadiusYProperty, binding);
|
||||
}
|
||||
else
|
||||
{
|
||||
BindingOperations.ClearBinding(rectangle, FrameworkElement.ActualWidthProperty);
|
||||
BindingOperations.ClearBinding(rectangle, FrameworkElement.ActualHeightProperty);
|
||||
BindingOperations.ClearBinding(rectangle, Rectangle.RadiusXProperty);
|
||||
BindingOperations.ClearBinding(rectangle, Rectangle.RadiusYProperty);
|
||||
}
|
||||
Converter = new RectangleCircularConverter()
|
||||
};
|
||||
binding.Bindings.Add(new Binding(FrameworkElement.ActualWidthProperty.Name) { Source = rectangle });
|
||||
binding.Bindings.Add(new Binding(FrameworkElement.ActualHeightProperty.Name) { Source = rectangle });
|
||||
rectangle.SetBinding(Rectangle.RadiusXProperty, binding);
|
||||
rectangle.SetBinding(Rectangle.RadiusYProperty, binding);
|
||||
}
|
||||
else
|
||||
{
|
||||
BindingOperations.ClearBinding(rectangle, FrameworkElement.ActualWidthProperty);
|
||||
BindingOperations.ClearBinding(rectangle, FrameworkElement.ActualHeightProperty);
|
||||
BindingOperations.ClearBinding(rectangle, Rectangle.RadiusXProperty);
|
||||
BindingOperations.ClearBinding(rectangle, Rectangle.RadiusYProperty);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetCircular(DependencyObject element, bool value)
|
||||
=> element.SetValue(CircularProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetCircular(DependencyObject element)
|
||||
=> (bool) element.GetValue(CircularProperty);
|
||||
}
|
||||
|
||||
public static void SetCircular(DependencyObject element, bool value)
|
||||
=> element.SetValue(CircularProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetCircular(DependencyObject element)
|
||||
=> (bool) element.GetValue(CircularProperty);
|
||||
}
|
||||
@@ -1,17 +1,55 @@
|
||||
using System.Windows;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ScrollViewerAttach
|
||||
{
|
||||
public class ScrollViewerAttach
|
||||
public static readonly DependencyProperty AutoHideProperty = DependencyProperty.RegisterAttached(
|
||||
"AutoHide", typeof(bool), typeof(ScrollViewerAttach), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetAutoHide(DependencyObject element, bool value)
|
||||
=> element.SetValue(AutoHideProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetAutoHide(DependencyObject element)
|
||||
=> (bool) element.GetValue(AutoHideProperty);
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.RegisterAttached(
|
||||
"Orientation", typeof(Orientation), typeof(ScrollViewerAttach), new FrameworkPropertyMetadata(ValueBoxes.VerticalBox, FrameworkPropertyMetadataOptions.Inherits, OnOrientationChanged));
|
||||
|
||||
private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
public static readonly DependencyProperty AutoHideProperty = DependencyProperty.RegisterAttached(
|
||||
"AutoHide", typeof(bool), typeof(ScrollViewerAttach), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
if (d is ScrollViewer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public static void SetAutoHide(DependencyObject element, bool value)
|
||||
=> element.SetValue(AutoHideProperty, value);
|
||||
|
||||
public static bool GetAutoHide(DependencyObject element)
|
||||
=> (bool) element.GetValue(AutoHideProperty);
|
||||
if (d is System.Windows.Controls.ScrollViewer scrollViewer)
|
||||
{
|
||||
if ((Orientation) e.NewValue == Orientation.Horizontal)
|
||||
{
|
||||
scrollViewer.PreviewMouseWheel += ScrollViewer_PreviewMouseWheel;
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollViewer.PreviewMouseWheel -= ScrollViewer_PreviewMouseWheel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
|
||||
{
|
||||
var scrollViewer = (System.Windows.Controls.ScrollViewer) sender;
|
||||
scrollViewer.ScrollToHorizontalOffset(Math.Min(Math.Max(0, scrollViewer.HorizontalOffset - e.Delta), scrollViewer.ScrollableWidth));
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
public static void SetOrientation(DependencyObject element, Orientation value)
|
||||
=> element.SetValue(OrientationProperty, ValueBoxes.OrientationBox(value));
|
||||
|
||||
public static Orientation GetOrientation(DependencyObject element)
|
||||
=> (Orientation) element.GetValue(OrientationProperty);
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class StatusSwitchElement
|
||||
{
|
||||
public class StatusSwitchElement
|
||||
{
|
||||
/// <summary>
|
||||
/// 选中时展示的元素
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CheckedElementProperty = DependencyProperty.RegisterAttached(
|
||||
"CheckedElement", typeof(object), typeof(StatusSwitchElement), new PropertyMetadata(default(object)));
|
||||
/// <summary>
|
||||
/// 选中时展示的元素
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CheckedElementProperty = DependencyProperty.RegisterAttached(
|
||||
"CheckedElement", typeof(object), typeof(StatusSwitchElement), new PropertyMetadata(default(object)));
|
||||
|
||||
public static void SetCheckedElement(DependencyObject element, object value) => element.SetValue(CheckedElementProperty, value);
|
||||
public static void SetCheckedElement(DependencyObject element, object value) => element.SetValue(CheckedElementProperty, value);
|
||||
|
||||
public static object GetCheckedElement(DependencyObject element) => element.GetValue(CheckedElementProperty);
|
||||
public static object GetCheckedElement(DependencyObject element) => element.GetValue(CheckedElementProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 是否隐藏元素
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty HideUncheckedElementProperty = DependencyProperty.RegisterAttached(
|
||||
"HideUncheckedElement", typeof(bool), typeof(StatusSwitchElement), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
/// <summary>
|
||||
/// 是否隐藏元素
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty HideUncheckedElementProperty = DependencyProperty.RegisterAttached(
|
||||
"HideUncheckedElement", typeof(bool), typeof(StatusSwitchElement), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static void SetHideUncheckedElement(DependencyObject element, bool value) => element.SetValue(HideUncheckedElementProperty, ValueBoxes.BooleanBox(value));
|
||||
public static void SetHideUncheckedElement(DependencyObject element, bool value) => element.SetValue(HideUncheckedElementProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetHideUncheckedElement(DependencyObject element) => (bool) element.GetValue(HideUncheckedElementProperty);
|
||||
}
|
||||
public static bool GetHideUncheckedElement(DependencyObject element) => (bool) element.GetValue(HideUncheckedElementProperty);
|
||||
}
|
||||
@@ -5,67 +5,66 @@ using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Helper;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class TextBlockAttach
|
||||
{
|
||||
public class TextBlockAttach
|
||||
public static readonly DependencyProperty AutoTooltipProperty = DependencyProperty.RegisterAttached(
|
||||
"AutoTooltip", typeof(bool), typeof(TextBlockAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnAutoTooltipChanged));
|
||||
|
||||
private static void OnAutoTooltipChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
public static readonly DependencyProperty AutoTooltipProperty = DependencyProperty.RegisterAttached(
|
||||
"AutoTooltip", typeof(bool), typeof(TextBlockAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnAutoTooltipChanged));
|
||||
|
||||
private static void OnAutoTooltipChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (d is TextBlock ctl)
|
||||
{
|
||||
if (d is TextBlock ctl)
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
UpdateTooltip(ctl);
|
||||
ctl.SizeChanged += TextBlock_SizeChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.SizeChanged -= TextBlock_SizeChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetAutoTooltip(DependencyObject element, bool value)
|
||||
=> element.SetValue(AutoTooltipProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetAutoTooltip(DependencyObject element)
|
||||
=> (bool) element.GetValue(AutoTooltipProperty);
|
||||
|
||||
private static void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (sender is TextBlock textBlock)
|
||||
{
|
||||
UpdateTooltip(textBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateTooltip(TextBlock textBlock)
|
||||
{
|
||||
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
var width = textBlock.DesiredSize.Width - textBlock.Margin.Left - textBlock.Margin.Right;
|
||||
|
||||
// the code Math.Abs(CalcTextWidth(textBlock) - width) > 1 is not elegant end even bugly,
|
||||
// while it does solve the problem of Tooltip failure in some cases
|
||||
if (textBlock.RenderSize.Width > width || textBlock.ActualWidth < width || Math.Abs(CalcTextWidth(textBlock) - width) > 1)
|
||||
{
|
||||
ToolTipService.SetToolTip(textBlock, textBlock.Text);
|
||||
UpdateTooltip(ctl);
|
||||
ctl.SizeChanged += TextBlock_SizeChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
ToolTipService.SetToolTip(textBlock, null);
|
||||
ctl.SizeChanged -= TextBlock_SizeChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static double CalcTextWidth(TextBlock textBlock)
|
||||
public static void SetAutoTooltip(DependencyObject element, bool value)
|
||||
=> element.SetValue(AutoTooltipProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetAutoTooltip(DependencyObject element)
|
||||
=> (bool) element.GetValue(AutoTooltipProperty);
|
||||
|
||||
private static void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (sender is TextBlock textBlock)
|
||||
{
|
||||
var formattedText = TextHelper.CreateFormattedText(textBlock.Text, textBlock.FlowDirection,
|
||||
new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch),
|
||||
textBlock.FontSize);
|
||||
|
||||
return formattedText.WidthIncludingTrailingWhitespace;
|
||||
UpdateTooltip(textBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateTooltip(TextBlock textBlock)
|
||||
{
|
||||
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
var width = textBlock.DesiredSize.Width - textBlock.Margin.Left - textBlock.Margin.Right;
|
||||
|
||||
// the code Math.Abs(CalcTextWidth(textBlock) - width) > 1 is not elegant end even bugly,
|
||||
// while it does solve the problem of Tooltip failure in some cases
|
||||
if (textBlock.RenderSize.Width > width || textBlock.ActualWidth < width || Math.Abs(CalcTextWidth(textBlock) - width) > 1)
|
||||
{
|
||||
ToolTipService.SetToolTip(textBlock, textBlock.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
ToolTipService.SetToolTip(textBlock, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static double CalcTextWidth(TextBlock textBlock)
|
||||
{
|
||||
var formattedText = TextHelper.CreateFormattedText(textBlock.Text, textBlock.FlowDirection,
|
||||
new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch),
|
||||
textBlock.FontSize);
|
||||
|
||||
return formattedText.WidthIncludingTrailingWhitespace;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,30 @@
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class TipElement
|
||||
{
|
||||
public class TipElement
|
||||
{
|
||||
public static readonly DependencyProperty VisibilityProperty = DependencyProperty.RegisterAttached(
|
||||
"Visibility", typeof(Visibility), typeof(TipElement), new PropertyMetadata(Visibility.Collapsed));
|
||||
public static readonly DependencyProperty VisibilityProperty = DependencyProperty.RegisterAttached(
|
||||
"Visibility", typeof(Visibility), typeof(TipElement), new PropertyMetadata(Visibility.Collapsed));
|
||||
|
||||
public static void SetVisibility(DependencyObject element, Visibility value) => element.SetValue(VisibilityProperty, value);
|
||||
public static void SetVisibility(DependencyObject element, Visibility value) => element.SetValue(VisibilityProperty, value);
|
||||
|
||||
public static Visibility GetVisibility(DependencyObject element) => (Visibility) element.GetValue(VisibilityProperty);
|
||||
public static Visibility GetVisibility(DependencyObject element) => (Visibility) element.GetValue(VisibilityProperty);
|
||||
|
||||
public static readonly DependencyProperty PlacementProperty = DependencyProperty.RegisterAttached(
|
||||
"Placement", typeof(PlacementType), typeof(TipElement), new PropertyMetadata(default(PlacementType)));
|
||||
public static readonly DependencyProperty PlacementProperty = DependencyProperty.RegisterAttached(
|
||||
"Placement", typeof(PlacementType), typeof(TipElement), new PropertyMetadata(default(PlacementType)));
|
||||
|
||||
public static void SetPlacement(DependencyObject element, PlacementType value) => element.SetValue(PlacementProperty, value);
|
||||
public static void SetPlacement(DependencyObject element, PlacementType value) => element.SetValue(PlacementProperty, value);
|
||||
|
||||
public static PlacementType GetPlacement(DependencyObject element) => (PlacementType) element.GetValue(PlacementProperty);
|
||||
public static PlacementType GetPlacement(DependencyObject element) => (PlacementType) element.GetValue(PlacementProperty);
|
||||
|
||||
public static readonly DependencyProperty StringFormatProperty = DependencyProperty.RegisterAttached(
|
||||
"StringFormat", typeof(string), typeof(TipElement), new PropertyMetadata("#0.0"));
|
||||
public static readonly DependencyProperty StringFormatProperty = DependencyProperty.RegisterAttached(
|
||||
"StringFormat", typeof(string), typeof(TipElement), new PropertyMetadata("#0.0"));
|
||||
|
||||
public static void SetStringFormat(DependencyObject element, string value)
|
||||
=> element.SetValue(StringFormatProperty, value);
|
||||
public static void SetStringFormat(DependencyObject element, string value)
|
||||
=> element.SetValue(StringFormatProperty, value);
|
||||
|
||||
public static string GetStringFormat(DependencyObject element)
|
||||
=> (string) element.GetValue(StringFormatProperty);
|
||||
}
|
||||
public static string GetStringFormat(DependencyObject element)
|
||||
=> (string) element.GetValue(StringFormatProperty);
|
||||
}
|
||||
@@ -2,87 +2,86 @@
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class TitleElement
|
||||
{
|
||||
public class TitleElement
|
||||
{
|
||||
public static readonly DependencyProperty TitleProperty = DependencyProperty.RegisterAttached(
|
||||
"Title", typeof(string), typeof(TitleElement), new PropertyMetadata(default(string)));
|
||||
public static readonly DependencyProperty TitleProperty = DependencyProperty.RegisterAttached(
|
||||
"Title", typeof(string), typeof(TitleElement), new PropertyMetadata(default(string)));
|
||||
|
||||
public static void SetTitle(DependencyObject element, string value)
|
||||
=> element.SetValue(TitleProperty, value);
|
||||
public static void SetTitle(DependencyObject element, string value)
|
||||
=> element.SetValue(TitleProperty, value);
|
||||
|
||||
public static string GetTitle(DependencyObject element)
|
||||
=> (string) element.GetValue(TitleProperty);
|
||||
public static string GetTitle(DependencyObject element)
|
||||
=> (string) element.GetValue(TitleProperty);
|
||||
|
||||
public static readonly DependencyProperty BackgroundProperty = DependencyProperty.RegisterAttached(
|
||||
"Background", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty BackgroundProperty = DependencyProperty.RegisterAttached(
|
||||
"Background", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetBackground(DependencyObject element, Brush value)
|
||||
=> element.SetValue(BackgroundProperty, value);
|
||||
public static void SetBackground(DependencyObject element, Brush value)
|
||||
=> element.SetValue(BackgroundProperty, value);
|
||||
|
||||
public static Brush GetBackground(DependencyObject element)
|
||||
=> (Brush) element.GetValue(BackgroundProperty);
|
||||
public static Brush GetBackground(DependencyObject element)
|
||||
=> (Brush) element.GetValue(BackgroundProperty);
|
||||
|
||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.RegisterAttached(
|
||||
"Foreground", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty ForegroundProperty = DependencyProperty.RegisterAttached(
|
||||
"Foreground", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetForeground(DependencyObject element, Brush value)
|
||||
=> element.SetValue(ForegroundProperty, value);
|
||||
public static void SetForeground(DependencyObject element, Brush value)
|
||||
=> element.SetValue(ForegroundProperty, value);
|
||||
|
||||
public static Brush GetForeground(DependencyObject element)
|
||||
=> (Brush) element.GetValue(ForegroundProperty);
|
||||
public static Brush GetForeground(DependencyObject element)
|
||||
=> (Brush) element.GetValue(ForegroundProperty);
|
||||
|
||||
public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.RegisterAttached(
|
||||
"BorderBrush", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.RegisterAttached(
|
||||
"BorderBrush", typeof(Brush), typeof(TitleElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetBorderBrush(DependencyObject element, Brush value)
|
||||
=> element.SetValue(BorderBrushProperty, value);
|
||||
public static void SetBorderBrush(DependencyObject element, Brush value)
|
||||
=> element.SetValue(BorderBrushProperty, value);
|
||||
|
||||
public static Brush GetBorderBrush(DependencyObject element)
|
||||
=> (Brush) element.GetValue(BorderBrushProperty);
|
||||
public static Brush GetBorderBrush(DependencyObject element)
|
||||
=> (Brush) element.GetValue(BorderBrushProperty);
|
||||
|
||||
public static readonly DependencyProperty TitlePlacementProperty = DependencyProperty.RegisterAttached(
|
||||
"TitlePlacement", typeof(TitlePlacementType), typeof(TitleElement), new FrameworkPropertyMetadata(TitlePlacementType.Top, FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty TitlePlacementProperty = DependencyProperty.RegisterAttached(
|
||||
"TitlePlacement", typeof(TitlePlacementType), typeof(TitleElement), new FrameworkPropertyMetadata(TitlePlacementType.Top, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetTitlePlacement(DependencyObject element, TitlePlacementType value)
|
||||
=> element.SetValue(TitlePlacementProperty, value);
|
||||
public static void SetTitlePlacement(DependencyObject element, TitlePlacementType value)
|
||||
=> element.SetValue(TitlePlacementProperty, value);
|
||||
|
||||
public static TitlePlacementType GetTitlePlacement(DependencyObject element)
|
||||
=> (TitlePlacementType) element.GetValue(TitlePlacementProperty);
|
||||
public static TitlePlacementType GetTitlePlacement(DependencyObject element)
|
||||
=> (TitlePlacementType) element.GetValue(TitlePlacementProperty);
|
||||
|
||||
public static readonly DependencyProperty TitleWidthProperty = DependencyProperty.RegisterAttached(
|
||||
"TitleWidth", typeof(GridLength), typeof(TitleElement), new FrameworkPropertyMetadata(GridLength.Auto, FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty TitleWidthProperty = DependencyProperty.RegisterAttached(
|
||||
"TitleWidth", typeof(GridLength), typeof(TitleElement), new FrameworkPropertyMetadata(GridLength.Auto, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetTitleWidth(DependencyObject element, GridLength value) => element.SetValue(TitleWidthProperty, value);
|
||||
public static void SetTitleWidth(DependencyObject element, GridLength value) => element.SetValue(TitleWidthProperty, value);
|
||||
|
||||
public static GridLength GetTitleWidth(DependencyObject element) => (GridLength) element.GetValue(TitleWidthProperty);
|
||||
public static GridLength GetTitleWidth(DependencyObject element) => (GridLength) element.GetValue(TitleWidthProperty);
|
||||
|
||||
public static readonly DependencyProperty HorizontalAlignmentProperty = DependencyProperty.RegisterAttached(
|
||||
"HorizontalAlignment", typeof(HorizontalAlignment), typeof(TitleElement), new FrameworkPropertyMetadata(default(HorizontalAlignment), FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty HorizontalAlignmentProperty = DependencyProperty.RegisterAttached(
|
||||
"HorizontalAlignment", typeof(HorizontalAlignment), typeof(TitleElement), new FrameworkPropertyMetadata(default(HorizontalAlignment), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetHorizontalAlignment(DependencyObject element, HorizontalAlignment value)
|
||||
=> element.SetValue(HorizontalAlignmentProperty, value);
|
||||
public static void SetHorizontalAlignment(DependencyObject element, HorizontalAlignment value)
|
||||
=> element.SetValue(HorizontalAlignmentProperty, value);
|
||||
|
||||
public static HorizontalAlignment GetHorizontalAlignment(DependencyObject element)
|
||||
=> (HorizontalAlignment) element.GetValue(HorizontalAlignmentProperty);
|
||||
public static HorizontalAlignment GetHorizontalAlignment(DependencyObject element)
|
||||
=> (HorizontalAlignment) element.GetValue(HorizontalAlignmentProperty);
|
||||
|
||||
public static readonly DependencyProperty VerticalAlignmentProperty = DependencyProperty.RegisterAttached(
|
||||
"VerticalAlignment", typeof(VerticalAlignment), typeof(TitleElement), new FrameworkPropertyMetadata(default(VerticalAlignment), FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty VerticalAlignmentProperty = DependencyProperty.RegisterAttached(
|
||||
"VerticalAlignment", typeof(VerticalAlignment), typeof(TitleElement), new FrameworkPropertyMetadata(default(VerticalAlignment), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetVerticalAlignment(DependencyObject element, VerticalAlignment value)
|
||||
=> element.SetValue(VerticalAlignmentProperty, value);
|
||||
public static void SetVerticalAlignment(DependencyObject element, VerticalAlignment value)
|
||||
=> element.SetValue(VerticalAlignmentProperty, value);
|
||||
|
||||
public static VerticalAlignment GetVerticalAlignment(DependencyObject element)
|
||||
=> (VerticalAlignment) element.GetValue(VerticalAlignmentProperty);
|
||||
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 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 void SetMarginOnTheLeft(DependencyObject element, Thickness value)
|
||||
=> element.SetValue(MarginOnTheLeftProperty, value);
|
||||
|
||||
public static Thickness GetMarginOnTheLeft(DependencyObject element)
|
||||
=> (Thickness) element.GetValue(MarginOnTheLeftProperty);
|
||||
}
|
||||
public static Thickness GetMarginOnTheLeft(DependencyObject element)
|
||||
=> (Thickness) element.GetValue(MarginOnTheLeftProperty);
|
||||
}
|
||||
@@ -1,53 +1,52 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class VisualElement
|
||||
{
|
||||
public class VisualElement
|
||||
{
|
||||
public static readonly DependencyProperty HighlightBrushProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightBrush", typeof(Brush), typeof(VisualElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty HighlightBrushProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightBrush", typeof(Brush), typeof(VisualElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetHighlightBrush(DependencyObject element, Brush value)
|
||||
=> element.SetValue(HighlightBrushProperty, value);
|
||||
public static void SetHighlightBrush(DependencyObject element, Brush value)
|
||||
=> element.SetValue(HighlightBrushProperty, value);
|
||||
|
||||
public static Brush GetHighlightBrush(DependencyObject element)
|
||||
=> (Brush) element.GetValue(HighlightBrushProperty);
|
||||
public static Brush GetHighlightBrush(DependencyObject element)
|
||||
=> (Brush) element.GetValue(HighlightBrushProperty);
|
||||
|
||||
public static readonly DependencyProperty HighlightBackgroundProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightBackground", typeof(Brush), typeof(VisualElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty HighlightBackgroundProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightBackground", typeof(Brush), typeof(VisualElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetHighlightBackground(DependencyObject element, Brush value)
|
||||
=> element.SetValue(HighlightBackgroundProperty, value);
|
||||
public static void SetHighlightBackground(DependencyObject element, Brush value)
|
||||
=> element.SetValue(HighlightBackgroundProperty, value);
|
||||
|
||||
public static Brush GetHighlightBackground(DependencyObject element)
|
||||
=> (Brush) element.GetValue(HighlightBackgroundProperty);
|
||||
public static Brush GetHighlightBackground(DependencyObject element)
|
||||
=> (Brush) element.GetValue(HighlightBackgroundProperty);
|
||||
|
||||
public static readonly DependencyProperty HighlightBorderBrushProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightBorderBrush", typeof(Brush), typeof(VisualElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty HighlightBorderBrushProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightBorderBrush", typeof(Brush), typeof(VisualElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetHighlightBorderBrush(DependencyObject element, Brush value)
|
||||
=> element.SetValue(HighlightBorderBrushProperty, value);
|
||||
public static void SetHighlightBorderBrush(DependencyObject element, Brush value)
|
||||
=> element.SetValue(HighlightBorderBrushProperty, value);
|
||||
|
||||
public static Brush GetHighlightBorderBrush(DependencyObject element)
|
||||
=> (Brush) element.GetValue(HighlightBorderBrushProperty);
|
||||
public static Brush GetHighlightBorderBrush(DependencyObject element)
|
||||
=> (Brush) element.GetValue(HighlightBorderBrushProperty);
|
||||
|
||||
public static readonly DependencyProperty HighlightForegroundProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightForeground", typeof(Brush), typeof(VisualElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
public static readonly DependencyProperty HighlightForegroundProperty = DependencyProperty.RegisterAttached(
|
||||
"HighlightForeground", typeof(Brush), typeof(VisualElement), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetHighlightForeground(DependencyObject element, Brush value)
|
||||
=> element.SetValue(HighlightForegroundProperty, value);
|
||||
public static void SetHighlightForeground(DependencyObject element, Brush value)
|
||||
=> element.SetValue(HighlightForegroundProperty, value);
|
||||
|
||||
public static Brush GetHighlightForeground(DependencyObject element)
|
||||
=> (Brush) element.GetValue(HighlightForegroundProperty);
|
||||
public static Brush GetHighlightForeground(DependencyObject element)
|
||||
=> (Brush) element.GetValue(HighlightForegroundProperty);
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
|
||||
"Text", typeof(string), typeof(VisualElement), new PropertyMetadata(default(string)));
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
|
||||
"Text", typeof(string), typeof(VisualElement), new PropertyMetadata(default(string)));
|
||||
|
||||
public static void SetText(DependencyObject element, string value)
|
||||
=> element.SetValue(TextProperty, value);
|
||||
public static void SetText(DependencyObject element, string value)
|
||||
=> element.SetValue(TextProperty, value);
|
||||
|
||||
public static string GetText(DependencyObject element)
|
||||
=> (string) element.GetValue(TextProperty);
|
||||
}
|
||||
public static string GetText(DependencyObject element)
|
||||
=> (string) element.GetValue(TextProperty);
|
||||
}
|
||||
@@ -6,144 +6,143 @@ using System.Windows.Interop;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public static class WindowAttach
|
||||
{
|
||||
public static class WindowAttach
|
||||
public static readonly DependencyProperty IsDragElementProperty = DependencyProperty.RegisterAttached(
|
||||
"IsDragElement", typeof(bool), typeof(WindowAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnIsDragElementChanged));
|
||||
|
||||
public static void SetIsDragElement(DependencyObject element, bool value)
|
||||
=> element.SetValue(IsDragElementProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsDragElement(DependencyObject element)
|
||||
=> (bool) element.GetValue(IsDragElementProperty);
|
||||
|
||||
private static void OnIsDragElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
public static readonly DependencyProperty IsDragElementProperty = DependencyProperty.RegisterAttached(
|
||||
"IsDragElement", typeof(bool), typeof(WindowAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnIsDragElementChanged));
|
||||
|
||||
public static void SetIsDragElement(DependencyObject element, bool value)
|
||||
=> element.SetValue(IsDragElementProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsDragElement(DependencyObject element)
|
||||
=> (bool) element.GetValue(IsDragElementProperty);
|
||||
|
||||
private static void OnIsDragElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (d is UIElement ctl)
|
||||
{
|
||||
if (d is UIElement ctl)
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
ctl.MouseLeftButtonDown += DragElement_MouseLeftButtonDown;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.MouseLeftButtonDown -= DragElement_MouseLeftButtonDown;
|
||||
}
|
||||
ctl.MouseLeftButtonDown += DragElement_MouseLeftButtonDown;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.MouseLeftButtonDown -= DragElement_MouseLeftButtonDown;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DragElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is DependencyObject obj && e.ButtonState == MouseButtonState.Pressed)
|
||||
{
|
||||
System.Windows.Window.GetWindow(obj)?.DragMove();
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IgnoreAltF4Property = DependencyProperty.RegisterAttached(
|
||||
"IgnoreAltF4", typeof(bool), typeof(WindowAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnIgnoreAltF4Changed));
|
||||
|
||||
private static void OnIgnoreAltF4Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is System.Windows.Window window)
|
||||
{
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
window.PreviewKeyDown += Window_PreviewKeyDown;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.PreviewKeyDown -= Window_PreviewKeyDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Window_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.System && e.SystemKey == Key.F4)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetIgnoreAltF4(DependencyObject element, bool value)
|
||||
=> element.SetValue(IgnoreAltF4Property, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIgnoreAltF4(DependencyObject element)
|
||||
=> (bool) element.GetValue(IgnoreAltF4Property);
|
||||
|
||||
public static readonly DependencyProperty ShowInTaskManagerProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowInTaskManager", typeof(bool), typeof(WindowAttach), new PropertyMetadata(ValueBoxes.TrueBox, OnShowInTaskManagerChanged));
|
||||
|
||||
private static void OnShowInTaskManagerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is System.Windows.Window window)
|
||||
{
|
||||
var v = (bool) e.NewValue;
|
||||
window.SetCurrentValue(System.Windows.Window.ShowInTaskbarProperty, v);
|
||||
|
||||
if (v)
|
||||
{
|
||||
window.SourceInitialized -= Window_SourceInitialized;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.SourceInitialized += Window_SourceInitialized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Window_SourceInitialized(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is System.Windows.Window window)
|
||||
{
|
||||
var _ = new WindowInteropHelper(window)
|
||||
{
|
||||
Owner = InteropMethods.GetDesktopWindow()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetShowInTaskManager(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowInTaskManagerProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetShowInTaskManager(DependencyObject element)
|
||||
=> (bool) element.GetValue(ShowInTaskManagerProperty);
|
||||
|
||||
public static readonly DependencyProperty HideWhenClosingProperty = DependencyProperty.RegisterAttached(
|
||||
"HideWhenClosing", typeof(bool), typeof(WindowAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnHideWhenClosingChanged));
|
||||
|
||||
private static void OnHideWhenClosingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is System.Windows.Window window)
|
||||
{
|
||||
var v = (bool) e.NewValue;
|
||||
if (v)
|
||||
{
|
||||
window.Closing += Window_Closing;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.Closing -= Window_Closing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (sender is System.Windows.Window window)
|
||||
{
|
||||
window.Hide();
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetHideWhenClosing(DependencyObject element, bool value)
|
||||
=> element.SetValue(HideWhenClosingProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetHideWhenClosing(DependencyObject element)
|
||||
=> (bool) element.GetValue(HideWhenClosingProperty);
|
||||
}
|
||||
|
||||
private static void DragElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is DependencyObject obj && e.ButtonState == MouseButtonState.Pressed)
|
||||
{
|
||||
System.Windows.Window.GetWindow(obj)?.DragMove();
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IgnoreAltF4Property = DependencyProperty.RegisterAttached(
|
||||
"IgnoreAltF4", typeof(bool), typeof(WindowAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnIgnoreAltF4Changed));
|
||||
|
||||
private static void OnIgnoreAltF4Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is System.Windows.Window window)
|
||||
{
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
window.PreviewKeyDown += Window_PreviewKeyDown;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.PreviewKeyDown -= Window_PreviewKeyDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Window_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.System && e.SystemKey == Key.F4)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetIgnoreAltF4(DependencyObject element, bool value)
|
||||
=> element.SetValue(IgnoreAltF4Property, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIgnoreAltF4(DependencyObject element)
|
||||
=> (bool) element.GetValue(IgnoreAltF4Property);
|
||||
|
||||
public static readonly DependencyProperty ShowInTaskManagerProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowInTaskManager", typeof(bool), typeof(WindowAttach), new PropertyMetadata(ValueBoxes.TrueBox, OnShowInTaskManagerChanged));
|
||||
|
||||
private static void OnShowInTaskManagerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is System.Windows.Window window)
|
||||
{
|
||||
var v = (bool) e.NewValue;
|
||||
window.SetCurrentValue(System.Windows.Window.ShowInTaskbarProperty, v);
|
||||
|
||||
if (v)
|
||||
{
|
||||
window.SourceInitialized -= Window_SourceInitialized;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.SourceInitialized += Window_SourceInitialized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Window_SourceInitialized(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is System.Windows.Window window)
|
||||
{
|
||||
var _ = new WindowInteropHelper(window)
|
||||
{
|
||||
Owner = InteropMethods.GetDesktopWindow()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetShowInTaskManager(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowInTaskManagerProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetShowInTaskManager(DependencyObject element)
|
||||
=> (bool) element.GetValue(ShowInTaskManagerProperty);
|
||||
|
||||
public static readonly DependencyProperty HideWhenClosingProperty = DependencyProperty.RegisterAttached(
|
||||
"HideWhenClosing", typeof(bool), typeof(WindowAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnHideWhenClosingChanged));
|
||||
|
||||
private static void OnHideWhenClosingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is System.Windows.Window window)
|
||||
{
|
||||
var v = (bool) e.NewValue;
|
||||
if (v)
|
||||
{
|
||||
window.Closing += Window_Closing;
|
||||
}
|
||||
else
|
||||
{
|
||||
window.Closing -= Window_Closing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (sender is System.Windows.Window window)
|
||||
{
|
||||
window.Hide();
|
||||
e.Cancel = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetHideWhenClosing(DependencyObject element, bool value)
|
||||
=> element.SetValue(HideWhenClosingProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetHideWhenClosing(DependencyObject element)
|
||||
=> (bool) element.GetValue(HideWhenClosingProperty);
|
||||
}
|
||||
@@ -4,84 +4,83 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public abstract class AdornerElement : Control, IDisposable
|
||||
{
|
||||
public abstract class AdornerElement : Control, IDisposable
|
||||
protected FrameworkElement ElementTarget { get; set; }
|
||||
|
||||
public static readonly DependencyProperty TargetProperty = DependencyProperty.Register(
|
||||
"Target", typeof(FrameworkElement), typeof(AdornerElement), new PropertyMetadata(default(FrameworkElement), OnTargetChanged));
|
||||
|
||||
private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
protected FrameworkElement ElementTarget { get; set; }
|
||||
|
||||
public static readonly DependencyProperty TargetProperty = DependencyProperty.Register(
|
||||
"Target", typeof(FrameworkElement), typeof(AdornerElement), new PropertyMetadata(default(FrameworkElement), OnTargetChanged));
|
||||
|
||||
private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (AdornerElement) d;
|
||||
ctl.OnTargetChanged(ctl.ElementTarget, false);
|
||||
ctl.OnTargetChanged((FrameworkElement) e.NewValue, true);
|
||||
}
|
||||
|
||||
[Bindable(true), Category("Layout")]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public FrameworkElement Target
|
||||
{
|
||||
get => (FrameworkElement) GetValue(TargetProperty);
|
||||
set => SetValue(TargetProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty InstanceProperty = DependencyProperty.RegisterAttached(
|
||||
"Instance", typeof(AdornerElement), typeof(AdornerElement), new PropertyMetadata(default(AdornerElement), OnInstanceChanged));
|
||||
|
||||
private static void OnInstanceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is not FrameworkElement target) return;
|
||||
var element = (AdornerElement) e.NewValue;
|
||||
element.OnInstanceChanged(target);
|
||||
}
|
||||
|
||||
protected virtual void OnInstanceChanged(FrameworkElement target) => Target = target;
|
||||
|
||||
public static void SetInstance(DependencyObject element, AdornerElement value)
|
||||
=> element.SetValue(InstanceProperty, value);
|
||||
|
||||
public static AdornerElement GetInstance(DependencyObject element)
|
||||
=> (AdornerElement) element.GetValue(InstanceProperty);
|
||||
|
||||
public static readonly DependencyProperty IsInstanceProperty = DependencyProperty.RegisterAttached(
|
||||
"IsInstance", typeof(bool), typeof(AdornerElement), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public static void SetIsInstance(DependencyObject element, bool value)
|
||||
=> element.SetValue(IsInstanceProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsInstance(DependencyObject element)
|
||||
=> (bool) element.GetValue(IsInstanceProperty);
|
||||
|
||||
protected virtual void OnTargetChanged(FrameworkElement element, bool isNew)
|
||||
{
|
||||
if (element == null) return;
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
element.Unloaded -= TargetElement_Unloaded;
|
||||
ElementTarget = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
element.Unloaded += TargetElement_Unloaded;
|
||||
ElementTarget = element;
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetElement_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is FrameworkElement element)
|
||||
{
|
||||
element.Unloaded -= TargetElement_Unloaded;
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void Dispose();
|
||||
|
||||
void IDisposable.Dispose() => Dispose();
|
||||
var ctl = (AdornerElement) d;
|
||||
ctl.OnTargetChanged(ctl.ElementTarget, false);
|
||||
ctl.OnTargetChanged((FrameworkElement) e.NewValue, true);
|
||||
}
|
||||
|
||||
[Bindable(true), Category("Layout")]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public FrameworkElement Target
|
||||
{
|
||||
get => (FrameworkElement) GetValue(TargetProperty);
|
||||
set => SetValue(TargetProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty InstanceProperty = DependencyProperty.RegisterAttached(
|
||||
"Instance", typeof(AdornerElement), typeof(AdornerElement), new PropertyMetadata(default(AdornerElement), OnInstanceChanged));
|
||||
|
||||
private static void OnInstanceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is not FrameworkElement target) return;
|
||||
var element = (AdornerElement) e.NewValue;
|
||||
element.OnInstanceChanged(target);
|
||||
}
|
||||
|
||||
protected virtual void OnInstanceChanged(FrameworkElement target) => Target = target;
|
||||
|
||||
public static void SetInstance(DependencyObject element, AdornerElement value)
|
||||
=> element.SetValue(InstanceProperty, value);
|
||||
|
||||
public static AdornerElement GetInstance(DependencyObject element)
|
||||
=> (AdornerElement) element.GetValue(InstanceProperty);
|
||||
|
||||
public static readonly DependencyProperty IsInstanceProperty = DependencyProperty.RegisterAttached(
|
||||
"IsInstance", typeof(bool), typeof(AdornerElement), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public static void SetIsInstance(DependencyObject element, bool value)
|
||||
=> element.SetValue(IsInstanceProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsInstance(DependencyObject element)
|
||||
=> (bool) element.GetValue(IsInstanceProperty);
|
||||
|
||||
protected virtual void OnTargetChanged(FrameworkElement element, bool isNew)
|
||||
{
|
||||
if (element == null) return;
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
element.Unloaded -= TargetElement_Unloaded;
|
||||
ElementTarget = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
element.Unloaded += TargetElement_Unloaded;
|
||||
ElementTarget = element;
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetElement_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is FrameworkElement element)
|
||||
{
|
||||
element.Unloaded -= TargetElement_Unloaded;
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void Dispose();
|
||||
|
||||
void IDisposable.Dispose() => Dispose();
|
||||
}
|
||||
@@ -1,25 +1,24 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class HeaderedSelectableItem : SelectableItem
|
||||
{
|
||||
public class HeaderedSelectableItem : SelectableItem
|
||||
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
|
||||
"Header", typeof(object), typeof(HeaderedSelectableItem), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Header
|
||||
{
|
||||
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
|
||||
"Header", typeof(object), typeof(HeaderedSelectableItem), new PropertyMetadata(default(object)));
|
||||
get => GetValue(HeaderProperty);
|
||||
set => SetValue(HeaderProperty, value);
|
||||
}
|
||||
|
||||
public object Header
|
||||
{
|
||||
get => GetValue(HeaderProperty);
|
||||
set => SetValue(HeaderProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register(
|
||||
"HeaderTemplate", typeof(DataTemplate), typeof(HeaderedSelectableItem), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register(
|
||||
"HeaderTemplate", typeof(DataTemplate), typeof(HeaderedSelectableItem), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public DataTemplate HeaderTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(HeaderTemplateProperty);
|
||||
set => SetValue(HeaderTemplateProperty, value);
|
||||
}
|
||||
public DataTemplate HeaderTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(HeaderTemplateProperty);
|
||||
set => SetValue(HeaderTemplateProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
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)));
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public object Header
|
||||
{
|
||||
get => GetValue(HeaderProperty);
|
||||
set => SetValue(HeaderProperty, value);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public interface IGravatarGenerator
|
||||
{
|
||||
public interface IGravatarGenerator
|
||||
{
|
||||
object GetGravatar(string id);
|
||||
}
|
||||
object GetGravatar(string id);
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public interface ISelectable
|
||||
{
|
||||
event RoutedEventHandler Selected;
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
bool IsSelected { get; set; }
|
||||
}
|
||||
public interface ISelectable
|
||||
{
|
||||
event RoutedEventHandler Selected;
|
||||
|
||||
bool IsSelected { get; set; }
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public interface ISingleOpen : IDisposable
|
||||
{
|
||||
public interface ISingleOpen : IDisposable
|
||||
{
|
||||
bool CanDispose { get; }
|
||||
}
|
||||
bool CanDispose { get; }
|
||||
}
|
||||
@@ -1,41 +1,40 @@
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 规则ItemsControl
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该类的每一项都具有相同的大小和外边距
|
||||
/// </remarks>
|
||||
public class RegularItemsControl : SimpleItemsControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 规则ItemsControl
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该类的每一项都具有相同的大小和外边距
|
||||
/// </remarks>
|
||||
public class RegularItemsControl : SimpleItemsControl
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register(
|
||||
"ItemWidth", typeof(double), typeof(RegularItemsControl), new PropertyMetadata(ValueBoxes.Double200Box));
|
||||
|
||||
public double ItemWidth
|
||||
{
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register(
|
||||
"ItemWidth", typeof(double), typeof(RegularItemsControl), new PropertyMetadata(ValueBoxes.Double200Box));
|
||||
get => (double) GetValue(ItemWidthProperty);
|
||||
set => SetValue(ItemWidthProperty, value);
|
||||
}
|
||||
|
||||
public double ItemWidth
|
||||
{
|
||||
get => (double) GetValue(ItemWidthProperty);
|
||||
set => SetValue(ItemWidthProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register(
|
||||
"ItemHeight", typeof(double), typeof(RegularItemsControl), new PropertyMetadata(ValueBoxes.Double200Box));
|
||||
|
||||
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register(
|
||||
"ItemHeight", typeof(double), typeof(RegularItemsControl), new PropertyMetadata(ValueBoxes.Double200Box));
|
||||
public double ItemHeight
|
||||
{
|
||||
get => (double) GetValue(ItemHeightProperty);
|
||||
set => SetValue(ItemHeightProperty, value);
|
||||
}
|
||||
|
||||
public double ItemHeight
|
||||
{
|
||||
get => (double) GetValue(ItemHeightProperty);
|
||||
set => SetValue(ItemHeightProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register(
|
||||
"ItemMargin", typeof(Thickness), typeof(RegularItemsControl), new PropertyMetadata(default(Thickness)));
|
||||
|
||||
public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register(
|
||||
"ItemMargin", typeof(Thickness), typeof(RegularItemsControl), new PropertyMetadata(default(Thickness)));
|
||||
|
||||
public Thickness ItemMargin
|
||||
{
|
||||
get => (Thickness) GetValue(ItemMarginProperty);
|
||||
set => SetValue(ItemMarginProperty, value);
|
||||
}
|
||||
public Thickness ItemMargin
|
||||
{
|
||||
get => (Thickness) GetValue(ItemMarginProperty);
|
||||
set => SetValue(ItemMarginProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -3,109 +3,108 @@ using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class SelectableItem : ContentControl, ISelectable
|
||||
{
|
||||
public class SelectableItem : ContentControl, ISelectable
|
||||
private bool _isMouseLeftButtonDown;
|
||||
|
||||
protected override void OnMouseLeave(MouseEventArgs e)
|
||||
{
|
||||
private bool _isMouseLeftButtonDown;
|
||||
base.OnMouseLeave(e);
|
||||
|
||||
protected override void OnMouseLeave(MouseEventArgs 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)
|
||||
{
|
||||
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)
|
||||
if (SelfManage)
|
||||
{
|
||||
if (SelfManage)
|
||||
if (!IsSelected)
|
||||
{
|
||||
if (!IsSelected)
|
||||
{
|
||||
IsSelected = true;
|
||||
OnSelected(new RoutedEventArgs(SelectedEvent, this));
|
||||
}
|
||||
else if (CanDeselect)
|
||||
{
|
||||
IsSelected = false;
|
||||
OnSelected(new RoutedEventArgs(DeselectedEvent, this));
|
||||
}
|
||||
IsSelected = true;
|
||||
OnSelected(new RoutedEventArgs(SelectedEvent, this));
|
||||
}
|
||||
else if (CanDeselect)
|
||||
{
|
||||
IsSelected = false;
|
||||
OnSelected(new RoutedEventArgs(DeselectedEvent, this));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CanDeselect)
|
||||
{
|
||||
OnSelected(IsSelected
|
||||
? new RoutedEventArgs(DeselectedEvent, this)
|
||||
: new RoutedEventArgs(SelectedEvent, this));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CanDeselect)
|
||||
{
|
||||
OnSelected(IsSelected
|
||||
? new RoutedEventArgs(DeselectedEvent, this)
|
||||
: new RoutedEventArgs(SelectedEvent, this));
|
||||
}
|
||||
else
|
||||
{
|
||||
OnSelected(new RoutedEventArgs(SelectedEvent, this));
|
||||
}
|
||||
OnSelected(new RoutedEventArgs(SelectedEvent, this));
|
||||
}
|
||||
_isMouseLeftButtonDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnSelected(RoutedEventArgs e) => RaiseEvent(e);
|
||||
|
||||
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
|
||||
"IsSelected", typeof(bool), typeof(SelectableItem), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get => (bool) GetValue(IsSelectedProperty);
|
||||
set => SetValue(IsSelectedProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelfManageProperty = DependencyProperty.Register(
|
||||
"SelfManage", typeof(bool), typeof(SelectableItem), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool SelfManage
|
||||
{
|
||||
get => (bool) GetValue(SelfManageProperty);
|
||||
set => SetValue(SelfManageProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CanDeselectProperty = DependencyProperty.Register(
|
||||
"CanDeselect", typeof(bool), typeof(SelectableItem), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool CanDeselect
|
||||
{
|
||||
get => (bool) GetValue(CanDeselectProperty);
|
||||
set => SetValue(CanDeselectProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent SelectedEvent =
|
||||
EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(SelectableItem));
|
||||
|
||||
public event RoutedEventHandler Selected
|
||||
{
|
||||
add => AddHandler(SelectedEvent, value);
|
||||
remove => RemoveHandler(SelectedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent DeselectedEvent =
|
||||
EventManager.RegisterRoutedEvent("Deselected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(SelectableItem));
|
||||
|
||||
public event RoutedEventHandler Deselected
|
||||
{
|
||||
add => AddHandler(DeselectedEvent, value);
|
||||
remove => RemoveHandler(DeselectedEvent, value);
|
||||
_isMouseLeftButtonDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnSelected(RoutedEventArgs e) => RaiseEvent(e);
|
||||
|
||||
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
|
||||
"IsSelected", typeof(bool), typeof(SelectableItem), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get => (bool) GetValue(IsSelectedProperty);
|
||||
set => SetValue(IsSelectedProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelfManageProperty = DependencyProperty.Register(
|
||||
"SelfManage", typeof(bool), typeof(SelectableItem), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool SelfManage
|
||||
{
|
||||
get => (bool) GetValue(SelfManageProperty);
|
||||
set => SetValue(SelfManageProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CanDeselectProperty = DependencyProperty.Register(
|
||||
"CanDeselect", typeof(bool), typeof(SelectableItem), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool CanDeselect
|
||||
{
|
||||
get => (bool) GetValue(CanDeselectProperty);
|
||||
set => SetValue(CanDeselectProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent SelectedEvent =
|
||||
EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(SelectableItem));
|
||||
|
||||
public event RoutedEventHandler Selected
|
||||
{
|
||||
add => AddHandler(SelectedEvent, value);
|
||||
remove => RemoveHandler(SelectedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent DeselectedEvent =
|
||||
EventManager.RegisterRoutedEvent("Deselected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(SelectableItem));
|
||||
|
||||
public event RoutedEventHandler Deselected
|
||||
{
|
||||
add => AddHandler(DeselectedEvent, value);
|
||||
remove => RemoveHandler(DeselectedEvent, value);
|
||||
}
|
||||
}
|
||||
@@ -7,161 +7,160 @@ using System.Windows.Controls;
|
||||
using System.Windows.Markup;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// ItemsControl的轻量级版本
|
||||
/// </summary>
|
||||
[DefaultProperty("Items")]
|
||||
[ContentProperty("Items")]
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
public class SimpleItemsControl : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// ItemsControl的轻量级版本
|
||||
/// </summary>
|
||||
[DefaultProperty("Items")]
|
||||
[ContentProperty("Items")]
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
public class SimpleItemsControl : Control
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
|
||||
public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
|
||||
"ItemTemplate", typeof(DataTemplate), typeof(SimpleItemsControl),
|
||||
new FrameworkPropertyMetadata(default(DataTemplate), OnItemTemplateChanged));
|
||||
|
||||
public static readonly DependencyProperty ItemContainerStyleProperty = DependencyProperty.Register(
|
||||
"ItemContainerStyle", typeof(Style), typeof(SimpleItemsControl),
|
||||
new PropertyMetadata(default(Style), OnItemContainerStyleChanged));
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
|
||||
"ItemsSource", typeof(IEnumerable), typeof(SimpleItemsControl),
|
||||
new PropertyMetadata(default(IEnumerable), OnItemsSourceChanged));
|
||||
|
||||
public SimpleItemsControl()
|
||||
{
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
|
||||
public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
|
||||
"ItemTemplate", typeof(DataTemplate), typeof(SimpleItemsControl),
|
||||
new FrameworkPropertyMetadata(default(DataTemplate), OnItemTemplateChanged));
|
||||
|
||||
public static readonly DependencyProperty ItemContainerStyleProperty = DependencyProperty.Register(
|
||||
"ItemContainerStyle", typeof(Style), typeof(SimpleItemsControl),
|
||||
new PropertyMetadata(default(Style), OnItemContainerStyleChanged));
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
|
||||
"ItemsSource", typeof(IEnumerable), typeof(SimpleItemsControl),
|
||||
new PropertyMetadata(default(IEnumerable), OnItemsSourceChanged));
|
||||
|
||||
public SimpleItemsControl()
|
||||
var items = new ObservableCollection<object>();
|
||||
items.CollectionChanged += (s, e) =>
|
||||
{
|
||||
var items = new ObservableCollection<object>();
|
||||
items.CollectionChanged += (s, e) =>
|
||||
if (e.NewItems != null && e.NewItems.Count > 0)
|
||||
{
|
||||
if (e.NewItems != null && e.NewItems.Count > 0)
|
||||
{
|
||||
SetValue(HasItemsPropertyKey, ValueBoxes.TrueBox);
|
||||
}
|
||||
OnItemsChanged(s, e);
|
||||
};
|
||||
Items = items;
|
||||
}
|
||||
|
||||
public IEnumerable ItemsSource
|
||||
{
|
||||
get => (IEnumerable) GetValue(ItemsSourceProperty);
|
||||
set => SetValue(ItemsSourceProperty, value);
|
||||
}
|
||||
|
||||
[Bindable(true)]
|
||||
[Category("Content")]
|
||||
public Style ItemContainerStyle
|
||||
{
|
||||
get => (Style) GetValue(ItemContainerStyleProperty);
|
||||
set => SetValue(ItemContainerStyleProperty, value);
|
||||
}
|
||||
|
||||
[Bindable(true)]
|
||||
public DataTemplate ItemTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(ItemTemplateProperty);
|
||||
set => SetValue(ItemTemplateProperty, value);
|
||||
}
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
||||
[Bindable(true)]
|
||||
public Collection<object> Items { get; }
|
||||
|
||||
internal Panel ItemsHost { get; set; }
|
||||
|
||||
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((SimpleItemsControl) d).OnItemsSourceChanged((IEnumerable) e.OldValue, (IEnumerable) e.NewValue);
|
||||
}
|
||||
|
||||
protected virtual void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
ItemsHost?.Children.Clear();
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
ItemsHost = GetTemplateChild(ElementPanel) as Panel;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
protected virtual void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
Refresh();
|
||||
UpdateItems();
|
||||
}
|
||||
|
||||
protected virtual DependencyObject GetContainerForItemOverride() => new ContentPresenter();
|
||||
|
||||
protected virtual bool IsItemItsOwnContainerOverride(object item) => item is ContentPresenter;
|
||||
|
||||
protected virtual void PrepareContainerForItemOverride(DependencyObject element, object item)
|
||||
{
|
||||
switch (element)
|
||||
{
|
||||
case ContentControl contentControl:
|
||||
contentControl.Content = item;
|
||||
contentControl.ContentTemplate = ItemTemplate;
|
||||
break;
|
||||
case ContentPresenter contentPresenter:
|
||||
contentPresenter.Content = item;
|
||||
contentPresenter.ContentTemplate = ItemTemplate;
|
||||
break;
|
||||
SetValue(HasItemsPropertyKey, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
OnItemsChanged(s, e);
|
||||
};
|
||||
Items = items;
|
||||
}
|
||||
|
||||
private static void OnItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
=> (d as SimpleItemsControl)?.OnItemTemplateChanged(e);
|
||||
public IEnumerable ItemsSource
|
||||
{
|
||||
get => (IEnumerable) GetValue(ItemsSourceProperty);
|
||||
set => SetValue(ItemsSourceProperty, value);
|
||||
}
|
||||
|
||||
protected virtual void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e) => Refresh();
|
||||
[Bindable(true)]
|
||||
[Category("Content")]
|
||||
public Style ItemContainerStyle
|
||||
{
|
||||
get => (Style) GetValue(ItemContainerStyleProperty);
|
||||
set => SetValue(ItemContainerStyleProperty, value);
|
||||
}
|
||||
|
||||
private static void OnItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
=> (d as SimpleItemsControl)?.OnItemContainerStyleChanged(e);
|
||||
[Bindable(true)]
|
||||
public DataTemplate ItemTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(ItemTemplateProperty);
|
||||
set => SetValue(ItemTemplateProperty, value);
|
||||
}
|
||||
|
||||
protected virtual void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e) => Refresh();
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
||||
[Bindable(true)]
|
||||
public Collection<object> Items { get; }
|
||||
|
||||
internal static readonly DependencyPropertyKey HasItemsPropertyKey =
|
||||
DependencyProperty.RegisterReadOnly(nameof(HasItems), typeof(bool), typeof(SimpleItemsControl),
|
||||
new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
internal Panel ItemsHost { get; set; }
|
||||
|
||||
public static readonly DependencyProperty HasItemsProperty = HasItemsPropertyKey.DependencyProperty;
|
||||
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((SimpleItemsControl) d).OnItemsSourceChanged((IEnumerable) e.OldValue, (IEnumerable) e.NewValue);
|
||||
}
|
||||
|
||||
public bool HasItems => (bool) GetValue(HasItemsProperty);
|
||||
protected virtual void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void Refresh()
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
ItemsHost?.Children.Clear();
|
||||
|
||||
ItemsHost.Children.Clear();
|
||||
foreach (var item in Items)
|
||||
{
|
||||
DependencyObject container;
|
||||
if (IsItemItsOwnContainerOverride(item))
|
||||
{
|
||||
container = item as DependencyObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
container = GetContainerForItemOverride();
|
||||
PrepareContainerForItemOverride(container, item);
|
||||
}
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (container is FrameworkElement element)
|
||||
{
|
||||
element.Style = ItemContainerStyle;
|
||||
ItemsHost.Children.Add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemsHost = GetTemplateChild(ElementPanel) as Panel;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
protected virtual void UpdateItems()
|
||||
protected virtual void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
Refresh();
|
||||
UpdateItems();
|
||||
}
|
||||
|
||||
protected virtual DependencyObject GetContainerForItemOverride() => new ContentPresenter();
|
||||
|
||||
protected virtual bool IsItemItsOwnContainerOverride(object item) => item is ContentPresenter;
|
||||
|
||||
protected virtual void PrepareContainerForItemOverride(DependencyObject element, object item)
|
||||
{
|
||||
switch (element)
|
||||
{
|
||||
case ContentControl contentControl:
|
||||
contentControl.Content = item;
|
||||
contentControl.ContentTemplate = ItemTemplate;
|
||||
break;
|
||||
case ContentPresenter contentPresenter:
|
||||
contentPresenter.Content = item;
|
||||
contentPresenter.ContentTemplate = ItemTemplate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
=> (d as SimpleItemsControl)?.OnItemTemplateChanged(e);
|
||||
|
||||
protected virtual void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e) => Refresh();
|
||||
|
||||
private static void OnItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
=> (d as SimpleItemsControl)?.OnItemContainerStyleChanged(e);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateItems()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -9,187 +9,186 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class FloatingBlock : Control
|
||||
{
|
||||
public class FloatingBlock : Control
|
||||
public static readonly DependencyProperty ToXProperty = DependencyProperty.RegisterAttached(
|
||||
"ToX", typeof(double), typeof(FloatingBlock), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public static void SetToX(DependencyObject element, double value)
|
||||
=> element.SetValue(ToXProperty, value);
|
||||
|
||||
public static double GetToX(DependencyObject element)
|
||||
=> (double) element.GetValue(ToXProperty);
|
||||
|
||||
public static readonly DependencyProperty ToYProperty = DependencyProperty.RegisterAttached(
|
||||
"ToY", typeof(double), typeof(FloatingBlock), new PropertyMetadata(-100.0));
|
||||
|
||||
public static void SetToY(DependencyObject element, double value)
|
||||
=> element.SetValue(ToYProperty, value);
|
||||
|
||||
public static double GetToY(DependencyObject element)
|
||||
=> (double) element.GetValue(ToYProperty);
|
||||
|
||||
public static readonly DependencyProperty DurationProperty = DependencyProperty.RegisterAttached(
|
||||
"Duration", typeof(Duration), typeof(FloatingBlock), new PropertyMetadata(new Duration(TimeSpan.FromSeconds(2))));
|
||||
|
||||
public static void SetDuration(DependencyObject element, Duration value)
|
||||
=> element.SetValue(DurationProperty, value);
|
||||
|
||||
public static Duration GetDuration(DependencyObject element)
|
||||
=> (Duration) element.GetValue(DurationProperty);
|
||||
|
||||
public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.RegisterAttached(
|
||||
"HorizontalOffset", typeof(double), typeof(FloatingBlock), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public static void SetHorizontalOffset(DependencyObject element, double value)
|
||||
=> element.SetValue(HorizontalOffsetProperty, value);
|
||||
|
||||
public static double GetHorizontalOffset(DependencyObject element)
|
||||
=> (double) element.GetValue(HorizontalOffsetProperty);
|
||||
|
||||
public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.RegisterAttached(
|
||||
"VerticalOffset", typeof(double), typeof(FloatingBlock), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public static void SetVerticalOffset(DependencyObject element, double value)
|
||||
=> element.SetValue(VerticalOffsetProperty, value);
|
||||
|
||||
public static double GetVerticalOffset(DependencyObject element)
|
||||
=> (double) element.GetValue(VerticalOffsetProperty);
|
||||
|
||||
public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.RegisterAttached(
|
||||
"ContentTemplate", typeof(DataTemplate), typeof(FloatingBlock), new PropertyMetadata(default(DataTemplate), OnDataChanged));
|
||||
|
||||
public static void SetContentTemplate(DependencyObject element, DataTemplate value)
|
||||
=> element.SetValue(ContentTemplateProperty, value);
|
||||
|
||||
public static DataTemplate GetContentTemplate(DependencyObject element)
|
||||
=> (DataTemplate) element.GetValue(ContentTemplateProperty);
|
||||
|
||||
public DataTemplate ContentTemplate
|
||||
{
|
||||
public static readonly DependencyProperty ToXProperty = DependencyProperty.RegisterAttached(
|
||||
"ToX", typeof(double), typeof(FloatingBlock), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
get => (DataTemplate) GetValue(ContentTemplateProperty);
|
||||
set => SetValue(ContentTemplateProperty, value);
|
||||
}
|
||||
|
||||
public static void SetToX(DependencyObject element, double value)
|
||||
=> element.SetValue(ToXProperty, value);
|
||||
private static readonly DependencyProperty ReadyToFloatProperty = DependencyProperty.RegisterAttached(
|
||||
"ReadyToFloat", typeof(bool), typeof(FloatingBlock), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static double GetToX(DependencyObject element)
|
||||
=> (double) element.GetValue(ToXProperty);
|
||||
private static void SetReadyToFloat(DependencyObject element, bool value)
|
||||
=> element.SetValue(ReadyToFloatProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static readonly DependencyProperty ToYProperty = DependencyProperty.RegisterAttached(
|
||||
"ToY", typeof(double), typeof(FloatingBlock), new PropertyMetadata(-100.0));
|
||||
private static bool GetReadyToFloat(DependencyObject element)
|
||||
=> (bool) element.GetValue(ReadyToFloatProperty);
|
||||
|
||||
public static void SetToY(DependencyObject element, double value)
|
||||
=> element.SetValue(ToYProperty, value);
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.RegisterAttached(
|
||||
"Content", typeof(object), typeof(FloatingBlock), new PropertyMetadata(default, OnDataChanged));
|
||||
|
||||
public static double GetToY(DependencyObject element)
|
||||
=> (double) element.GetValue(ToYProperty);
|
||||
public static void SetContent(DependencyObject element, object value)
|
||||
=> element.SetValue(ContentProperty, value);
|
||||
|
||||
public static readonly DependencyProperty DurationProperty = DependencyProperty.RegisterAttached(
|
||||
"Duration", typeof(Duration), typeof(FloatingBlock), new PropertyMetadata(new Duration(TimeSpan.FromSeconds(2))));
|
||||
public static object GetContent(DependencyObject element)
|
||||
=> element.GetValue(ContentProperty);
|
||||
|
||||
public static void SetDuration(DependencyObject element, Duration value)
|
||||
=> element.SetValue(DurationProperty, value);
|
||||
public object Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
public static Duration GetDuration(DependencyObject element)
|
||||
=> (Duration) element.GetValue(DurationProperty);
|
||||
private static void OnDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is not UIElement target) return;
|
||||
|
||||
public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.RegisterAttached(
|
||||
"HorizontalOffset", typeof(double), typeof(FloatingBlock), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
target.PreviewMouseLeftButtonDown -= Target_PreviewMouseLeftButtonDown;
|
||||
target.PreviewMouseLeftButtonUp -= Target_PreviewMouseLeftButtonUp;
|
||||
|
||||
public static void SetHorizontalOffset(DependencyObject element, double value)
|
||||
=> element.SetValue(HorizontalOffsetProperty, value);
|
||||
|
||||
public static double GetHorizontalOffset(DependencyObject element)
|
||||
=> (double) element.GetValue(HorizontalOffsetProperty);
|
||||
|
||||
public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.RegisterAttached(
|
||||
"VerticalOffset", typeof(double), typeof(FloatingBlock), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public static void SetVerticalOffset(DependencyObject element, double value)
|
||||
=> element.SetValue(VerticalOffsetProperty, value);
|
||||
|
||||
public static double GetVerticalOffset(DependencyObject element)
|
||||
=> (double) element.GetValue(VerticalOffsetProperty);
|
||||
|
||||
public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.RegisterAttached(
|
||||
"ContentTemplate", typeof(DataTemplate), typeof(FloatingBlock), new PropertyMetadata(default(DataTemplate), OnDataChanged));
|
||||
|
||||
public static void SetContentTemplate(DependencyObject element, DataTemplate value)
|
||||
=> element.SetValue(ContentTemplateProperty, value);
|
||||
|
||||
public static DataTemplate GetContentTemplate(DependencyObject element)
|
||||
=> (DataTemplate) element.GetValue(ContentTemplateProperty);
|
||||
|
||||
public DataTemplate ContentTemplate
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
get => (DataTemplate) GetValue(ContentTemplateProperty);
|
||||
set => SetValue(ContentTemplateProperty, value);
|
||||
}
|
||||
|
||||
private static readonly DependencyProperty ReadyToFloatProperty = DependencyProperty.RegisterAttached(
|
||||
"ReadyToFloat", typeof(bool), typeof(FloatingBlock), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
private static void SetReadyToFloat(DependencyObject element, bool value)
|
||||
=> element.SetValue(ReadyToFloatProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
private static bool GetReadyToFloat(DependencyObject element)
|
||||
=> (bool) element.GetValue(ReadyToFloatProperty);
|
||||
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.RegisterAttached(
|
||||
"Content", typeof(object), typeof(FloatingBlock), new PropertyMetadata(default, OnDataChanged));
|
||||
|
||||
public static void SetContent(DependencyObject element, object value)
|
||||
=> element.SetValue(ContentProperty, value);
|
||||
|
||||
public static object GetContent(DependencyObject element)
|
||||
=> element.GetValue(ContentProperty);
|
||||
|
||||
public object Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
private static void OnDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is not UIElement target) return;
|
||||
|
||||
target.PreviewMouseLeftButtonDown -= Target_PreviewMouseLeftButtonDown;
|
||||
target.PreviewMouseLeftButtonUp -= Target_PreviewMouseLeftButtonUp;
|
||||
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
target.PreviewMouseLeftButtonDown += Target_PreviewMouseLeftButtonDown;
|
||||
target.PreviewMouseLeftButtonUp += Target_PreviewMouseLeftButtonUp;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Target_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) => SetReadyToFloat(sender as DependencyObject, true);
|
||||
|
||||
private static void Target_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is UIElement element && GetReadyToFloat(element))
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(element);
|
||||
if (layer != null)
|
||||
{
|
||||
var adorner = new AdornerContainer(layer)
|
||||
{
|
||||
IsHitTestVisible = false
|
||||
};
|
||||
var child = CreateBlock(element, adorner);
|
||||
adorner.Child = child;
|
||||
|
||||
layer.Add(adorner);
|
||||
}
|
||||
SetReadyToFloat(element, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static FloatingBlock CreateBlock(Visual element, AdornerContainer adorner)
|
||||
{
|
||||
var p = Mouse.GetPosition(adorner.AdornedElement);
|
||||
var transform = new TranslateTransform
|
||||
{
|
||||
X = p.X + GetHorizontalOffset(element),
|
||||
Y = p.Y + GetVerticalOffset(element)
|
||||
};
|
||||
|
||||
var block = new FloatingBlock
|
||||
{
|
||||
Content = GetContent(element),
|
||||
ContentTemplate = GetContentTemplate(element),
|
||||
RenderTransform = new TransformGroup
|
||||
{
|
||||
Children =
|
||||
{
|
||||
transform
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var milliseconds = GetDuration(element).TimeSpan.TotalMilliseconds;
|
||||
|
||||
var animationX = AnimationHelper.CreateAnimation(GetToX(element) + transform.X, milliseconds);
|
||||
Storyboard.SetTargetProperty(animationX, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"));
|
||||
Storyboard.SetTarget(animationX, block);
|
||||
|
||||
var animationY = AnimationHelper.CreateAnimation(GetToY(element) + transform.Y, milliseconds);
|
||||
Storyboard.SetTargetProperty(animationY, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.Y)"));
|
||||
Storyboard.SetTarget(animationY, block);
|
||||
|
||||
var animationOpacity = AnimationHelper.CreateAnimation(0, milliseconds);
|
||||
Storyboard.SetTargetProperty(animationOpacity, new PropertyPath("Opacity"));
|
||||
Storyboard.SetTarget(animationOpacity, block);
|
||||
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Completed += (s, e) =>
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(element);
|
||||
if (layer != null)
|
||||
{
|
||||
layer.Remove(adorner);
|
||||
}
|
||||
else if (adorner.Parent is AdornerLayer parent)
|
||||
{
|
||||
parent.Remove(adorner);
|
||||
}
|
||||
|
||||
adorner.Child = null;
|
||||
};
|
||||
storyboard.Children.Add(animationX);
|
||||
storyboard.Children.Add(animationY);
|
||||
storyboard.Children.Add(animationOpacity);
|
||||
storyboard.Begin();
|
||||
|
||||
return block;
|
||||
target.PreviewMouseLeftButtonDown += Target_PreviewMouseLeftButtonDown;
|
||||
target.PreviewMouseLeftButtonUp += Target_PreviewMouseLeftButtonUp;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Target_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) => SetReadyToFloat(sender as DependencyObject, true);
|
||||
|
||||
private static void Target_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is UIElement element && GetReadyToFloat(element))
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(element);
|
||||
if (layer != null)
|
||||
{
|
||||
var adorner = new AdornerContainer(layer)
|
||||
{
|
||||
IsHitTestVisible = false
|
||||
};
|
||||
var child = CreateBlock(element, adorner);
|
||||
adorner.Child = child;
|
||||
|
||||
layer.Add(adorner);
|
||||
}
|
||||
SetReadyToFloat(element, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static FloatingBlock CreateBlock(Visual element, AdornerContainer adorner)
|
||||
{
|
||||
var p = Mouse.GetPosition(adorner.AdornedElement);
|
||||
var transform = new TranslateTransform
|
||||
{
|
||||
X = p.X + GetHorizontalOffset(element),
|
||||
Y = p.Y + GetVerticalOffset(element)
|
||||
};
|
||||
|
||||
var block = new FloatingBlock
|
||||
{
|
||||
Content = GetContent(element),
|
||||
ContentTemplate = GetContentTemplate(element),
|
||||
RenderTransform = new TransformGroup
|
||||
{
|
||||
Children =
|
||||
{
|
||||
transform
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var milliseconds = GetDuration(element).TimeSpan.TotalMilliseconds;
|
||||
|
||||
var animationX = AnimationHelper.CreateAnimation(GetToX(element) + transform.X, milliseconds);
|
||||
Storyboard.SetTargetProperty(animationX, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"));
|
||||
Storyboard.SetTarget(animationX, block);
|
||||
|
||||
var animationY = AnimationHelper.CreateAnimation(GetToY(element) + transform.Y, milliseconds);
|
||||
Storyboard.SetTargetProperty(animationY, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.Y)"));
|
||||
Storyboard.SetTarget(animationY, block);
|
||||
|
||||
var animationOpacity = AnimationHelper.CreateAnimation(0, milliseconds);
|
||||
Storyboard.SetTargetProperty(animationOpacity, new PropertyPath("Opacity"));
|
||||
Storyboard.SetTarget(animationOpacity, block);
|
||||
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Completed += (s, e) =>
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(element);
|
||||
if (layer != null)
|
||||
{
|
||||
layer.Remove(adorner);
|
||||
}
|
||||
else if (adorner.Parent is AdornerLayer parent)
|
||||
{
|
||||
parent.Remove(adorner);
|
||||
}
|
||||
|
||||
adorner.Child = null;
|
||||
};
|
||||
storyboard.Children.Add(animationX);
|
||||
storyboard.Children.Add(animationY);
|
||||
storyboard.Children.Add(animationOpacity);
|
||||
storyboard.Begin();
|
||||
|
||||
return block;
|
||||
}
|
||||
}
|
||||
@@ -5,195 +5,194 @@ using System.Windows.Media.Animation;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Expression.Drawing;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementContent, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
public class RunningBlock : ContentControl
|
||||
{
|
||||
[TemplatePart(Name = ElementContent, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
public class RunningBlock : ContentControl
|
||||
private const string ElementContent = "PART_ContentElement";
|
||||
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
|
||||
protected Storyboard _storyboard;
|
||||
|
||||
private FrameworkElement _elementContent;
|
||||
|
||||
private FrameworkElement _elementPanel;
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
private const string ElementContent = "PART_ContentElement";
|
||||
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
|
||||
protected Storyboard _storyboard;
|
||||
|
||||
private FrameworkElement _elementContent;
|
||||
|
||||
private FrameworkElement _elementPanel;
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
if (_elementPanel != null)
|
||||
{
|
||||
if (_elementPanel != null)
|
||||
_elementPanel.SizeChanged -= ElementPanel_SizeChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_elementContent = GetTemplateChild(ElementContent) as FrameworkElement;
|
||||
_elementPanel = GetTemplateChild(ElementPanel) as Panel;
|
||||
|
||||
if (_elementPanel != null)
|
||||
{
|
||||
_elementPanel.SizeChanged += ElementPanel_SizeChanged;
|
||||
}
|
||||
|
||||
UpdateContent();
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
UpdateContent();
|
||||
}
|
||||
|
||||
private void ElementPanel_SizeChanged(object sender, SizeChangedEventArgs e) => UpdateContent();
|
||||
|
||||
public static readonly DependencyProperty RunawayProperty = DependencyProperty.Register(
|
||||
"Runaway", typeof(bool), typeof(RunningBlock), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool Runaway
|
||||
{
|
||||
get => (bool) GetValue(RunawayProperty);
|
||||
set => SetValue(RunawayProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AutoRunProperty = DependencyProperty.Register(
|
||||
"AutoRun", typeof(bool), typeof(RunningBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool AutoRun
|
||||
{
|
||||
get => (bool) GetValue(AutoRunProperty);
|
||||
set => SetValue(AutoRunProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(RunningBlock), new FrameworkPropertyMetadata(default(Orientation), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register(
|
||||
"Duration", typeof(Duration), typeof(RunningBlock), new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(5)), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Duration Duration
|
||||
{
|
||||
get => (Duration) GetValue(DurationProperty);
|
||||
set => SetValue(DurationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SpeedProperty = DependencyProperty.Register(
|
||||
"Speed", typeof(double), typeof(RunningBlock), new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double Speed
|
||||
{
|
||||
get => (double) GetValue(SpeedProperty);
|
||||
set => SetValue(SpeedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsRunningProperty = DependencyProperty.Register(
|
||||
"IsRunning", typeof(bool), typeof(RunningBlock), new PropertyMetadata(ValueBoxes.TrueBox, (o, args) =>
|
||||
{
|
||||
var ctl = (RunningBlock) o;
|
||||
var v = (bool) args.NewValue;
|
||||
if (v)
|
||||
{
|
||||
_elementPanel.SizeChanged -= ElementPanel_SizeChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_elementContent = GetTemplateChild(ElementContent) as FrameworkElement;
|
||||
_elementPanel = GetTemplateChild(ElementPanel) as Panel;
|
||||
|
||||
if (_elementPanel != null)
|
||||
{
|
||||
_elementPanel.SizeChanged += ElementPanel_SizeChanged;
|
||||
}
|
||||
|
||||
UpdateContent();
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
UpdateContent();
|
||||
}
|
||||
|
||||
private void ElementPanel_SizeChanged(object sender, SizeChangedEventArgs e) => UpdateContent();
|
||||
|
||||
public static readonly DependencyProperty RunawayProperty = DependencyProperty.Register(
|
||||
"Runaway", typeof(bool), typeof(RunningBlock), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool Runaway
|
||||
{
|
||||
get => (bool) GetValue(RunawayProperty);
|
||||
set => SetValue(RunawayProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AutoRunProperty = DependencyProperty.Register(
|
||||
"AutoRun", typeof(bool), typeof(RunningBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool AutoRun
|
||||
{
|
||||
get => (bool) GetValue(AutoRunProperty);
|
||||
set => SetValue(AutoRunProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(RunningBlock), new FrameworkPropertyMetadata(default(Orientation), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register(
|
||||
"Duration", typeof(Duration), typeof(RunningBlock), new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(5)), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Duration Duration
|
||||
{
|
||||
get => (Duration) GetValue(DurationProperty);
|
||||
set => SetValue(DurationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SpeedProperty = DependencyProperty.Register(
|
||||
"Speed", typeof(double), typeof(RunningBlock), new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double Speed
|
||||
{
|
||||
get => (double) GetValue(SpeedProperty);
|
||||
set => SetValue(SpeedProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsRunningProperty = DependencyProperty.Register(
|
||||
"IsRunning", typeof(bool), typeof(RunningBlock), new PropertyMetadata(ValueBoxes.TrueBox, (o, args) =>
|
||||
{
|
||||
var ctl = (RunningBlock) o;
|
||||
var v = (bool) args.NewValue;
|
||||
if (v)
|
||||
{
|
||||
ctl._storyboard?.Resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl._storyboard?.Pause();
|
||||
}
|
||||
}));
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
get => (bool) GetValue(IsRunningProperty);
|
||||
set => SetValue(IsRunningProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AutoReverseProperty = DependencyProperty.Register(
|
||||
"AutoReverse", typeof(bool), typeof(RunningBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool AutoReverse
|
||||
{
|
||||
get => (bool) GetValue(AutoReverseProperty);
|
||||
set => SetValue(AutoReverseProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private void UpdateContent()
|
||||
{
|
||||
if (_elementContent == null || _elementPanel == null) return;
|
||||
if (MathHelper.IsZero(_elementPanel.ActualWidth) || MathHelper.IsZero(_elementPanel.ActualHeight)) return;
|
||||
|
||||
_storyboard?.Stop();
|
||||
|
||||
double from;
|
||||
double to;
|
||||
PropertyPath propertyPath;
|
||||
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
{
|
||||
if (AutoRun && _elementPanel.ActualWidth < ActualWidth)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Runaway)
|
||||
{
|
||||
from = -_elementPanel.ActualWidth;
|
||||
to = ActualWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = 0;
|
||||
to = ActualWidth - _elementPanel.ActualWidth;
|
||||
SetCurrentValue(AutoReverseProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
propertyPath = new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)");
|
||||
ctl._storyboard?.Resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AutoRun && _elementPanel.ActualHeight < ActualHeight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ctl._storyboard?.Pause();
|
||||
}
|
||||
}));
|
||||
|
||||
if (Runaway)
|
||||
{
|
||||
from = -_elementPanel.ActualHeight;
|
||||
to = ActualHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = 0;
|
||||
to = ActualHeight - _elementPanel.ActualHeight;
|
||||
SetCurrentValue(AutoReverseProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
propertyPath = new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.Y)");
|
||||
public bool IsRunning
|
||||
{
|
||||
get => (bool) GetValue(IsRunningProperty);
|
||||
set => SetValue(IsRunningProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AutoReverseProperty = DependencyProperty.Register(
|
||||
"AutoReverse", typeof(bool), typeof(RunningBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool AutoReverse
|
||||
{
|
||||
get => (bool) GetValue(AutoReverseProperty);
|
||||
set => SetValue(AutoReverseProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private void UpdateContent()
|
||||
{
|
||||
if (_elementContent == null || _elementPanel == null) return;
|
||||
if (MathHelper.IsZero(_elementPanel.ActualWidth) || MathHelper.IsZero(_elementPanel.ActualHeight)) return;
|
||||
|
||||
_storyboard?.Stop();
|
||||
|
||||
double from;
|
||||
double to;
|
||||
PropertyPath propertyPath;
|
||||
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
{
|
||||
if (AutoRun && _elementPanel.ActualWidth < ActualWidth)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var duration = double.IsNaN(Speed)
|
||||
? Duration
|
||||
: !MathHelper.IsVerySmall(Speed)
|
||||
? TimeSpan.FromSeconds(Math.Abs(to - from) / Speed)
|
||||
: Duration;
|
||||
|
||||
var animation = new DoubleAnimation(from, to, duration)
|
||||
if (Runaway)
|
||||
{
|
||||
RepeatBehavior = RepeatBehavior.Forever,
|
||||
AutoReverse = AutoReverse
|
||||
};
|
||||
|
||||
Storyboard.SetTargetProperty(animation, propertyPath);
|
||||
Storyboard.SetTarget(animation, _elementContent);
|
||||
|
||||
_storyboard = new Storyboard();
|
||||
_storyboard.Children.Add(animation);
|
||||
_storyboard.Begin();
|
||||
from = -_elementPanel.ActualWidth;
|
||||
to = ActualWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = 0;
|
||||
to = ActualWidth - _elementPanel.ActualWidth;
|
||||
SetCurrentValue(AutoReverseProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
propertyPath = new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AutoRun && _elementPanel.ActualHeight < ActualHeight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Runaway)
|
||||
{
|
||||
from = -_elementPanel.ActualHeight;
|
||||
to = ActualHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = 0;
|
||||
to = ActualHeight - _elementPanel.ActualHeight;
|
||||
SetCurrentValue(AutoReverseProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
propertyPath = new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.Y)");
|
||||
}
|
||||
|
||||
var duration = double.IsNaN(Speed)
|
||||
? Duration
|
||||
: !MathHelper.IsVerySmall(Speed)
|
||||
? TimeSpan.FromSeconds(Math.Abs(to - from) / Speed)
|
||||
: Duration;
|
||||
|
||||
var animation = new DoubleAnimation(from, to, duration)
|
||||
{
|
||||
RepeatBehavior = RepeatBehavior.Forever,
|
||||
AutoReverse = AutoReverse
|
||||
};
|
||||
|
||||
Storyboard.SetTargetProperty(animation, propertyPath);
|
||||
Storyboard.SetTarget(animation, _elementContent);
|
||||
|
||||
_storyboard = new Storyboard();
|
||||
_storyboard.Children.Add(animation);
|
||||
_storyboard.Begin();
|
||||
}
|
||||
}
|
||||
@@ -3,63 +3,62 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class RunningBorder : Border
|
||||
{
|
||||
public class RunningBorder : Border
|
||||
private bool _test;
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
private bool _test;
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
if (_test)
|
||||
{
|
||||
if (_test)
|
||||
{
|
||||
_test = false;
|
||||
return constraint;
|
||||
}
|
||||
|
||||
var child = Child;
|
||||
var borderThickness = BorderThickness;
|
||||
var padding = Padding;
|
||||
|
||||
if (UseLayoutRounding)
|
||||
{
|
||||
var dpiScaleX = DpiHelper.DeviceDpiX;
|
||||
var dpiScaleY = DpiHelper.DeviceDpiY;
|
||||
|
||||
borderThickness = new Thickness(
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Left, dpiScaleX),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Top, dpiScaleY),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Right, dpiScaleX),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Bottom, dpiScaleY));
|
||||
}
|
||||
|
||||
var borderSize = ConvertThickness2Size(borderThickness);
|
||||
var paddingSize = ConvertThickness2Size(padding);
|
||||
var mySize = new Size();
|
||||
|
||||
if (child != null)
|
||||
{
|
||||
var combined = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height);
|
||||
var borderConstraint = new Size(Math.Max(0.0, constraint.Width - combined.Width), Math.Max(0.0, constraint.Height - combined.Height));
|
||||
var childConstraint = new Size(Math.Max(0.0, double.PositiveInfinity - combined.Width), Math.Max(0.0, double.PositiveInfinity - combined.Height));
|
||||
|
||||
|
||||
child.Measure(borderConstraint);
|
||||
var childSize = child.DesiredSize;
|
||||
|
||||
mySize.Width = childSize.Width + combined.Width;
|
||||
mySize.Height = childSize.Height + combined.Height;
|
||||
|
||||
child.Measure(childConstraint);
|
||||
}
|
||||
else
|
||||
{
|
||||
mySize = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height);
|
||||
}
|
||||
|
||||
return mySize;
|
||||
_test = false;
|
||||
return constraint;
|
||||
}
|
||||
|
||||
private static Size ConvertThickness2Size(Thickness th) => new(th.Left + th.Right, th.Top + th.Bottom);
|
||||
var child = Child;
|
||||
var borderThickness = BorderThickness;
|
||||
var padding = Padding;
|
||||
|
||||
if (UseLayoutRounding)
|
||||
{
|
||||
var dpiScaleX = DpiHelper.DeviceDpiX;
|
||||
var dpiScaleY = DpiHelper.DeviceDpiY;
|
||||
|
||||
borderThickness = new Thickness(
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Left, dpiScaleX),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Top, dpiScaleY),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Right, dpiScaleX),
|
||||
DpiHelper.RoundLayoutValue(borderThickness.Bottom, dpiScaleY));
|
||||
}
|
||||
|
||||
var borderSize = ConvertThickness2Size(borderThickness);
|
||||
var paddingSize = ConvertThickness2Size(padding);
|
||||
var mySize = new Size();
|
||||
|
||||
if (child != null)
|
||||
{
|
||||
var combined = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height);
|
||||
var borderConstraint = new Size(Math.Max(0.0, constraint.Width - combined.Width), Math.Max(0.0, constraint.Height - combined.Height));
|
||||
var childConstraint = new Size(Math.Max(0.0, double.PositiveInfinity - combined.Width), Math.Max(0.0, double.PositiveInfinity - combined.Height));
|
||||
|
||||
|
||||
child.Measure(borderConstraint);
|
||||
var childSize = child.DesiredSize;
|
||||
|
||||
mySize.Width = childSize.Width + combined.Width;
|
||||
mySize.Height = childSize.Height + combined.Height;
|
||||
|
||||
child.Measure(childConstraint);
|
||||
}
|
||||
else
|
||||
{
|
||||
mySize = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height);
|
||||
}
|
||||
|
||||
return mySize;
|
||||
}
|
||||
|
||||
private static Size ConvertThickness2Size(Thickness th) => new(th.Left + th.Right, th.Top + th.Bottom);
|
||||
}
|
||||
@@ -3,57 +3,56 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 切换块
|
||||
/// </summary>
|
||||
public class ToggleBlock : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// 切换块
|
||||
/// </summary>
|
||||
public class ToggleBlock : Control
|
||||
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(
|
||||
"IsChecked", typeof(bool?), typeof(ToggleBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox,
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal));
|
||||
|
||||
[Category("Appearance")]
|
||||
[TypeConverter(typeof(NullableBoolConverter))]
|
||||
[Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
|
||||
public bool? IsChecked
|
||||
{
|
||||
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(
|
||||
"IsChecked", typeof(bool?), typeof(ToggleBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox,
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal));
|
||||
|
||||
[Category("Appearance")]
|
||||
[TypeConverter(typeof(NullableBoolConverter))]
|
||||
[Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
|
||||
public bool? IsChecked
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
// Because Nullable<bool> unboxing is very slow (uses reflection) first we cast to bool
|
||||
var value = GetValue(IsCheckedProperty);
|
||||
// ReSharper disable once RedundantExplicitNullableCreation
|
||||
return value == null ? new bool?() : new bool?((bool) value);
|
||||
}
|
||||
set => SetValue(IsCheckedProperty, value.HasValue ? ValueBoxes.BooleanBox(value.Value) : null);
|
||||
// Because Nullable<bool> unboxing is very slow (uses reflection) first we cast to bool
|
||||
var value = GetValue(IsCheckedProperty);
|
||||
// ReSharper disable once RedundantExplicitNullableCreation
|
||||
return value == null ? new bool?() : new bool?((bool) value);
|
||||
}
|
||||
set => SetValue(IsCheckedProperty, value.HasValue ? ValueBoxes.BooleanBox(value.Value) : null);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CheckedContentProperty = DependencyProperty.Register(
|
||||
"CheckedContent", typeof(object), typeof(ToggleBlock), new PropertyMetadata(default(object)));
|
||||
public static readonly DependencyProperty CheckedContentProperty = DependencyProperty.Register(
|
||||
"CheckedContent", typeof(object), typeof(ToggleBlock), new PropertyMetadata(default(object)));
|
||||
|
||||
public object CheckedContent
|
||||
{
|
||||
get => GetValue(CheckedContentProperty);
|
||||
set => SetValue(CheckedContentProperty, value);
|
||||
}
|
||||
public object CheckedContent
|
||||
{
|
||||
get => GetValue(CheckedContentProperty);
|
||||
set => SetValue(CheckedContentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UnCheckedContentProperty = DependencyProperty.Register(
|
||||
"UnCheckedContent", typeof(object), typeof(ToggleBlock), new PropertyMetadata(default(object)));
|
||||
public static readonly DependencyProperty UnCheckedContentProperty = DependencyProperty.Register(
|
||||
"UnCheckedContent", typeof(object), typeof(ToggleBlock), new PropertyMetadata(default(object)));
|
||||
|
||||
public object UnCheckedContent
|
||||
{
|
||||
get => GetValue(UnCheckedContentProperty);
|
||||
set => SetValue(UnCheckedContentProperty, value);
|
||||
}
|
||||
public object UnCheckedContent
|
||||
{
|
||||
get => GetValue(UnCheckedContentProperty);
|
||||
set => SetValue(UnCheckedContentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IndeterminateContentProperty = DependencyProperty.Register(
|
||||
"IndeterminateContent", typeof(object), typeof(ToggleBlock), new PropertyMetadata(default(object)));
|
||||
public static readonly DependencyProperty IndeterminateContentProperty = DependencyProperty.Register(
|
||||
"IndeterminateContent", typeof(object), typeof(ToggleBlock), new PropertyMetadata(default(object)));
|
||||
|
||||
public object IndeterminateContent
|
||||
{
|
||||
get => GetValue(IndeterminateContentProperty);
|
||||
set => SetValue(IndeterminateContentProperty, value);
|
||||
}
|
||||
public object IndeterminateContent
|
||||
{
|
||||
get => GetValue(IndeterminateContentProperty);
|
||||
set => SetValue(IndeterminateContentProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,40 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ButtonGroup : ItemsControl
|
||||
{
|
||||
public class ButtonGroup : ItemsControl
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is Button or RadioButton or ToggleButton;
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(ButtonGroup), new PropertyMetadata(default(Orientation)));
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is Button || item is RadioButton || item is ToggleButton;
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(ButtonGroup), new PropertyMetadata(default(Orientation)));
|
||||
public static readonly DependencyProperty LayoutProperty = DependencyProperty.Register(
|
||||
"Layout", typeof(LinearLayout), typeof(ButtonGroup), new PropertyMetadata(LinearLayout.Uniform));
|
||||
|
||||
public Orientation Orientation
|
||||
public LinearLayout Layout
|
||||
{
|
||||
get => (LinearLayout) GetValue(LayoutProperty);
|
||||
set => SetValue(LayoutProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
var count = Items.Count;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
|
||||
{
|
||||
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
|
||||
|
||||
var count = Items.Count;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var item = (ButtonBase) Items[i];
|
||||
item.Style = ItemContainerStyleSelector?.SelectStyle(item, this);
|
||||
}
|
||||
var item = (ButtonBase) Items[i];
|
||||
item.Style = ItemContainerStyleSelector?.SelectStyle(item, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,22 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// 带上下文菜单的按钮
|
||||
/// </summary>
|
||||
public class ContextMenuButton : Button
|
||||
{
|
||||
public ContextMenu Menu { get; set; }
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
protected override void OnClick()
|
||||
/// <summary>
|
||||
/// 带上下文菜单的按钮
|
||||
/// </summary>
|
||||
public class ContextMenuButton : Button
|
||||
{
|
||||
public ContextMenu Menu { get; set; }
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
base.OnClick();
|
||||
if (Menu != null)
|
||||
{
|
||||
base.OnClick();
|
||||
if (Menu != null)
|
||||
{
|
||||
Menu.PlacementTarget = this;
|
||||
Menu.IsOpen = true;
|
||||
}
|
||||
Menu.PlacementTarget = this;
|
||||
Menu.IsOpen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,29 +2,28 @@
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// 带上下文菜单的切换按钮
|
||||
/// </summary>
|
||||
public class ContextMenuToggleButton : ToggleButton
|
||||
{
|
||||
public ContextMenu Menu { get; set; }
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
protected override void OnClick()
|
||||
/// <summary>
|
||||
/// 带上下文菜单的切换按钮
|
||||
/// </summary>
|
||||
public class ContextMenuToggleButton : ToggleButton
|
||||
{
|
||||
public ContextMenu Menu { get; set; }
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
base.OnClick();
|
||||
if (Menu != null)
|
||||
{
|
||||
base.OnClick();
|
||||
if (Menu != null)
|
||||
if (IsChecked == true)
|
||||
{
|
||||
if (IsChecked == true)
|
||||
{
|
||||
Menu.PlacementTarget = this;
|
||||
Menu.IsOpen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu.IsOpen = false;
|
||||
}
|
||||
Menu.PlacementTarget = this;
|
||||
Menu.IsOpen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu.IsOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,26 +2,25 @@
|
||||
using System.Windows.Controls.Primitives;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ProgressButton : ToggleButton
|
||||
{
|
||||
public class ProgressButton : ToggleButton
|
||||
public static readonly DependencyProperty ProgressStyleProperty = DependencyProperty.Register(
|
||||
"ProgressStyle", typeof(Style), typeof(ProgressButton), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style ProgressStyle
|
||||
{
|
||||
public static readonly DependencyProperty ProgressStyleProperty = DependencyProperty.Register(
|
||||
"ProgressStyle", typeof(Style), typeof(ProgressButton), new PropertyMetadata(default(Style)));
|
||||
get => (Style) GetValue(ProgressStyleProperty);
|
||||
set => SetValue(ProgressStyleProperty, value);
|
||||
}
|
||||
|
||||
public Style ProgressStyle
|
||||
{
|
||||
get => (Style) GetValue(ProgressStyleProperty);
|
||||
set => SetValue(ProgressStyleProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register(
|
||||
"Progress", typeof(double), typeof(ProgressButton), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register(
|
||||
"Progress", typeof(double), typeof(ProgressButton), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double Progress
|
||||
{
|
||||
get => (double) GetValue(ProgressProperty);
|
||||
set => SetValue(ProgressProperty, value);
|
||||
}
|
||||
public double Progress
|
||||
{
|
||||
get => (double) GetValue(ProgressProperty);
|
||||
set => SetValue(ProgressProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -5,77 +5,76 @@ using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Data.Enum;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class SplitButton : ButtonBase
|
||||
{
|
||||
public class SplitButton : ButtonBase
|
||||
public static readonly DependencyProperty HitModeProperty = DependencyProperty.Register(
|
||||
"HitMode", typeof(HitMode), typeof(SplitButton), new PropertyMetadata(default(HitMode)));
|
||||
|
||||
public HitMode HitMode
|
||||
{
|
||||
public static readonly DependencyProperty HitModeProperty = DependencyProperty.Register(
|
||||
"HitMode", typeof(HitMode), typeof(SplitButton), new PropertyMetadata(default(HitMode)));
|
||||
get => (HitMode) GetValue(HitModeProperty);
|
||||
set => SetValue(HitModeProperty, value);
|
||||
}
|
||||
|
||||
public HitMode HitMode
|
||||
public static readonly DependencyProperty MaxDropDownHeightProperty = DependencyProperty.Register(
|
||||
"MaxDropDownHeight", typeof(double), typeof(SplitButton), new PropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0));
|
||||
|
||||
public double MaxDropDownHeight
|
||||
{
|
||||
get => (double) GetValue(MaxDropDownHeightProperty);
|
||||
set => SetValue(MaxDropDownHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
|
||||
"IsDropDownOpen", typeof(bool), typeof(SplitButton), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsDropDownOpen
|
||||
{
|
||||
get => (bool) GetValue(IsDropDownOpenProperty);
|
||||
set => SetValue(IsDropDownOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DropDownContentProperty = DependencyProperty.Register(
|
||||
"DropDownContent", typeof(object), typeof(SplitButton), new PropertyMetadata(default(object)));
|
||||
|
||||
public object DropDownContent
|
||||
{
|
||||
get => GetValue(DropDownContentProperty);
|
||||
set => SetValue(DropDownContentProperty, value);
|
||||
}
|
||||
|
||||
public SplitButton()
|
||||
{
|
||||
AddHandler(MenuItem.ClickEvent, new RoutedEventHandler(ItemsOnClick));
|
||||
}
|
||||
|
||||
private void ItemsOnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is MenuItem)
|
||||
{
|
||||
get => (HitMode) GetValue(HitModeProperty);
|
||||
set => SetValue(HitModeProperty, value);
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaxDropDownHeightProperty = DependencyProperty.Register(
|
||||
"MaxDropDownHeight", typeof(double), typeof(SplitButton), new PropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0));
|
||||
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnPreviewMouseLeftButtonDown(e);
|
||||
|
||||
public double MaxDropDownHeight
|
||||
if (HitMode == HitMode.Hover)
|
||||
{
|
||||
get => (double) GetValue(MaxDropDownHeightProperty);
|
||||
set => SetValue(MaxDropDownHeightProperty, value);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
|
||||
"IsDropDownOpen", typeof(bool), typeof(SplitButton), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
protected override void OnMouseEnter(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseEnter(e);
|
||||
|
||||
public bool IsDropDownOpen
|
||||
if (HitMode == HitMode.Hover)
|
||||
{
|
||||
get => (bool) GetValue(IsDropDownOpenProperty);
|
||||
set => SetValue(IsDropDownOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DropDownContentProperty = DependencyProperty.Register(
|
||||
"DropDownContent", typeof(object), typeof(SplitButton), new PropertyMetadata(default(object)));
|
||||
|
||||
public object DropDownContent
|
||||
{
|
||||
get => GetValue(DropDownContentProperty);
|
||||
set => SetValue(DropDownContentProperty, value);
|
||||
}
|
||||
|
||||
public SplitButton()
|
||||
{
|
||||
AddHandler(MenuItem.ClickEvent, new RoutedEventHandler(ItemsOnClick));
|
||||
}
|
||||
|
||||
private void ItemsOnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is MenuItem)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnPreviewMouseLeftButtonDown(e);
|
||||
|
||||
if (HitMode == HitMode.Hover)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseEnter(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseEnter(e);
|
||||
|
||||
if (HitMode == HitMode.Hover)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,443 +14,442 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 轮播控件
|
||||
/// </summary>
|
||||
[DefaultProperty("Items")]
|
||||
[ContentProperty("Items")]
|
||||
[TemplatePart(Name = ElementPanelPage, Type = typeof(Panel))]
|
||||
public class Carousel : SimpleItemsControl, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 轮播控件
|
||||
/// </summary>
|
||||
[DefaultProperty("Items")]
|
||||
[ContentProperty("Items")]
|
||||
[TemplatePart(Name = ElementPanelPage, Type = typeof(Panel))]
|
||||
public class Carousel : SimpleItemsControl, IDisposable
|
||||
#region Constants
|
||||
|
||||
private const string ElementPanelPage = "PART_PanelPage";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Data
|
||||
|
||||
private bool _isDisposed;
|
||||
|
||||
private Panel _panelPage;
|
||||
|
||||
private bool _appliedTemplate;
|
||||
|
||||
private int _pageIndex = -1;
|
||||
|
||||
private RadioButton _selectedButton;
|
||||
|
||||
private DispatcherTimer _updateTimer;
|
||||
|
||||
private readonly List<double> _widthList = new();
|
||||
|
||||
private readonly Dictionary<object, CarouselItem> _entryDic = new();
|
||||
|
||||
private bool _isRefresh;
|
||||
|
||||
private IEnumerable _itemsSourceInternal;
|
||||
|
||||
#endregion Data
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
#region Constants
|
||||
_appliedTemplate = false;
|
||||
|
||||
private const string ElementPanelPage = "PART_PanelPage";
|
||||
_panelPage?.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonPages_OnClick));
|
||||
|
||||
#endregion Constants
|
||||
base.OnApplyTemplate();
|
||||
|
||||
#region Data
|
||||
_panelPage = GetTemplateChild(ElementPanelPage) as Panel;
|
||||
|
||||
private bool _isDisposed;
|
||||
if (!CheckNull()) return;
|
||||
|
||||
private Panel _panelPage;
|
||||
_panelPage.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonPages_OnClick));
|
||||
_appliedTemplate = true;
|
||||
Update();
|
||||
}
|
||||
|
||||
private bool _appliedTemplate;
|
||||
private void Update()
|
||||
{
|
||||
TimerSwitch(AutoRun);
|
||||
UpdatePageButtons(_pageIndex);
|
||||
}
|
||||
|
||||
private int _pageIndex = -1;
|
||||
private bool CheckNull() => _panelPage != null;
|
||||
|
||||
private RadioButton _selectedButton;
|
||||
|
||||
private DispatcherTimer _updateTimer;
|
||||
|
||||
private readonly List<double> _widthList = new();
|
||||
|
||||
private readonly Dictionary<object, CarouselItem> _entryDic = new();
|
||||
|
||||
private bool _isRefresh;
|
||||
|
||||
private IEnumerable _itemsSourceInternal;
|
||||
|
||||
#endregion Data
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
public static readonly DependencyProperty AutoRunProperty = DependencyProperty.Register(
|
||||
"AutoRun", typeof(bool), typeof(Carousel), new PropertyMetadata(ValueBoxes.FalseBox, (o, args) =>
|
||||
{
|
||||
_appliedTemplate = false;
|
||||
var ctl = (Carousel) o;
|
||||
ctl.TimerSwitch((bool) args.NewValue);
|
||||
}));
|
||||
|
||||
_panelPage?.RemoveHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonPages_OnClick));
|
||||
public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register(
|
||||
"Interval", typeof(TimeSpan), typeof(Carousel), new PropertyMetadata(TimeSpan.FromSeconds(2)));
|
||||
|
||||
base.OnApplyTemplate();
|
||||
public static readonly DependencyProperty ExtendWidthProperty = DependencyProperty.Register(
|
||||
"ExtendWidth", typeof(double), typeof(Carousel), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
_panelPage = GetTemplateChild(ElementPanelPage) as Panel;
|
||||
public double ExtendWidth
|
||||
{
|
||||
get => (double) GetValue(ExtendWidthProperty);
|
||||
set => SetValue(ExtendWidthProperty, value);
|
||||
}
|
||||
|
||||
if (!CheckNull()) return;
|
||||
public static readonly DependencyProperty IsCenterProperty = DependencyProperty.Register(
|
||||
"IsCenter", typeof(bool), typeof(Carousel), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
_panelPage.AddHandler(ButtonBase.ClickEvent, new RoutedEventHandler(ButtonPages_OnClick));
|
||||
_appliedTemplate = true;
|
||||
Update();
|
||||
}
|
||||
public bool IsCenter
|
||||
{
|
||||
get => (bool) GetValue(IsCenterProperty);
|
||||
set => SetValue(IsCenterProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private void Update()
|
||||
public static readonly DependencyProperty PageButtonStyleProperty = DependencyProperty.Register(
|
||||
"PageButtonStyle", typeof(Style), typeof(Carousel), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style PageButtonStyle
|
||||
{
|
||||
get => (Style) GetValue(PageButtonStyleProperty);
|
||||
set => SetValue(PageButtonStyleProperty, value);
|
||||
}
|
||||
|
||||
public Carousel()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Prev, ButtonPrev_OnClick));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Next, ButtonNext_OnClick));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Selected, ButtonPages_OnClick));
|
||||
|
||||
Loaded += (s, e) => UpdatePageButtons();
|
||||
IsVisibleChanged += Carousel_IsVisibleChanged;
|
||||
}
|
||||
|
||||
~Carousel() => Dispose();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
|
||||
IsVisibleChanged -= Carousel_IsVisibleChanged;
|
||||
_updateTimer?.Stop();
|
||||
_isDisposed = true;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Carousel_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (_updateTimer == null) return;
|
||||
|
||||
if (IsVisible)
|
||||
{
|
||||
TimerSwitch(AutoRun);
|
||||
UpdatePageButtons(_pageIndex);
|
||||
}
|
||||
|
||||
private bool CheckNull() => _panelPage != null;
|
||||
|
||||
public static readonly DependencyProperty AutoRunProperty = DependencyProperty.Register(
|
||||
"AutoRun", typeof(bool), typeof(Carousel), new PropertyMetadata(ValueBoxes.FalseBox, (o, args) =>
|
||||
{
|
||||
var ctl = (Carousel) o;
|
||||
ctl.TimerSwitch((bool) args.NewValue);
|
||||
}));
|
||||
|
||||
public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register(
|
||||
"Interval", typeof(TimeSpan), typeof(Carousel), new PropertyMetadata(TimeSpan.FromSeconds(2)));
|
||||
|
||||
public static readonly DependencyProperty ExtendWidthProperty = DependencyProperty.Register(
|
||||
"ExtendWidth", typeof(double), typeof(Carousel), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double ExtendWidth
|
||||
{
|
||||
get => (double) GetValue(ExtendWidthProperty);
|
||||
set => SetValue(ExtendWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsCenterProperty = DependencyProperty.Register(
|
||||
"IsCenter", typeof(bool), typeof(Carousel), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsCenter
|
||||
{
|
||||
get => (bool) GetValue(IsCenterProperty);
|
||||
set => SetValue(IsCenterProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PageButtonStyleProperty = DependencyProperty.Register(
|
||||
"PageButtonStyle", typeof(Style), typeof(Carousel), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style PageButtonStyle
|
||||
{
|
||||
get => (Style) GetValue(PageButtonStyleProperty);
|
||||
set => SetValue(PageButtonStyleProperty, value);
|
||||
}
|
||||
|
||||
public Carousel()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Prev, ButtonPrev_OnClick));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Next, ButtonNext_OnClick));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Selected, ButtonPages_OnClick));
|
||||
|
||||
Loaded += (s, e) => UpdatePageButtons();
|
||||
IsVisibleChanged += Carousel_IsVisibleChanged;
|
||||
}
|
||||
|
||||
~Carousel() => Dispose();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
|
||||
IsVisibleChanged -= Carousel_IsVisibleChanged;
|
||||
_updateTimer?.Stop();
|
||||
_isDisposed = true;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Carousel_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (_updateTimer == null) return;
|
||||
|
||||
if (IsVisible)
|
||||
{
|
||||
_updateTimer.Tick += UpdateTimer_Tick;
|
||||
_updateTimer.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
_updateTimer.Stop();
|
||||
_updateTimer.Tick -= UpdateTimer_Tick;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否自动跳转
|
||||
/// </summary>
|
||||
public bool AutoRun
|
||||
{
|
||||
get => (bool) GetValue(AutoRunProperty);
|
||||
set => SetValue(AutoRunProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 跳转时间间隔
|
||||
/// </summary>
|
||||
public TimeSpan Interval
|
||||
{
|
||||
get => (TimeSpan) GetValue(IntervalProperty);
|
||||
set => SetValue(IntervalProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// </summary>
|
||||
public int PageIndex
|
||||
{
|
||||
get => _pageIndex;
|
||||
set
|
||||
{
|
||||
if (Items.Count == 0) return;
|
||||
if (_pageIndex == value) return;
|
||||
if (value < 0)
|
||||
_pageIndex = Items.Count - 1;
|
||||
else if (value >= Items.Count)
|
||||
_pageIndex = 0;
|
||||
else
|
||||
_pageIndex = value;
|
||||
UpdatePageButtons(_pageIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计时器开关
|
||||
/// </summary>
|
||||
private void TimerSwitch(bool run)
|
||||
{
|
||||
if (!_appliedTemplate) return;
|
||||
|
||||
if (_updateTimer != null)
|
||||
{
|
||||
_updateTimer.Tick -= UpdateTimer_Tick;
|
||||
_updateTimer.Stop();
|
||||
_updateTimer = null;
|
||||
}
|
||||
|
||||
if (!run) return;
|
||||
_updateTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = Interval
|
||||
};
|
||||
_updateTimer.Tick += UpdateTimer_Tick;
|
||||
_updateTimer.Start();
|
||||
}
|
||||
|
||||
private void UpdateTimer_Tick(object sender, EventArgs e)
|
||||
else
|
||||
{
|
||||
if (IsMouseOver) return;
|
||||
PageIndex++;
|
||||
_updateTimer.Stop();
|
||||
_updateTimer.Tick -= UpdateTimer_Tick;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新页按钮
|
||||
/// </summary>
|
||||
public void UpdatePageButtons(int index = -1)
|
||||
/// <summary>
|
||||
/// 是否自动跳转
|
||||
/// </summary>
|
||||
public bool AutoRun
|
||||
{
|
||||
get => (bool) GetValue(AutoRunProperty);
|
||||
set => SetValue(AutoRunProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 跳转时间间隔
|
||||
/// </summary>
|
||||
public TimeSpan Interval
|
||||
{
|
||||
get => (TimeSpan) GetValue(IntervalProperty);
|
||||
set => SetValue(IntervalProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// </summary>
|
||||
public int PageIndex
|
||||
{
|
||||
get => _pageIndex;
|
||||
set
|
||||
{
|
||||
if (!CheckNull()) return;
|
||||
if (!_appliedTemplate) return;
|
||||
|
||||
var count = Items.Count;
|
||||
_widthList.Clear();
|
||||
_widthList.Add(0);
|
||||
var width = .0;
|
||||
foreach (FrameworkElement item in ItemsHost.Children)
|
||||
{
|
||||
item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
width += item.DesiredSize.Width;
|
||||
_widthList.Add(width);
|
||||
}
|
||||
|
||||
ItemsHost.Width = _widthList.Last() + ExtendWidth;
|
||||
_panelPage.Children.Clear();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
_panelPage.Children.Add(new RadioButton
|
||||
{
|
||||
Style = PageButtonStyle
|
||||
});
|
||||
}
|
||||
|
||||
if (index == -1 && count > 0) index = 0;
|
||||
if (index >= 0 && index < count)
|
||||
{
|
||||
if (_panelPage.Children[index] is RadioButton button)
|
||||
{
|
||||
button.IsChecked = true;
|
||||
button.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent, button));
|
||||
UpdateItemsPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新项的位置
|
||||
/// </summary>
|
||||
private void UpdateItemsPosition()
|
||||
{
|
||||
if (!CheckNull()) return;
|
||||
if (!_appliedTemplate) return;
|
||||
if (Items.Count == 0) return;
|
||||
if (!IsCenter)
|
||||
if (_pageIndex == value) return;
|
||||
if (value < 0)
|
||||
_pageIndex = Items.Count - 1;
|
||||
else if (value >= Items.Count)
|
||||
_pageIndex = 0;
|
||||
else
|
||||
_pageIndex = value;
|
||||
UpdatePageButtons(_pageIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计时器开关
|
||||
/// </summary>
|
||||
private void TimerSwitch(bool run)
|
||||
{
|
||||
if (!_appliedTemplate) return;
|
||||
|
||||
if (_updateTimer != null)
|
||||
{
|
||||
_updateTimer.Tick -= UpdateTimer_Tick;
|
||||
_updateTimer.Stop();
|
||||
_updateTimer = null;
|
||||
}
|
||||
|
||||
if (!run) return;
|
||||
_updateTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = Interval
|
||||
};
|
||||
_updateTimer.Tick += UpdateTimer_Tick;
|
||||
_updateTimer.Start();
|
||||
}
|
||||
|
||||
private void UpdateTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (IsMouseOver) return;
|
||||
PageIndex++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新页按钮
|
||||
/// </summary>
|
||||
public void UpdatePageButtons(int index = -1)
|
||||
{
|
||||
if (!CheckNull()) return;
|
||||
if (!_appliedTemplate) return;
|
||||
|
||||
var count = Items.Count;
|
||||
_widthList.Clear();
|
||||
_widthList.Add(0);
|
||||
var width = .0;
|
||||
foreach (FrameworkElement item in ItemsHost.Children)
|
||||
{
|
||||
item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
width += item.DesiredSize.Width;
|
||||
_widthList.Add(width);
|
||||
}
|
||||
|
||||
ItemsHost.Width = _widthList.Last() + ExtendWidth;
|
||||
_panelPage.Children.Clear();
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
_panelPage.Children.Add(new RadioButton
|
||||
{
|
||||
ItemsHost.BeginAnimation(MarginProperty,
|
||||
AnimationHelper.CreateAnimation(new Thickness(-_widthList[PageIndex], 0, 0, 0)));
|
||||
Style = PageButtonStyle
|
||||
});
|
||||
}
|
||||
|
||||
if (index == -1 && count > 0) index = 0;
|
||||
if (index >= 0 && index < count)
|
||||
{
|
||||
if (_panelPage.Children[index] is RadioButton button)
|
||||
{
|
||||
button.IsChecked = true;
|
||||
button.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent, button));
|
||||
UpdateItemsPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新项的位置
|
||||
/// </summary>
|
||||
private void UpdateItemsPosition()
|
||||
{
|
||||
if (!CheckNull()) return;
|
||||
if (!_appliedTemplate) return;
|
||||
if (Items.Count == 0) return;
|
||||
if (!IsCenter)
|
||||
{
|
||||
ItemsHost.BeginAnimation(MarginProperty,
|
||||
AnimationHelper.CreateAnimation(new Thickness(-_widthList[PageIndex], 0, 0, 0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
var ctl = (FrameworkElement) ItemsHost.Children[PageIndex];
|
||||
var ctlWidth = ctl.DesiredSize.Width;
|
||||
ItemsHost.BeginAnimation(MarginProperty,
|
||||
AnimationHelper.CreateAnimation(
|
||||
new Thickness(-_widthList[PageIndex] + (ActualWidth - ctlWidth) / 2, 0, 0, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
UpdateItemsPosition();
|
||||
}
|
||||
|
||||
private void ButtonPages_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!CheckNull()) return;
|
||||
|
||||
_selectedButton = e.OriginalSource as RadioButton;
|
||||
|
||||
var index = _panelPage.Children.IndexOf(_selectedButton);
|
||||
if (index != -1)
|
||||
{
|
||||
PageIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
private void ButtonPrev_OnClick(object sender, RoutedEventArgs e) => PageIndex--;
|
||||
|
||||
private void ButtonNext_OnClick(object sender, RoutedEventArgs e) => PageIndex++;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new CarouselItem();
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is CarouselItem;
|
||||
|
||||
private void ClearItems()
|
||||
{
|
||||
ItemsHost?.Children.Clear();
|
||||
_entryDic.Clear();
|
||||
}
|
||||
|
||||
private void RemoveItem(object item)
|
||||
{
|
||||
if (_entryDic.TryGetValue(item, out var entry))
|
||||
{
|
||||
ItemsHost.Children.Remove(entry);
|
||||
Items.Remove(item);
|
||||
_entryDic.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Refresh()
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
_entryDic.Clear();
|
||||
_isRefresh = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
AddItem(item);
|
||||
}
|
||||
|
||||
_isRefresh = false;
|
||||
}
|
||||
|
||||
private void AddItem(object item) => InsertItem(_entryDic.Count, item);
|
||||
|
||||
private void InsertItem(int index, object item)
|
||||
{
|
||||
if (ItemsHost == null)
|
||||
{
|
||||
Items.Insert(index, item);
|
||||
_entryDic.Add(item, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
DependencyObject container;
|
||||
if (IsItemItsOwnContainerOverride(item))
|
||||
{
|
||||
container = item as DependencyObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ctl = (FrameworkElement) ItemsHost.Children[PageIndex];
|
||||
var ctlWidth = ctl.DesiredSize.Width;
|
||||
ItemsHost.BeginAnimation(MarginProperty,
|
||||
AnimationHelper.CreateAnimation(
|
||||
new Thickness(-_widthList[PageIndex] + (ActualWidth - ctlWidth) / 2, 0, 0, 0)));
|
||||
container = GetContainerForItemOverride();
|
||||
PrepareContainerForItemOverride(container, item);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
UpdateItemsPosition();
|
||||
}
|
||||
|
||||
private void ButtonPages_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!CheckNull()) return;
|
||||
|
||||
_selectedButton = e.OriginalSource as RadioButton;
|
||||
|
||||
var index = _panelPage.Children.IndexOf(_selectedButton);
|
||||
if (index != -1)
|
||||
if (container is CarouselItem element)
|
||||
{
|
||||
PageIndex = index;
|
||||
element.Style = ItemContainerStyle;
|
||||
_entryDic[item] = element;
|
||||
ItemsHost.Children.Insert(index, element);
|
||||
|
||||
if (IsLoaded && !_isRefresh && _itemsSourceInternal != null)
|
||||
{
|
||||
Items.Insert(index, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ButtonPrev_OnClick(object sender, RoutedEventArgs e) => PageIndex--;
|
||||
|
||||
private void ButtonNext_OnClick(object sender, RoutedEventArgs e) => PageIndex++;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new CarouselItem();
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is CarouselItem;
|
||||
|
||||
private void ClearItems()
|
||||
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
|
||||
{
|
||||
if (_itemsSourceInternal != null)
|
||||
{
|
||||
ItemsHost?.Children.Clear();
|
||||
_entryDic.Clear();
|
||||
}
|
||||
|
||||
private void RemoveItem(object item)
|
||||
{
|
||||
if (_entryDic.TryGetValue(item, out var entry))
|
||||
if (_itemsSourceInternal is INotifyCollectionChanged s)
|
||||
{
|
||||
ItemsHost.Children.Remove(entry);
|
||||
Items.Remove(item);
|
||||
_entryDic.Remove(item);
|
||||
s.CollectionChanged -= InternalCollectionChanged;
|
||||
}
|
||||
|
||||
Items.Clear();
|
||||
ClearItems();
|
||||
}
|
||||
|
||||
protected override void Refresh()
|
||||
_itemsSourceInternal = newValue;
|
||||
if (_itemsSourceInternal != null)
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
_entryDic.Clear();
|
||||
_isRefresh = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
if (_itemsSourceInternal is INotifyCollectionChanged s)
|
||||
{
|
||||
s.CollectionChanged += InternalCollectionChanged;
|
||||
}
|
||||
foreach (var item in _itemsSourceInternal)
|
||||
{
|
||||
AddItem(item);
|
||||
}
|
||||
|
||||
_isRefresh = false;
|
||||
}
|
||||
|
||||
private void AddItem(object item) => InsertItem(_entryDic.Count, item);
|
||||
|
||||
private void InsertItem(int index, object item)
|
||||
{
|
||||
if (ItemsHost == null)
|
||||
{
|
||||
Items.Insert(index, item);
|
||||
_entryDic.Add(item, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
DependencyObject container;
|
||||
if (IsItemItsOwnContainerOverride(item))
|
||||
{
|
||||
container = item as DependencyObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
container = GetContainerForItemOverride();
|
||||
PrepareContainerForItemOverride(container, item);
|
||||
}
|
||||
|
||||
if (container is CarouselItem element)
|
||||
{
|
||||
element.Style = ItemContainerStyle;
|
||||
_entryDic[item] = element;
|
||||
ItemsHost.Children.Insert(index, element);
|
||||
|
||||
if (IsLoaded && !_isRefresh && _itemsSourceInternal != null)
|
||||
{
|
||||
Items.Insert(index, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
|
||||
{
|
||||
if (_itemsSourceInternal != null)
|
||||
{
|
||||
if (_itemsSourceInternal is INotifyCollectionChanged s)
|
||||
{
|
||||
s.CollectionChanged -= InternalCollectionChanged;
|
||||
}
|
||||
|
||||
Items.Clear();
|
||||
ClearItems();
|
||||
}
|
||||
_itemsSourceInternal = newValue;
|
||||
if (_itemsSourceInternal != null)
|
||||
{
|
||||
if (_itemsSourceInternal is INotifyCollectionChanged s)
|
||||
{
|
||||
s.CollectionChanged += InternalCollectionChanged;
|
||||
}
|
||||
foreach (var item in _itemsSourceInternal)
|
||||
{
|
||||
AddItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InternalCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
if (_entryDic.Count == 0) return;
|
||||
ClearItems();
|
||||
Items.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (var item in e.OldItems)
|
||||
{
|
||||
RemoveItem(item);
|
||||
}
|
||||
}
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
var count = 0;
|
||||
foreach (var item in e.NewItems)
|
||||
{
|
||||
var index = e.NewStartingIndex + count++;
|
||||
InsertItem(index, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (_itemsSourceInternal != null) return;
|
||||
|
||||
InternalCollectionChanged(sender, e);
|
||||
}
|
||||
|
||||
protected override void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void InternalCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
if (_entryDic.Count == 0) return;
|
||||
ClearItems();
|
||||
Items.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (var item in e.OldItems)
|
||||
{
|
||||
RemoveItem(item);
|
||||
}
|
||||
}
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
var count = 0;
|
||||
foreach (var item in e.NewItems)
|
||||
{
|
||||
var index = e.NewStartingIndex + count++;
|
||||
InsertItem(index, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (_itemsSourceInternal != null) return;
|
||||
|
||||
InternalCollectionChanged(sender, e);
|
||||
}
|
||||
|
||||
protected override void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class CarouselItem : ContentControl
|
||||
{
|
||||
public class CarouselItem : ContentControl
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,101 +6,100 @@ using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
internal class ColorDropper
|
||||
{
|
||||
internal class ColorDropper
|
||||
private bool _cursorIsSetted;
|
||||
|
||||
private Cursor _dropperCursor;
|
||||
|
||||
private readonly ColorPicker _colorPicker;
|
||||
|
||||
public ColorDropper(ColorPicker colorPicker)
|
||||
{
|
||||
private bool _cursorIsSetted;
|
||||
_colorPicker = colorPicker;
|
||||
}
|
||||
|
||||
private Cursor _dropperCursor;
|
||||
|
||||
private readonly ColorPicker _colorPicker;
|
||||
|
||||
public ColorDropper(ColorPicker colorPicker)
|
||||
public void Update(bool isShow)
|
||||
{
|
||||
if (isShow)
|
||||
{
|
||||
_colorPicker = colorPicker;
|
||||
}
|
||||
|
||||
public void Update(bool isShow)
|
||||
{
|
||||
if (isShow)
|
||||
if (_dropperCursor == null)
|
||||
{
|
||||
if (_dropperCursor == null)
|
||||
var info = Application.GetResourceStream(new Uri("pack://application:,,,/HandyControl;Component/Resources/dropper.cur"));
|
||||
if (info != null)
|
||||
{
|
||||
var info = Application.GetResourceStream(new Uri("pack://application:,,,/HandyControl;Component/Resources/dropper.cur"));
|
||||
if (info != null)
|
||||
{
|
||||
_dropperCursor = new Cursor(info.Stream);
|
||||
}
|
||||
}
|
||||
|
||||
if (_dropperCursor == null) return;
|
||||
|
||||
MouseHook.Start();
|
||||
MouseHook.StatusChanged += MouseHook_StatusChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
Mouse.OverrideCursor = Cursors.Arrow;
|
||||
MouseHook.Stop();
|
||||
MouseHook.StatusChanged -= MouseHook_StatusChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void MouseHook_StatusChanged(object sender, MouseHookEventArgs e)
|
||||
{
|
||||
var window = System.Windows.Window.GetWindow(_colorPicker);
|
||||
if (window == null)
|
||||
{
|
||||
UpdateCursor(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_colorPicker.IsMouseOver && window.IsMouseOver)
|
||||
{
|
||||
UpdateCursor(true);
|
||||
if (e.MessageType == MouseHookMessageType.LeftButtonDown)
|
||||
{
|
||||
var brush = new SolidColorBrush(GetColorAt(e.Point.X, e.Point.Y));
|
||||
_colorPicker.SelectedBrush = brush;
|
||||
_dropperCursor = new Cursor(info.Stream);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateCursor(false);
|
||||
}
|
||||
|
||||
if (_dropperCursor == null) return;
|
||||
|
||||
MouseHook.Start();
|
||||
MouseHook.StatusChanged += MouseHook_StatusChanged;
|
||||
}
|
||||
|
||||
private void UpdateCursor(bool isDropper)
|
||||
else
|
||||
{
|
||||
if (isDropper)
|
||||
{
|
||||
Mouse.Captured?.ReleaseMouseCapture();
|
||||
|
||||
if (!_cursorIsSetted)
|
||||
{
|
||||
Mouse.OverrideCursor = _dropperCursor;
|
||||
_cursorIsSetted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_cursorIsSetted)
|
||||
{
|
||||
Mouse.OverrideCursor = Cursors.Arrow;
|
||||
_cursorIsSetted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Color GetColorAt(int x, int y)
|
||||
{
|
||||
var desk = InteropMethods.GetDesktopWindow();
|
||||
var dc = InteropMethods.GetWindowDC(desk);
|
||||
var a = (int) InteropMethods.GetPixel(dc, x, y);
|
||||
InteropMethods.ReleaseDC(desk, dc);
|
||||
return Color.FromArgb(255, (byte) ((a >> 0) & 0xff), (byte) ((a >> 8) & 0xff), (byte) ((a >> 16) & 0xff));
|
||||
Mouse.OverrideCursor = Cursors.Arrow;
|
||||
MouseHook.Stop();
|
||||
MouseHook.StatusChanged -= MouseHook_StatusChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void MouseHook_StatusChanged(object sender, MouseHookEventArgs e)
|
||||
{
|
||||
var window = System.Windows.Window.GetWindow(_colorPicker);
|
||||
if (window == null)
|
||||
{
|
||||
UpdateCursor(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_colorPicker.IsMouseOver && window.IsMouseOver)
|
||||
{
|
||||
UpdateCursor(true);
|
||||
if (e.MessageType == MouseHookMessageType.LeftButtonDown)
|
||||
{
|
||||
var brush = new SolidColorBrush(GetColorAt(e.Point.X, e.Point.Y));
|
||||
_colorPicker.SelectedBrush = brush;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateCursor(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCursor(bool isDropper)
|
||||
{
|
||||
if (isDropper)
|
||||
{
|
||||
Mouse.Captured?.ReleaseMouseCapture();
|
||||
|
||||
if (!_cursorIsSetted)
|
||||
{
|
||||
Mouse.OverrideCursor = _dropperCursor;
|
||||
_cursorIsSetted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_cursorIsSetted)
|
||||
{
|
||||
Mouse.OverrideCursor = Cursors.Arrow;
|
||||
_cursorIsSetted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Color GetColorAt(int x, int y)
|
||||
{
|
||||
var desk = InteropMethods.GetDesktopWindow();
|
||||
var dc = InteropMethods.GetWindowDC(desk);
|
||||
var a = (int) InteropMethods.GetPixel(dc, x, y);
|
||||
InteropMethods.ReleaseDC(desk, dc);
|
||||
return Color.FromArgb(255, (byte) ((a >> 0) & 0xff), (byte) ((a >> 8) & 0xff), (byte) ((a >> 16) & 0xff));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -10,289 +10,288 @@ using System.Windows.Media.Media3D;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 封面流
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ElementViewport3D, Type = typeof(Viewport3D))]
|
||||
[TemplatePart(Name = ElementCamera, Type = typeof(ProjectionCamera))]
|
||||
[TemplatePart(Name = ElementVisualParent, Type = typeof(ModelVisual3D))]
|
||||
public class CoverFlow : Control
|
||||
{
|
||||
private const string ElementViewport3D = "PART_Viewport3D";
|
||||
|
||||
private const string ElementCamera = "PART_Camera";
|
||||
|
||||
private const string ElementVisualParent = "PART_VisualParent";
|
||||
|
||||
/// <summary>
|
||||
/// 封面流
|
||||
/// 最大显示数量的一半
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ElementViewport3D, Type = typeof(Viewport3D))]
|
||||
[TemplatePart(Name = ElementCamera, Type = typeof(ProjectionCamera))]
|
||||
[TemplatePart(Name = ElementVisualParent, Type = typeof(ModelVisual3D))]
|
||||
public class CoverFlow : Control
|
||||
private const int MaxShowCountHalf = 3;
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PageIndexProperty = DependencyProperty.Register(
|
||||
"PageIndex", typeof(int), typeof(CoverFlow),
|
||||
new PropertyMetadata(ValueBoxes.Int0Box, OnPageIndexChanged, CoercePageIndex));
|
||||
|
||||
private static object CoercePageIndex(DependencyObject d, object baseValue)
|
||||
{
|
||||
private const string ElementViewport3D = "PART_Viewport3D";
|
||||
var ctl = (CoverFlow) d;
|
||||
var v = (int) baseValue;
|
||||
|
||||
private const string ElementCamera = "PART_Camera";
|
||||
|
||||
private const string ElementVisualParent = "PART_VisualParent";
|
||||
|
||||
/// <summary>
|
||||
/// 最大显示数量的一半
|
||||
/// </summary>
|
||||
private const int MaxShowCountHalf = 3;
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PageIndexProperty = DependencyProperty.Register(
|
||||
"PageIndex", typeof(int), typeof(CoverFlow),
|
||||
new PropertyMetadata(ValueBoxes.Int0Box, OnPageIndexChanged, CoercePageIndex));
|
||||
|
||||
private static object CoercePageIndex(DependencyObject d, object baseValue)
|
||||
if (v < 0)
|
||||
{
|
||||
var ctl = (CoverFlow) d;
|
||||
var v = (int) baseValue;
|
||||
return 0;
|
||||
}
|
||||
if (v >= ctl._contentDic.Count)
|
||||
{
|
||||
return ctl._contentDic.Count - 1;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
if (v < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (v >= ctl._contentDic.Count)
|
||||
{
|
||||
return ctl._contentDic.Count - 1;
|
||||
}
|
||||
return v;
|
||||
private static void OnPageIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (CoverFlow) d;
|
||||
ctl.UpdateIndex((int) e.NewValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否循环
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty LoopProperty = DependencyProperty.Register(
|
||||
"Loop", typeof(bool), typeof(CoverFlow), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有的内容
|
||||
/// </summary>
|
||||
private readonly Dictionary<int, object> _contentDic = new();
|
||||
|
||||
/// <summary>
|
||||
/// 当前在显示范围内的项
|
||||
/// </summary>
|
||||
private readonly Dictionary<int, CoverFlowItem> _itemShowDic = new();
|
||||
|
||||
/// <summary>
|
||||
/// 相机
|
||||
/// </summary>
|
||||
private ProjectionCamera _camera;
|
||||
|
||||
private Point3DAnimation _point3DAnimation;
|
||||
|
||||
/// <summary>
|
||||
/// 3d画布
|
||||
/// </summary>
|
||||
private Viewport3D _viewport3D;
|
||||
|
||||
/// <summary>
|
||||
/// 项容器
|
||||
/// </summary>
|
||||
private ModelVisual3D _visualParent;
|
||||
|
||||
/// <summary>
|
||||
/// 显示范围内第一个项的编号
|
||||
/// </summary>
|
||||
private int _firstShowIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 显示范围内最后一个项的编号
|
||||
/// </summary>
|
||||
private int _lastShowIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// </summary>
|
||||
public int PageIndex
|
||||
{
|
||||
get => (int) GetValue(PageIndexProperty);
|
||||
set => SetValue(PageIndexProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否循环
|
||||
/// </summary>
|
||||
public bool Loop
|
||||
{
|
||||
get => (bool) GetValue(LoopProperty);
|
||||
set => SetValue(LoopProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_viewport3D != null)
|
||||
{
|
||||
_viewport3D.Children.Clear();
|
||||
_itemShowDic.Clear();
|
||||
_viewport3D.MouseLeftButtonDown -= Viewport3D_MouseLeftButtonDown;
|
||||
}
|
||||
|
||||
private static void OnPageIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_viewport3D = GetTemplateChild(ElementViewport3D) as Viewport3D;
|
||||
if (_viewport3D != null)
|
||||
{
|
||||
var ctl = (CoverFlow) d;
|
||||
ctl.UpdateIndex((int) e.NewValue);
|
||||
_viewport3D.MouseLeftButtonDown += Viewport3D_MouseLeftButtonDown;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否循环
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty LoopProperty = DependencyProperty.Register(
|
||||
"Loop", typeof(bool), typeof(CoverFlow), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
_camera = GetTemplateChild(ElementCamera) as ProjectionCamera;
|
||||
_visualParent = GetTemplateChild(ElementVisualParent) as ModelVisual3D;
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有的内容
|
||||
/// </summary>
|
||||
private readonly Dictionary<int, object> _contentDic = new();
|
||||
UpdateShowRange();
|
||||
|
||||
/// <summary>
|
||||
/// 当前在显示范围内的项
|
||||
/// </summary>
|
||||
private readonly Dictionary<int, CoverFlowItem> _itemShowDic = new();
|
||||
_point3DAnimation = new Point3DAnimation(new Point3D(CoverFlowItem.Interval * PageIndex, _camera.Position.Y, _camera.Position.Z), new Duration(TimeSpan.FromMilliseconds(200)));
|
||||
_camera.BeginAnimation(ProjectionCamera.PositionProperty, _point3DAnimation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 相机
|
||||
/// </summary>
|
||||
private ProjectionCamera _camera;
|
||||
|
||||
private Point3DAnimation _point3DAnimation;
|
||||
|
||||
/// <summary>
|
||||
/// 3d画布
|
||||
/// </summary>
|
||||
private Viewport3D _viewport3D;
|
||||
|
||||
/// <summary>
|
||||
/// 项容器
|
||||
/// </summary>
|
||||
private ModelVisual3D _visualParent;
|
||||
|
||||
/// <summary>
|
||||
/// 显示范围内第一个项的编号
|
||||
/// </summary>
|
||||
private int _firstShowIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 显示范围内最后一个项的编号
|
||||
/// </summary>
|
||||
private int _lastShowIndex;
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// </summary>
|
||||
public int PageIndex
|
||||
/// <summary>
|
||||
/// 批量添加资源
|
||||
/// </summary>
|
||||
/// <param name="contentList"></param>
|
||||
public void AddRange(IEnumerable<object> contentList)
|
||||
{
|
||||
foreach (var content in contentList)
|
||||
{
|
||||
get => (int) GetValue(PageIndexProperty);
|
||||
set => SetValue(PageIndexProperty, value);
|
||||
_contentDic.Add(_contentDic.Count, content);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一项资源
|
||||
/// </summary>
|
||||
/// <param name="uriString"></param>
|
||||
public void Add(string uriString) => _contentDic.Add(_contentDic.Count, new Uri(uriString));
|
||||
|
||||
/// <summary>
|
||||
/// 添加一项资源
|
||||
/// </summary>
|
||||
/// <param name="uri"></param>
|
||||
public void Add(Uri uri) => _contentDic.Add(_contentDic.Count, uri);
|
||||
|
||||
public void Next() => PageIndex++;
|
||||
|
||||
public void Prev() => PageIndex--;
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
|
||||
if (e.Delta < 0)
|
||||
{
|
||||
var index = PageIndex + 1;
|
||||
PageIndex = index >= _contentDic.Count ? Loop ? 0 : _contentDic.Count - 1 : index;
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = PageIndex - 1;
|
||||
PageIndex = index < 0 ? Loop ? _contentDic.Count - 1 : 0 : index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否循环
|
||||
/// </summary>
|
||||
public bool Loop
|
||||
{
|
||||
get => (bool) GetValue(LoopProperty);
|
||||
set => SetValue(LoopProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
/// <summary>
|
||||
/// 删除指定位置的项
|
||||
/// </summary>
|
||||
/// <param name="pos"></param>
|
||||
private void Remove(int pos)
|
||||
{
|
||||
if (!_itemShowDic.TryGetValue(pos, out var item)) return;
|
||||
_visualParent.Children.Remove(item);
|
||||
_itemShowDic.Remove(pos);
|
||||
}
|
||||
|
||||
private void Viewport3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var result = (RayMeshGeometry3DHitTestResult) VisualTreeHelper.HitTest(_viewport3D, e.GetPosition(_viewport3D));
|
||||
if (result != null)
|
||||
{
|
||||
if (_viewport3D != null)
|
||||
foreach (var item in _itemShowDic.Values)
|
||||
{
|
||||
_viewport3D.Children.Clear();
|
||||
_itemShowDic.Clear();
|
||||
_viewport3D.MouseLeftButtonDown -= Viewport3D_MouseLeftButtonDown;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_viewport3D = GetTemplateChild(ElementViewport3D) as Viewport3D;
|
||||
if (_viewport3D != null)
|
||||
{
|
||||
_viewport3D.MouseLeftButtonDown += Viewport3D_MouseLeftButtonDown;
|
||||
}
|
||||
|
||||
_camera = GetTemplateChild(ElementCamera) as ProjectionCamera;
|
||||
_visualParent = GetTemplateChild(ElementVisualParent) as ModelVisual3D;
|
||||
|
||||
UpdateShowRange();
|
||||
|
||||
_point3DAnimation = new Point3DAnimation(new Point3D(CoverFlowItem.Interval * PageIndex, _camera.Position.Y, _camera.Position.Z), new Duration(TimeSpan.FromMilliseconds(200)));
|
||||
_camera.BeginAnimation(ProjectionCamera.PositionProperty, _point3DAnimation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量添加资源
|
||||
/// </summary>
|
||||
/// <param name="contentList"></param>
|
||||
public void AddRange(IEnumerable<object> contentList)
|
||||
{
|
||||
foreach (var content in contentList)
|
||||
{
|
||||
_contentDic.Add(_contentDic.Count, content);
|
||||
if (item.HitTest(result.MeshHit))
|
||||
{
|
||||
PageIndex = item.Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加一项资源
|
||||
/// </summary>
|
||||
/// <param name="uriString"></param>
|
||||
public void Add(string uriString) => _contentDic.Add(_contentDic.Count, new Uri(uriString));
|
||||
|
||||
/// <summary>
|
||||
/// 添加一项资源
|
||||
/// </summary>
|
||||
/// <param name="uri"></param>
|
||||
public void Add(Uri uri) => _contentDic.Add(_contentDic.Count, uri);
|
||||
|
||||
public void Next() => PageIndex++;
|
||||
|
||||
public void Prev() => PageIndex--;
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
/// <summary>
|
||||
/// 更新项的位置
|
||||
/// </summary>
|
||||
/// <param name="newIndex"></param>
|
||||
private void UpdateIndex(int newIndex)
|
||||
{
|
||||
if (!IsLoaded)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Delta < 0)
|
||||
UpdateShowRange();
|
||||
_itemShowDic.Do(item =>
|
||||
{
|
||||
if (item.Value.Index < _firstShowIndex || item.Value.Index > _lastShowIndex)
|
||||
{
|
||||
var index = PageIndex + 1;
|
||||
PageIndex = index >= _contentDic.Count ? Loop ? 0 : _contentDic.Count - 1 : index;
|
||||
Remove(item.Value.Index);
|
||||
}
|
||||
else
|
||||
{
|
||||
var index = PageIndex - 1;
|
||||
PageIndex = index < 0 ? Loop ? _contentDic.Count - 1 : 0 : index;
|
||||
item.Value.Move(PageIndex);
|
||||
}
|
||||
});
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
_point3DAnimation = new Point3DAnimation(new Point3D(CoverFlowItem.Interval * newIndex, _camera.Position.Y,
|
||||
_camera.Position.Z), new Duration(TimeSpan.FromMilliseconds(200)));
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定位置的项
|
||||
/// </summary>
|
||||
/// <param name="pos"></param>
|
||||
private void Remove(int pos)
|
||||
_camera.BeginAnimation(ProjectionCamera.PositionProperty, _point3DAnimation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新显示范围
|
||||
/// </summary>
|
||||
private void UpdateShowRange()
|
||||
{
|
||||
var newFirstShowIndex = Math.Max(PageIndex - MaxShowCountHalf, 0);
|
||||
var newLastShowIndex = Math.Min(PageIndex + MaxShowCountHalf, _contentDic.Count - 1);
|
||||
|
||||
for (var i = newFirstShowIndex; i <= newLastShowIndex; i++)
|
||||
{
|
||||
if (!_itemShowDic.TryGetValue(pos, out var item)) return;
|
||||
_visualParent.Children.Remove(item);
|
||||
_itemShowDic.Remove(pos);
|
||||
}
|
||||
|
||||
private void Viewport3D_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var result = (RayMeshGeometry3DHitTestResult) VisualTreeHelper.HitTest(_viewport3D, e.GetPosition(_viewport3D));
|
||||
if (result != null)
|
||||
if (!_itemShowDic.ContainsKey(i))
|
||||
{
|
||||
foreach (var item in _itemShowDic.Values)
|
||||
{
|
||||
if (item.HitTest(result.MeshHit))
|
||||
{
|
||||
PageIndex = item.Index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var cover = CreateCoverFlowItem(i, _contentDic[i]);
|
||||
_itemShowDic[i] = cover;
|
||||
_visualParent.Children.Add(cover);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新项的位置
|
||||
/// </summary>
|
||||
/// <param name="newIndex"></param>
|
||||
private void UpdateIndex(int newIndex)
|
||||
_firstShowIndex = newFirstShowIndex;
|
||||
_lastShowIndex = newLastShowIndex;
|
||||
}
|
||||
|
||||
private CoverFlowItem CreateCoverFlowItem(int index, object content)
|
||||
{
|
||||
if (content is Uri uri)
|
||||
{
|
||||
if (!IsLoaded)
|
||||
try
|
||||
{
|
||||
return;
|
||||
return new CoverFlowItem(index, PageIndex, new Image
|
||||
{
|
||||
Source = BitmapFrame.Create(uri, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand)
|
||||
});
|
||||
}
|
||||
|
||||
UpdateShowRange();
|
||||
_itemShowDic.Do(item =>
|
||||
catch
|
||||
{
|
||||
if (item.Value.Index < _firstShowIndex || item.Value.Index > _lastShowIndex)
|
||||
{
|
||||
Remove(item.Value.Index);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Value.Move(PageIndex);
|
||||
}
|
||||
});
|
||||
|
||||
_point3DAnimation = new Point3DAnimation(new Point3D(CoverFlowItem.Interval * newIndex, _camera.Position.Y,
|
||||
_camera.Position.Z), new Duration(TimeSpan.FromMilliseconds(200)));
|
||||
|
||||
_camera.BeginAnimation(ProjectionCamera.PositionProperty, _point3DAnimation);
|
||||
return new CoverFlowItem(index, PageIndex, new ContentControl());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新显示范围
|
||||
/// </summary>
|
||||
private void UpdateShowRange()
|
||||
return new CoverFlowItem(index, PageIndex, new ContentControl
|
||||
{
|
||||
var newFirstShowIndex = Math.Max(PageIndex - MaxShowCountHalf, 0);
|
||||
var newLastShowIndex = Math.Min(PageIndex + MaxShowCountHalf, _contentDic.Count - 1);
|
||||
|
||||
for (var i = newFirstShowIndex; i <= newLastShowIndex; i++)
|
||||
{
|
||||
if (!_itemShowDic.ContainsKey(i))
|
||||
{
|
||||
var cover = CreateCoverFlowItem(i, _contentDic[i]);
|
||||
_itemShowDic[i] = cover;
|
||||
_visualParent.Children.Add(cover);
|
||||
}
|
||||
}
|
||||
|
||||
_firstShowIndex = newFirstShowIndex;
|
||||
_lastShowIndex = newLastShowIndex;
|
||||
}
|
||||
|
||||
private CoverFlowItem CreateCoverFlowItem(int index, object content)
|
||||
{
|
||||
if (content is Uri uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new CoverFlowItem(index, PageIndex, new Image
|
||||
{
|
||||
Source = BitmapFrame.Create(uri, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand)
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new CoverFlowItem(index, PageIndex, new ContentControl());
|
||||
}
|
||||
}
|
||||
|
||||
return new CoverFlowItem(index, PageIndex, new ContentControl
|
||||
{
|
||||
Content = content
|
||||
});
|
||||
}
|
||||
Content = content
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4,154 +4,153 @@ using System.Windows.Media;
|
||||
using System.Windows.Media.Media3D;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class CoverFlowItem : ModelVisual3D
|
||||
{
|
||||
public class CoverFlowItem : ModelVisual3D
|
||||
internal static readonly double Interval = .2;
|
||||
|
||||
internal static readonly double AnimationSpeed = 400;
|
||||
|
||||
private readonly AxisAngleRotation3D _rotation3D;
|
||||
|
||||
private readonly TranslateTransform3D _transform3D;
|
||||
|
||||
private readonly Model3DGroup _model3DGroup;
|
||||
|
||||
private readonly UIElement _uiElement;
|
||||
|
||||
internal int Index { get; set; }
|
||||
|
||||
public CoverFlowItem(int itemIndex, int currentIndex, UIElement element)
|
||||
{
|
||||
internal static readonly double Interval = .2;
|
||||
Index = itemIndex;
|
||||
_uiElement = element;
|
||||
_uiElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
|
||||
internal static readonly double AnimationSpeed = 400;
|
||||
_rotation3D = new AxisAngleRotation3D(new Vector3D(0, 1, 0), GetAngleByPos(currentIndex));
|
||||
_transform3D = new TranslateTransform3D(GetXByPos(currentIndex), 0, GetZByPos(currentIndex));
|
||||
|
||||
private readonly AxisAngleRotation3D _rotation3D;
|
||||
var transformGroup = new Transform3DGroup();
|
||||
transformGroup.Children.Add(new RotateTransform3D(_rotation3D));
|
||||
transformGroup.Children.Add(_transform3D);
|
||||
|
||||
private readonly TranslateTransform3D _transform3D;
|
||||
_model3DGroup = new Model3DGroup();
|
||||
_model3DGroup.Children.Add(new GeometryModel3D(CreateItemGeometry(), new DiffuseMaterial(new VisualBrush(element))));
|
||||
_model3DGroup.Transform = transformGroup;
|
||||
|
||||
private readonly Model3DGroup _model3DGroup;
|
||||
Content = _model3DGroup;
|
||||
}
|
||||
|
||||
private readonly UIElement _uiElement;
|
||||
|
||||
internal int Index { get; set; }
|
||||
|
||||
public CoverFlowItem(int itemIndex, int currentIndex, UIElement element)
|
||||
/// <summary>
|
||||
/// 创建网格形状
|
||||
/// </summary>
|
||||
/// <param name="p0"></param>
|
||||
/// <param name="p1"></param>
|
||||
/// <param name="p2"></param>
|
||||
/// <param name="p3"></param>
|
||||
/// <returns></returns>
|
||||
private static MeshGeometry3D CreateMeshGeometry(Point3D p0, Point3D p1, Point3D p2, Point3D p3)
|
||||
{
|
||||
var positions = new Point3DCollection
|
||||
{
|
||||
Index = itemIndex;
|
||||
_uiElement = element;
|
||||
_uiElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
p0,
|
||||
p1,
|
||||
p2,
|
||||
p3
|
||||
};
|
||||
|
||||
_rotation3D = new AxisAngleRotation3D(new Vector3D(0, 1, 0), GetAngleByPos(currentIndex));
|
||||
_transform3D = new TranslateTransform3D(GetXByPos(currentIndex), 0, GetZByPos(currentIndex));
|
||||
|
||||
var transformGroup = new Transform3DGroup();
|
||||
transformGroup.Children.Add(new RotateTransform3D(_rotation3D));
|
||||
transformGroup.Children.Add(_transform3D);
|
||||
|
||||
_model3DGroup = new Model3DGroup();
|
||||
_model3DGroup.Children.Add(new GeometryModel3D(CreateItemGeometry(), new DiffuseMaterial(new VisualBrush(element))));
|
||||
_model3DGroup.Transform = transformGroup;
|
||||
|
||||
Content = _model3DGroup;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建网格形状
|
||||
/// </summary>
|
||||
/// <param name="p0"></param>
|
||||
/// <param name="p1"></param>
|
||||
/// <param name="p2"></param>
|
||||
/// <param name="p3"></param>
|
||||
/// <returns></returns>
|
||||
private static MeshGeometry3D CreateMeshGeometry(Point3D p0, Point3D p1, Point3D p2, Point3D p3)
|
||||
var triangleIndices = new Int32Collection
|
||||
{
|
||||
var positions = new Point3DCollection
|
||||
{
|
||||
p0,
|
||||
p1,
|
||||
p2,
|
||||
p3
|
||||
};
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
3,
|
||||
0
|
||||
};
|
||||
|
||||
var triangleIndices = new Int32Collection
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
3,
|
||||
0
|
||||
};
|
||||
|
||||
var textureCoordinates = new PointCollection
|
||||
{
|
||||
new(0, 1),
|
||||
new(1, 1),
|
||||
new(1, 0),
|
||||
new(0, 0),
|
||||
new(1, 0),
|
||||
new(1, 1)
|
||||
};
|
||||
|
||||
var normals = new Vector3DCollection
|
||||
{
|
||||
ArithmeticHelper.CalNormal(p0, p1, p2),
|
||||
ArithmeticHelper.CalNormal(p2, p3, p0)
|
||||
};
|
||||
|
||||
var geometry3D = new MeshGeometry3D
|
||||
{
|
||||
Positions = positions,
|
||||
TriangleIndices = triangleIndices,
|
||||
TextureCoordinates = textureCoordinates,
|
||||
Normals = normals
|
||||
};
|
||||
|
||||
geometry3D.Freeze();
|
||||
return geometry3D;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建内容形状
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Geometry3D CreateItemGeometry()
|
||||
var textureCoordinates = new PointCollection
|
||||
{
|
||||
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;
|
||||
new(0, 1),
|
||||
new(1, 1),
|
||||
new(1, 0),
|
||||
new(0, 0),
|
||||
new(1, 0),
|
||||
new(1, 1)
|
||||
};
|
||||
|
||||
var p0 = new Point3D(-1 + sx, -1 + sy, 0);
|
||||
var p1 = new Point3D(1 - sx, -1 + sy, 0);
|
||||
var p2 = new Point3D(1 - sx, 1 - sy, 0);
|
||||
var p3 = new Point3D(-1 + sx, 1 - sy, 0);
|
||||
|
||||
return CreateMeshGeometry(p0, p1, p2, p3);
|
||||
}
|
||||
|
||||
private double GetAngleByPos(int index) => Math.Sign(Index - index) * -90;
|
||||
|
||||
private double GetXByPos(int index) => Index * Interval + Math.Sign(Index - index) * 1.5;
|
||||
|
||||
private double GetZByPos(int index) => Index == index ? 1 : 0;
|
||||
|
||||
/// <summary>
|
||||
/// 移动
|
||||
/// </summary>
|
||||
internal void Move(int currentIndex)
|
||||
var normals = new Vector3DCollection
|
||||
{
|
||||
_rotation3D.BeginAnimation(AxisAngleRotation3D.AngleProperty,
|
||||
AnimationHelper.CreateAnimation(GetAngleByPos(currentIndex), AnimationSpeed));
|
||||
_transform3D.BeginAnimation(TranslateTransform3D.OffsetXProperty,
|
||||
AnimationHelper.CreateAnimation(GetXByPos(currentIndex), AnimationSpeed));
|
||||
_transform3D.BeginAnimation(TranslateTransform3D.OffsetZProperty,
|
||||
AnimationHelper.CreateAnimation(GetZByPos(currentIndex), AnimationSpeed));
|
||||
}
|
||||
ArithmeticHelper.CalNormal(p0, p1, p2),
|
||||
ArithmeticHelper.CalNormal(p2, p3, p0)
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 命中测试
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <returns></returns>
|
||||
internal bool HitTest(MeshGeometry3D mesh)
|
||||
var geometry3D = new MeshGeometry3D
|
||||
{
|
||||
foreach (var item in _model3DGroup.Children)
|
||||
Positions = positions,
|
||||
TriangleIndices = triangleIndices,
|
||||
TextureCoordinates = textureCoordinates,
|
||||
Normals = normals
|
||||
};
|
||||
|
||||
geometry3D.Freeze();
|
||||
return geometry3D;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建内容形状
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Geometry3D CreateItemGeometry()
|
||||
{
|
||||
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);
|
||||
var p2 = new Point3D(1 - sx, 1 - sy, 0);
|
||||
var p3 = new Point3D(-1 + sx, 1 - sy, 0);
|
||||
|
||||
return CreateMeshGeometry(p0, p1, p2, p3);
|
||||
}
|
||||
|
||||
private double GetAngleByPos(int index) => Math.Sign(Index - index) * -90;
|
||||
|
||||
private double GetXByPos(int index) => Index * Interval + Math.Sign(Index - index) * 1.5;
|
||||
|
||||
private double GetZByPos(int index) => Index == index ? 1 : 0;
|
||||
|
||||
/// <summary>
|
||||
/// 移动
|
||||
/// </summary>
|
||||
internal void Move(int currentIndex)
|
||||
{
|
||||
_rotation3D.BeginAnimation(AxisAngleRotation3D.AngleProperty,
|
||||
AnimationHelper.CreateAnimation(GetAngleByPos(currentIndex), AnimationSpeed));
|
||||
_transform3D.BeginAnimation(TranslateTransform3D.OffsetXProperty,
|
||||
AnimationHelper.CreateAnimation(GetXByPos(currentIndex), AnimationSpeed));
|
||||
_transform3D.BeginAnimation(TranslateTransform3D.OffsetZProperty,
|
||||
AnimationHelper.CreateAnimation(GetZByPos(currentIndex), AnimationSpeed));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 命中测试
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <returns></returns>
|
||||
internal bool HitTest(MeshGeometry3D mesh)
|
||||
{
|
||||
foreach (var item in _model3DGroup.Children)
|
||||
{
|
||||
if (item is GeometryModel3D geometryModel3D)
|
||||
{
|
||||
if (item is GeometryModel3D geometryModel3D)
|
||||
if (Equals(geometryModel3D.Geometry, mesh))
|
||||
{
|
||||
if (Equals(geometryModel3D.Geometry, mesh))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -6,413 +6,417 @@ using System.Windows.Data;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class CoverView : RegularItemsControl
|
||||
{
|
||||
public class CoverView : RegularItemsControl
|
||||
private readonly CoverViewContent _viewContent;
|
||||
|
||||
private CoverViewItem _selectedItem;
|
||||
|
||||
private IEnumerable _itemsSourceInternal;
|
||||
|
||||
private readonly Dictionary<object, CoverViewItem> _entryDic = new();
|
||||
|
||||
private bool _isRefresh;
|
||||
|
||||
public CoverView()
|
||||
{
|
||||
private readonly CoverViewContent _viewContent;
|
||||
_viewContent = new CoverViewContent();
|
||||
|
||||
private CoverViewItem _selectedItem;
|
||||
AddHandler(SelectableItem.SelectedEvent, new RoutedEventHandler(CoverViewItem_OnSelected));
|
||||
_viewContent.SetBinding(CoverViewContent.ContentHeightProperty, new Binding(ItemContentHeightProperty.Name) { Source = this });
|
||||
_viewContent.SetBinding(WidthProperty, new Binding(ActualWidthProperty.Name) { Source = this });
|
||||
}
|
||||
|
||||
private IEnumerable _itemsSourceInternal;
|
||||
|
||||
private readonly Dictionary<object, CoverViewItem> _entryDic = new();
|
||||
|
||||
private bool _isRefresh;
|
||||
|
||||
public CoverView()
|
||||
private void CoverViewItem_OnSelected(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is CoverViewItem item)
|
||||
{
|
||||
_viewContent = new CoverViewContent();
|
||||
|
||||
AddHandler(SelectableItem.SelectedEvent, new RoutedEventHandler(CoverViewItem_OnSelected));
|
||||
_viewContent.SetBinding(CoverViewContent.ContentHeightProperty, new Binding(ItemContentHeightProperty.Name) { Source = this });
|
||||
_viewContent.SetBinding(WidthProperty, new Binding(ActualWidthProperty.Name) { Source = this });
|
||||
}
|
||||
|
||||
private void CoverViewItem_OnSelected(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is CoverViewItem item)
|
||||
if (_selectedItem == null)
|
||||
{
|
||||
if (_selectedItem == null)
|
||||
{
|
||||
item.IsSelected = true;
|
||||
_selectedItem = item;
|
||||
if (_viewContent != null)
|
||||
{
|
||||
_viewContent.Content = item.Content;
|
||||
_viewContent.ContentTemplate = ItemTemplate;
|
||||
UpdateCoverViewContent(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Equals(_selectedItem, item))
|
||||
{
|
||||
_selectedItem.IsSelected = false;
|
||||
item.IsSelected = true;
|
||||
_selectedItem = item;
|
||||
if (_viewContent != null)
|
||||
{
|
||||
_viewContent.Content = item.Content;
|
||||
UpdateCoverViewContent(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
item.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.TrueBox);
|
||||
_selectedItem = item;
|
||||
if (_viewContent != null)
|
||||
{
|
||||
_viewContent.Content = null;
|
||||
_viewContent.ContentTemplate = null;
|
||||
UpdateCoverViewContent(false);
|
||||
_viewContent.Content = item.Content;
|
||||
_viewContent.ContentTemplate = ItemTemplate;
|
||||
UpdateCoverViewContent(true);
|
||||
}
|
||||
_selectedItem.IsSelected = false;
|
||||
_selectedItem = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_viewContent.Style ??= CoverViewContentStyle;
|
||||
|
||||
if (_selectedItem != null)
|
||||
{
|
||||
UpdateCoverViewContent(_selectedItem != null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new CoverViewItem();
|
||||
|
||||
private void SetBindingForItem(FrameworkElement item)
|
||||
{
|
||||
item.SetBinding(MarginProperty, new Binding(ItemMarginProperty.Name) { Source = this });
|
||||
item.SetBinding(WidthProperty, new Binding(ItemWidthProperty.Name) { Source = this });
|
||||
item.SetBinding(HeightProperty, new Binding(ItemHeightProperty.Name) { Source = this });
|
||||
item.SetBinding(HeaderedSelectableItem.HeaderTemplateProperty, new Binding(ItemHeaderTemplateProperty.Name) { Source = this });
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is CoverViewItem;
|
||||
|
||||
public static readonly DependencyProperty CoverViewContentStyleProperty = DependencyProperty.Register(
|
||||
"CoverViewContentStyle", typeof(Style), typeof(CoverView), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style CoverViewContentStyle
|
||||
{
|
||||
get => (Style) GetValue(CoverViewContentStyleProperty);
|
||||
set => SetValue(CoverViewContentStyleProperty, value);
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty GroupsProperty = DependencyProperty.Register(
|
||||
"Groups", typeof(int), typeof(CoverView),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Int5Box, FrameworkPropertyMetadataOptions.AffectsMeasure,
|
||||
OnGroupsChanged), IsGroupsValid);
|
||||
|
||||
internal static void OnGroupsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is CoverView ctl)
|
||||
{
|
||||
ctl.UpdateCoverViewContent(ctl._viewContent.IsOpen);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsGroupsValid(object value)
|
||||
{
|
||||
var v = (int) value;
|
||||
return v >= 1;
|
||||
}
|
||||
|
||||
public int Groups
|
||||
{
|
||||
get => (int) GetValue(GroupsProperty);
|
||||
set => SetValue(GroupsProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemContentHeightProperty = DependencyProperty.Register(
|
||||
"ItemContentHeight", typeof(double), typeof(CoverView), new PropertyMetadata(ValueBoxes.Double300Box),
|
||||
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
||||
|
||||
public double ItemContentHeight
|
||||
{
|
||||
get => (double) GetValue(ItemContentHeightProperty);
|
||||
set => SetValue(ItemContentHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemContentHeightFixedProperty = DependencyProperty.Register(
|
||||
"ItemContentHeightFixed", typeof(bool), typeof(CoverView), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool ItemContentHeightFixed
|
||||
{
|
||||
get => (bool) GetValue(ItemContentHeightFixedProperty);
|
||||
set => SetValue(ItemContentHeightFixedProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemHeaderTemplateProperty = DependencyProperty.Register(
|
||||
"ItemHeaderTemplate", typeof(DataTemplate), typeof(CoverView), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public DataTemplate ItemHeaderTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(ItemHeaderTemplateProperty);
|
||||
set => SetValue(ItemHeaderTemplateProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
|
||||
Groups = (int) (sizeInfo.NewSize.Width / (ItemWidth + ItemMargin.Left + ItemMargin.Right));
|
||||
}
|
||||
|
||||
protected override void Refresh()
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
_entryDic.Clear();
|
||||
_isRefresh = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
AddItem(item);
|
||||
return;
|
||||
}
|
||||
|
||||
_isRefresh = false;
|
||||
GenerateIndex();
|
||||
UpdateCoverViewContent(_viewContent.IsOpen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新内容视图
|
||||
/// </summary>
|
||||
private void UpdateCoverViewContent(bool isOpen)
|
||||
{
|
||||
if (_selectedItem == null) return;
|
||||
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
|
||||
if (!ItemContentHeightFixed)
|
||||
if (!Equals(_selectedItem, item))
|
||||
{
|
||||
_viewContent.ManualHeight = 0;
|
||||
if (_viewContent.Content is FrameworkElement element)
|
||||
_selectedItem.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.FalseBox);
|
||||
item.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.TrueBox);
|
||||
_selectedItem = item;
|
||||
if (_viewContent != null)
|
||||
{
|
||||
element.VerticalAlignment = VerticalAlignment.Top;
|
||||
element.Arrange(new Rect(new Size(double.MaxValue, double.MaxValue)));
|
||||
_viewContent.ManualHeight = element.ActualHeight;
|
||||
_viewContent.Content = item.Content;
|
||||
UpdateCoverViewContent(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateCoverViewContentPosition();
|
||||
if (_viewContent.CanSwitch)
|
||||
if (_viewContent != null)
|
||||
{
|
||||
_viewContent.IsOpen = isOpen;
|
||||
_viewContent.Content = null;
|
||||
_viewContent.ContentTemplate = null;
|
||||
UpdateCoverViewContent(false);
|
||||
}
|
||||
_selectedItem.SetCurrentValue(SelectableItem.IsSelectedProperty, ValueBoxes.FalseBox);
|
||||
_selectedItem = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_viewContent.Style ??= CoverViewContentStyle;
|
||||
|
||||
if (_selectedItem != null)
|
||||
{
|
||||
UpdateCoverViewContent(_selectedItem != null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new CoverViewItem();
|
||||
|
||||
private void SetBindingForItem(FrameworkElement item)
|
||||
{
|
||||
item.SetBinding(MarginProperty, new Binding(ItemMarginProperty.Name) { Source = this });
|
||||
item.SetBinding(WidthProperty, new Binding(ItemWidthProperty.Name) { Source = this });
|
||||
item.SetBinding(HeightProperty, new Binding(ItemHeightProperty.Name) { Source = this });
|
||||
item.SetBinding(HeaderedSelectableItem.HeaderTemplateProperty, new Binding(ItemHeaderTemplateProperty.Name) { Source = this });
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is CoverViewItem;
|
||||
|
||||
public static readonly DependencyProperty CoverViewContentStyleProperty = DependencyProperty.Register(
|
||||
"CoverViewContentStyle", typeof(Style), typeof(CoverView), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style CoverViewContentStyle
|
||||
{
|
||||
get => (Style) GetValue(CoverViewContentStyleProperty);
|
||||
set => SetValue(CoverViewContentStyleProperty, value);
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty GroupsProperty = DependencyProperty.Register(
|
||||
"Groups", typeof(int), typeof(CoverView),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Int5Box, FrameworkPropertyMetadataOptions.AffectsMeasure,
|
||||
OnGroupsChanged, CoerceGroups));
|
||||
|
||||
private static object CoerceGroups(DependencyObject d, object basevalue)
|
||||
{
|
||||
return (int) basevalue < 1 ? 1 : basevalue;
|
||||
}
|
||||
|
||||
internal static void OnGroupsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is CoverView ctl)
|
||||
{
|
||||
ctl.UpdateCoverViewContent(ctl._viewContent.IsOpen);
|
||||
}
|
||||
}
|
||||
|
||||
public int Groups
|
||||
{
|
||||
get => (int) GetValue(GroupsProperty);
|
||||
set => SetValue(GroupsProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemContentHeightProperty = DependencyProperty.Register(
|
||||
"ItemContentHeight", typeof(double), typeof(CoverView), new PropertyMetadata(ValueBoxes.Double300Box),
|
||||
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
||||
|
||||
public double ItemContentHeight
|
||||
{
|
||||
get => (double) GetValue(ItemContentHeightProperty);
|
||||
set => SetValue(ItemContentHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemContentHeightFixedProperty = DependencyProperty.Register(
|
||||
"ItemContentHeightFixed", typeof(bool), typeof(CoverView), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool ItemContentHeightFixed
|
||||
{
|
||||
get => (bool) GetValue(ItemContentHeightFixedProperty);
|
||||
set => SetValue(ItemContentHeightFixedProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemHeaderTemplateProperty = DependencyProperty.Register(
|
||||
"ItemHeaderTemplate", typeof(DataTemplate), typeof(CoverView), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public DataTemplate ItemHeaderTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(ItemHeaderTemplateProperty);
|
||||
set => SetValue(ItemHeaderTemplateProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
|
||||
Groups = (int) (sizeInfo.NewSize.Width / (ItemWidth + ItemMargin.Left + ItemMargin.Right));
|
||||
}
|
||||
|
||||
protected override void Refresh()
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
_entryDic.Clear();
|
||||
_isRefresh = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
AddItem(item);
|
||||
}
|
||||
|
||||
_isRefresh = false;
|
||||
GenerateIndex();
|
||||
UpdateCoverViewContent(_viewContent.IsOpen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新内容视图
|
||||
/// </summary>
|
||||
private void UpdateCoverViewContent(bool isOpen)
|
||||
{
|
||||
if (_selectedItem == null) return;
|
||||
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
|
||||
if (!ItemContentHeightFixed)
|
||||
{
|
||||
_viewContent.ManualHeight = 0;
|
||||
if (_viewContent.Content is FrameworkElement element)
|
||||
{
|
||||
element.VerticalAlignment = VerticalAlignment.Top;
|
||||
element.Arrange(new Rect(new Size(double.MaxValue, double.MaxValue)));
|
||||
_viewContent.ManualHeight = element.ActualHeight;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新内容视图位置
|
||||
/// </summary>
|
||||
private void UpdateCoverViewContentPosition()
|
||||
UpdateCoverViewContentPosition();
|
||||
if (_viewContent.CanSwitch)
|
||||
{
|
||||
if (_viewContent.Parent != null)
|
||||
{
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
}
|
||||
var total = _entryDic.Count + 1;
|
||||
var totalRow = total / Groups + (total % Groups > 0 ? 1 : 0);
|
||||
if (total <= Groups)
|
||||
_viewContent.IsOpen = isOpen;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新内容视图位置
|
||||
/// </summary>
|
||||
private void UpdateCoverViewContentPosition()
|
||||
{
|
||||
if (_viewContent.Parent != null)
|
||||
{
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
}
|
||||
|
||||
if (_selectedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var total = _entryDic.Count + 1;
|
||||
var totalRow = total / Groups + (total % Groups > 0 ? 1 : 0);
|
||||
if (total <= Groups)
|
||||
{
|
||||
ItemsHost.Children.Add(_viewContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
var row = _selectedItem.Index / Groups + 1;
|
||||
if (row == totalRow)
|
||||
{
|
||||
ItemsHost.Children.Add(_viewContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
var row = _selectedItem.Index / Groups + 1;
|
||||
if (row == totalRow)
|
||||
{
|
||||
ItemsHost.Children.Add(_viewContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemsHost.Children.Insert(row * Groups, _viewContent);
|
||||
}
|
||||
}
|
||||
|
||||
_viewContent.UpdatePosition(_selectedItem.Index, Groups, _selectedItem.DesiredSize.Width);
|
||||
}
|
||||
|
||||
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
|
||||
{
|
||||
if (_itemsSourceInternal != null)
|
||||
{
|
||||
if (_itemsSourceInternal is INotifyCollectionChanged s)
|
||||
{
|
||||
s.CollectionChanged -= InternalCollectionChanged;
|
||||
}
|
||||
|
||||
Items.Clear();
|
||||
ClearItems();
|
||||
}
|
||||
_itemsSourceInternal = newValue;
|
||||
if (_itemsSourceInternal != null)
|
||||
{
|
||||
if (_itemsSourceInternal is INotifyCollectionChanged s)
|
||||
{
|
||||
s.CollectionChanged += InternalCollectionChanged;
|
||||
}
|
||||
foreach (var item in _itemsSourceInternal)
|
||||
{
|
||||
AddItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (ItemsHost != null)
|
||||
{
|
||||
GenerateIndex();
|
||||
ItemsHost.Children.Insert(row * Groups, _viewContent);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearItems()
|
||||
{
|
||||
_selectedItem = null;
|
||||
_viewContent.Content = null;
|
||||
_viewContent.ContentTemplate = null;
|
||||
_viewContent.UpdatePosition(_selectedItem.Index, Groups, _selectedItem.DesiredSize.Width);
|
||||
}
|
||||
|
||||
if (ItemsHost != null)
|
||||
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
|
||||
{
|
||||
if (_itemsSourceInternal != null)
|
||||
{
|
||||
if (_itemsSourceInternal is INotifyCollectionChanged s)
|
||||
{
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
ItemsHost.Children.Clear();
|
||||
s.CollectionChanged -= InternalCollectionChanged;
|
||||
}
|
||||
|
||||
_entryDic.Clear();
|
||||
Items.Clear();
|
||||
ClearItems();
|
||||
}
|
||||
_itemsSourceInternal = newValue;
|
||||
if (_itemsSourceInternal != null)
|
||||
{
|
||||
if (_itemsSourceInternal is INotifyCollectionChanged s)
|
||||
{
|
||||
s.CollectionChanged += InternalCollectionChanged;
|
||||
}
|
||||
foreach (var item in _itemsSourceInternal)
|
||||
{
|
||||
AddItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveItem(object item)
|
||||
if (ItemsHost != null)
|
||||
{
|
||||
if (_entryDic.TryGetValue(item, out var entry))
|
||||
GenerateIndex();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearItems()
|
||||
{
|
||||
_selectedItem = null;
|
||||
_viewContent.Content = null;
|
||||
_viewContent.ContentTemplate = null;
|
||||
|
||||
if (ItemsHost != null)
|
||||
{
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
ItemsHost.Children.Clear();
|
||||
}
|
||||
|
||||
_entryDic.Clear();
|
||||
}
|
||||
|
||||
private void RemoveItem(object item)
|
||||
{
|
||||
if (_entryDic.TryGetValue(item, out var entry))
|
||||
{
|
||||
if (ReferenceEquals(entry, _selectedItem))
|
||||
{
|
||||
if (ReferenceEquals(entry, _selectedItem))
|
||||
_selectedItem = null;
|
||||
if (_viewContent != null)
|
||||
{
|
||||
_selectedItem = null;
|
||||
if (_viewContent != null)
|
||||
{
|
||||
_viewContent.Content = null;
|
||||
_viewContent.IsOpen = false;
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
}
|
||||
_viewContent.Content = null;
|
||||
_viewContent.IsOpen = false;
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
}
|
||||
|
||||
ItemsHost.Children.Remove(entry);
|
||||
Items.Remove(item);
|
||||
_entryDic.Remove(item);
|
||||
}
|
||||
|
||||
ItemsHost.Children.Remove(entry);
|
||||
Items.Remove(item);
|
||||
_entryDic.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddItem(object item) => InsertItem(_entryDic.Count, item);
|
||||
private void AddItem(object item) => InsertItem(_entryDic.Count, item);
|
||||
|
||||
private void InsertItem(int index, object item)
|
||||
private void InsertItem(int index, object item)
|
||||
{
|
||||
if (ItemsHost == null)
|
||||
{
|
||||
if (ItemsHost == null)
|
||||
Items.Insert(index, item);
|
||||
_entryDic.Add(item, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
DependencyObject container;
|
||||
if (IsItemItsOwnContainerOverride(item))
|
||||
{
|
||||
Items.Insert(index, item);
|
||||
_entryDic.Add(item, null);
|
||||
container = item as DependencyObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
DependencyObject container;
|
||||
if (IsItemItsOwnContainerOverride(item))
|
||||
{
|
||||
container = item as DependencyObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
container = GetContainerForItemOverride();
|
||||
PrepareContainerForItemOverride(container, item);
|
||||
}
|
||||
|
||||
if (container is CoverViewItem element)
|
||||
{
|
||||
SetBindingForItem(element);
|
||||
element.Style = ItemContainerStyle;
|
||||
element.Header ??= item;
|
||||
_entryDic[item] = element;
|
||||
ItemsHost.Children.Insert(index, element);
|
||||
|
||||
if (IsLoaded && !_isRefresh && _itemsSourceInternal != null)
|
||||
{
|
||||
Items.Insert(index, item);
|
||||
}
|
||||
}
|
||||
container = GetContainerForItemOverride();
|
||||
PrepareContainerForItemOverride(container, item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成序号
|
||||
/// </summary>
|
||||
private void GenerateIndex()
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var item in _entryDic.Values)
|
||||
if (container is CoverViewItem element)
|
||||
{
|
||||
item.Index = index++;
|
||||
}
|
||||
}
|
||||
SetBindingForItem(element);
|
||||
element.Style = ItemContainerStyle;
|
||||
element.Header ??= item;
|
||||
_entryDic[item] = element;
|
||||
ItemsHost.Children.Insert(index, element);
|
||||
|
||||
private void InternalCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
if (_entryDic.Count == 0) return;
|
||||
ClearItems();
|
||||
Items.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (var item in e.OldItems)
|
||||
if (IsLoaded && !_isRefresh && _itemsSourceInternal != null)
|
||||
{
|
||||
RemoveItem(item);
|
||||
Items.Insert(index, item);
|
||||
}
|
||||
}
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
if (_viewContent.IsOpen)
|
||||
{
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
foreach (var item in e.NewItems)
|
||||
{
|
||||
var index = e.NewStartingIndex + count++;
|
||||
InsertItem(index, item);
|
||||
}
|
||||
}
|
||||
|
||||
GenerateIndex();
|
||||
if (_viewContent.IsOpen)
|
||||
{
|
||||
UpdateCoverViewContentPosition();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (_itemsSourceInternal != null) return;
|
||||
|
||||
InternalCollectionChanged(sender, e);
|
||||
}
|
||||
|
||||
protected override void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成序号
|
||||
/// </summary>
|
||||
private void GenerateIndex()
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var item in _entryDic.Values)
|
||||
{
|
||||
item.Index = index++;
|
||||
}
|
||||
}
|
||||
|
||||
private void InternalCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (ItemsHost == null) return;
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
if (_entryDic.Count == 0) return;
|
||||
ClearItems();
|
||||
Items.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (var item in e.OldItems)
|
||||
{
|
||||
RemoveItem(item);
|
||||
}
|
||||
}
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
if (_viewContent.IsOpen)
|
||||
{
|
||||
ItemsHost.Children.Remove(_viewContent);
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
foreach (var item in e.NewItems)
|
||||
{
|
||||
var index = e.NewStartingIndex + count++;
|
||||
InsertItem(index, item);
|
||||
}
|
||||
}
|
||||
|
||||
GenerateIndex();
|
||||
if (_viewContent.IsOpen)
|
||||
{
|
||||
UpdateCoverViewContentPosition();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (_itemsSourceInternal != null) return;
|
||||
|
||||
InternalCollectionChanged(sender, e);
|
||||
}
|
||||
|
||||
protected override void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,118 +5,117 @@ using HandyControl.Expression.Drawing;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementTriangle, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = ElementContent, Type = typeof(FrameworkElement))]
|
||||
public class CoverViewContent : ContentControl
|
||||
{
|
||||
[TemplatePart(Name = ElementTriangle, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = ElementContent, Type = typeof(FrameworkElement))]
|
||||
internal class CoverViewContent : ContentControl
|
||||
private const string ElementTriangle = "PART_Triangle";
|
||||
|
||||
private const string ElementContent = "PART_Content";
|
||||
|
||||
private FrameworkElement _triangle;
|
||||
|
||||
private FrameworkElement _content;
|
||||
|
||||
internal bool WaitForUpdate { get; set; }
|
||||
|
||||
private int _index;
|
||||
|
||||
private int _groups;
|
||||
|
||||
private double _itemWidth;
|
||||
|
||||
internal bool CanSwitch { get; set; } = true;
|
||||
|
||||
private bool _isOpen;
|
||||
|
||||
internal bool IsOpen
|
||||
{
|
||||
private const string ElementTriangle = "PART_Triangle";
|
||||
|
||||
private const string ElementContent = "PART_Content";
|
||||
|
||||
private FrameworkElement _triangle;
|
||||
|
||||
private FrameworkElement _content;
|
||||
|
||||
internal bool WaitForUpdate { get; set; }
|
||||
|
||||
private int _index;
|
||||
|
||||
private int _groups;
|
||||
|
||||
private double _itemWidth;
|
||||
|
||||
internal bool CanSwitch { get; set; } = true;
|
||||
|
||||
private bool _isOpen;
|
||||
|
||||
internal bool IsOpen
|
||||
get => _isOpen;
|
||||
set
|
||||
{
|
||||
get => _isOpen;
|
||||
set
|
||||
{
|
||||
if (_isOpen == value) return;
|
||||
_isOpen = value;
|
||||
OpenSwitch(value);
|
||||
}
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty ManualHeightProperty = DependencyProperty.Register(
|
||||
"ManualHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double0Box), ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
||||
|
||||
internal double ManualHeight
|
||||
{
|
||||
get => (double) GetValue(ManualHeightProperty);
|
||||
set => SetValue(ManualHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.Register(
|
||||
"ContentHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double300Box),
|
||||
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
||||
|
||||
public double ContentHeight
|
||||
{
|
||||
get => (double) GetValue(ContentHeightProperty);
|
||||
set => SetValue(ContentHeightProperty, value);
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_triangle = GetTemplateChild(ElementTriangle) as FrameworkElement;
|
||||
_content = GetTemplateChild(ElementContent) as FrameworkElement;
|
||||
|
||||
if (WaitForUpdate)
|
||||
{
|
||||
_triangle.BeginAnimation(MarginProperty, AnimationHelper.CreateAnimation(new Thickness((_index % _groups + .5) * _itemWidth - _triangle.Width / 2, 0, 0, 0)));
|
||||
OpenSwitch(_isOpen);
|
||||
WaitForUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdatePosition(int index, int groups, double itemWidth)
|
||||
{
|
||||
if (_triangle == null)
|
||||
{
|
||||
_index = index;
|
||||
_groups = groups;
|
||||
_itemWidth = itemWidth;
|
||||
WaitForUpdate = true;
|
||||
return;
|
||||
}
|
||||
_triangle.BeginAnimation(MarginProperty, AnimationHelper.CreateAnimation(new Thickness((index % groups + .5) * itemWidth - _triangle.Width / 2, 0, 0, 0)));
|
||||
if (IsOpen)
|
||||
{
|
||||
if (ManualHeight > 0 && !MathHelper.AreClose(ManualHeight, ContentHeight))
|
||||
{
|
||||
_content.BeginAnimation(HeightProperty, AnimationHelper.CreateAnimation(ManualHeight));
|
||||
}
|
||||
else
|
||||
{
|
||||
_content.BeginAnimation(HeightProperty, AnimationHelper.CreateAnimation(ContentHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenSwitch(bool isOpen)
|
||||
{
|
||||
if (_content == null) return;
|
||||
var animation = AnimationHelper.CreateAnimation(isOpen ? ManualHeight > 0 ? ManualHeight : ContentHeight : 0);
|
||||
_triangle.Show(false);
|
||||
this.Show(true);
|
||||
animation.Completed += (s, e) =>
|
||||
{
|
||||
CanSwitch = true;
|
||||
this.Show(IsOpen);
|
||||
if (IsOpen)
|
||||
{
|
||||
_triangle.Show(true);
|
||||
}
|
||||
};
|
||||
CanSwitch = false;
|
||||
_content.BeginAnimation(HeightProperty, animation);
|
||||
if (_isOpen == value) return;
|
||||
_isOpen = value;
|
||||
OpenSwitch(value);
|
||||
}
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty ManualHeightProperty = DependencyProperty.Register(
|
||||
"ManualHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double0Box), ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
||||
|
||||
internal double ManualHeight
|
||||
{
|
||||
get => (double) GetValue(ManualHeightProperty);
|
||||
set => SetValue(ManualHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.Register(
|
||||
"ContentHeight", typeof(double), typeof(CoverViewContent), new PropertyMetadata(ValueBoxes.Double300Box),
|
||||
ValidateHelper.IsInRangeOfPosDoubleIncludeZero);
|
||||
|
||||
public double ContentHeight
|
||||
{
|
||||
get => (double) GetValue(ContentHeightProperty);
|
||||
set => SetValue(ContentHeightProperty, value);
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_triangle = GetTemplateChild(ElementTriangle) as FrameworkElement;
|
||||
_content = GetTemplateChild(ElementContent) as FrameworkElement;
|
||||
|
||||
if (WaitForUpdate)
|
||||
{
|
||||
_triangle.BeginAnimation(MarginProperty, AnimationHelper.CreateAnimation(new Thickness((_index % _groups + .5) * _itemWidth - _triangle.Width / 2, 0, 0, 0)));
|
||||
OpenSwitch(_isOpen);
|
||||
WaitForUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdatePosition(int index, int groups, double itemWidth)
|
||||
{
|
||||
if (_triangle == null)
|
||||
{
|
||||
_index = index;
|
||||
_groups = groups;
|
||||
_itemWidth = itemWidth;
|
||||
WaitForUpdate = true;
|
||||
return;
|
||||
}
|
||||
_triangle.BeginAnimation(MarginProperty, AnimationHelper.CreateAnimation(new Thickness((index % groups + .5) * itemWidth - _triangle.Width / 2, 0, 0, 0)));
|
||||
if (IsOpen)
|
||||
{
|
||||
if (ManualHeight > 0 && !MathHelper.AreClose(ManualHeight, ContentHeight))
|
||||
{
|
||||
_content.BeginAnimation(HeightProperty, AnimationHelper.CreateAnimation(ManualHeight));
|
||||
}
|
||||
else
|
||||
{
|
||||
_content.BeginAnimation(HeightProperty, AnimationHelper.CreateAnimation(ContentHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenSwitch(bool isOpen)
|
||||
{
|
||||
if (_content == null) return;
|
||||
var animation = AnimationHelper.CreateAnimation(isOpen ? ManualHeight > 0 ? ManualHeight : ContentHeight : 0);
|
||||
_triangle.Show(false);
|
||||
this.Show(true);
|
||||
animation.Completed += (s, e) =>
|
||||
{
|
||||
CanSwitch = true;
|
||||
this.Show(IsOpen);
|
||||
if (IsOpen)
|
||||
{
|
||||
_triangle.Show(true);
|
||||
}
|
||||
};
|
||||
CanSwitch = false;
|
||||
_content.BeginAnimation(HeightProperty, animation);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class CoverViewItem : HeaderedSelectableItem
|
||||
{
|
||||
public class CoverViewItem : HeaderedSelectableItem
|
||||
{
|
||||
internal int Index { get; set; }
|
||||
}
|
||||
internal int Index { get; set; }
|
||||
}
|
||||
@@ -8,168 +8,167 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class Dialog : ContentControl
|
||||
{
|
||||
public class Dialog : ContentControl
|
||||
private string _token;
|
||||
|
||||
private AdornerContainer _container;
|
||||
|
||||
private static readonly Dictionary<string, FrameworkElement> ContainerDic = new();
|
||||
|
||||
public static readonly DependencyProperty IsClosedProperty = DependencyProperty.Register(
|
||||
"IsClosed", typeof(bool), typeof(Dialog), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsClosed
|
||||
{
|
||||
private string _token;
|
||||
get => (bool) GetValue(IsClosedProperty);
|
||||
internal set => SetValue(IsClosedProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private AdornerContainer _container;
|
||||
public static readonly DependencyProperty TokenProperty = DependencyProperty.RegisterAttached(
|
||||
"Token", typeof(string), typeof(Dialog), new PropertyMetadata(default(string), OnTokenChanged));
|
||||
|
||||
private static readonly Dictionary<string, FrameworkElement> ContainerDic = new();
|
||||
|
||||
public static readonly DependencyProperty IsClosedProperty = DependencyProperty.Register(
|
||||
"IsClosed", typeof(bool), typeof(Dialog), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsClosed
|
||||
private static void OnTokenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is FrameworkElement element)
|
||||
{
|
||||
get => (bool) GetValue(IsClosedProperty);
|
||||
internal set => SetValue(IsClosedProperty, ValueBoxes.BooleanBox(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 FrameworkElement element)
|
||||
if (e.NewValue == null)
|
||||
{
|
||||
if (e.NewValue == null)
|
||||
{
|
||||
Unregister(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
Register(e.NewValue.ToString(), element);
|
||||
}
|
||||
Unregister(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
Register(e.NewValue.ToString(), element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetToken(DependencyObject element, string value)
|
||||
=> element.SetValue(TokenProperty, value);
|
||||
public static void SetToken(DependencyObject element, string value)
|
||||
=> element.SetValue(TokenProperty, value);
|
||||
|
||||
public static string GetToken(DependencyObject element)
|
||||
=> (string) element.GetValue(TokenProperty);
|
||||
public static string GetToken(DependencyObject element)
|
||||
=> (string) element.GetValue(TokenProperty);
|
||||
|
||||
public Dialog()
|
||||
public Dialog()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => Close()));
|
||||
}
|
||||
|
||||
public static void Register(string token, FrameworkElement element)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || element == null) return;
|
||||
ContainerDic[token] = element;
|
||||
}
|
||||
|
||||
public static void Unregister(string token, FrameworkElement element)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || element == null) return;
|
||||
|
||||
if (ContainerDic.ContainsKey(token))
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => Close()));
|
||||
}
|
||||
|
||||
public static void Register(string token, FrameworkElement element)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || element == null) return;
|
||||
ContainerDic[token] = element;
|
||||
}
|
||||
|
||||
public static void Unregister(string token, FrameworkElement element)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token) || element == null) return;
|
||||
|
||||
if (ContainerDic.ContainsKey(token))
|
||||
{
|
||||
if (ReferenceEquals(ContainerDic[token], element))
|
||||
{
|
||||
ContainerDic.Remove(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(FrameworkElement element)
|
||||
{
|
||||
if (element == null) return;
|
||||
var first = ContainerDic.FirstOrDefault(item => ReferenceEquals(element, item.Value));
|
||||
if (!string.IsNullOrEmpty(first.Key))
|
||||
{
|
||||
ContainerDic.Remove(first.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token)) return;
|
||||
|
||||
if (ContainerDic.ContainsKey(token))
|
||||
if (ReferenceEquals(ContainerDic[token], element))
|
||||
{
|
||||
ContainerDic.Remove(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Dialog Show<T>(string token = "") where T : new() => Show(new T(), token);
|
||||
|
||||
public static Dialog Show(object content, string token = "")
|
||||
public static void Unregister(FrameworkElement element)
|
||||
{
|
||||
if (element == null) return;
|
||||
var first = ContainerDic.FirstOrDefault(item => ReferenceEquals(element, item.Value));
|
||||
if (!string.IsNullOrEmpty(first.Key))
|
||||
{
|
||||
var dialog = new Dialog
|
||||
{
|
||||
_token = token,
|
||||
Content = content
|
||||
};
|
||||
ContainerDic.Remove(first.Key);
|
||||
}
|
||||
}
|
||||
|
||||
FrameworkElement element;
|
||||
public static void Unregister(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token)) return;
|
||||
|
||||
AdornerDecorator decorator;
|
||||
if (string.IsNullOrEmpty(token))
|
||||
if (ContainerDic.ContainsKey(token))
|
||||
{
|
||||
ContainerDic.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
|
||||
{
|
||||
_token = token,
|
||||
Content = content
|
||||
};
|
||||
|
||||
FrameworkElement element;
|
||||
|
||||
AdornerDecorator decorator;
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
element = WindowHelper.GetActiveWindow();
|
||||
decorator = VisualHelper.GetChild<AdornerDecorator>(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
ContainerDic.TryGetValue(token, out element);
|
||||
decorator = element is System.Windows.Window ?
|
||||
VisualHelper.GetChild<AdornerDecorator>(element) :
|
||||
VisualHelper.GetChild<DialogContainer>(element);
|
||||
}
|
||||
|
||||
if (decorator != null)
|
||||
{
|
||||
if (decorator.Child != null)
|
||||
{
|
||||
element = WindowHelper.GetActiveWindow();
|
||||
decorator = VisualHelper.GetChild<AdornerDecorator>(element);
|
||||
decorator.Child.IsEnabled = false;
|
||||
}
|
||||
else
|
||||
var layer = decorator.AdornerLayer;
|
||||
if (layer != null)
|
||||
{
|
||||
ContainerDic.TryGetValue(token, out element);
|
||||
decorator = element is System.Windows.Window ?
|
||||
VisualHelper.GetChild<AdornerDecorator>(element) :
|
||||
VisualHelper.GetChild<DialogContainer>(element);
|
||||
var container = new AdornerContainer(layer)
|
||||
{
|
||||
Child = dialog
|
||||
};
|
||||
dialog._container = container;
|
||||
dialog.IsClosed = false;
|
||||
layer.Add(container);
|
||||
}
|
||||
}
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_token))
|
||||
{
|
||||
Close(WindowHelper.GetActiveWindow());
|
||||
}
|
||||
else if (ContainerDic.TryGetValue(_token, out var element))
|
||||
{
|
||||
Close(element);
|
||||
}
|
||||
}
|
||||
|
||||
private void Close(DependencyObject element)
|
||||
{
|
||||
if (element != null && _container != null)
|
||||
{
|
||||
var decorator = VisualHelper.GetChild<AdornerDecorator>(element);
|
||||
if (decorator != null)
|
||||
{
|
||||
if (decorator.Child != null)
|
||||
{
|
||||
decorator.Child.IsEnabled = false;
|
||||
decorator.Child.IsEnabled = true;
|
||||
}
|
||||
var layer = decorator.AdornerLayer;
|
||||
if (layer != null)
|
||||
{
|
||||
var container = new AdornerContainer(layer)
|
||||
{
|
||||
Child = dialog
|
||||
};
|
||||
dialog._container = container;
|
||||
dialog.IsClosed = false;
|
||||
layer.Add(container);
|
||||
}
|
||||
}
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_token))
|
||||
{
|
||||
Close(WindowHelper.GetActiveWindow());
|
||||
}
|
||||
else if (ContainerDic.TryGetValue(_token, out var element))
|
||||
{
|
||||
Close(element);
|
||||
}
|
||||
}
|
||||
|
||||
private void Close(DependencyObject element)
|
||||
{
|
||||
if (element != null && _container != null)
|
||||
{
|
||||
var decorator = VisualHelper.GetChild<AdornerDecorator>(element);
|
||||
if (decorator != null)
|
||||
{
|
||||
if (decorator.Child != null)
|
||||
{
|
||||
decorator.Child.IsEnabled = true;
|
||||
}
|
||||
var layer = decorator.AdornerLayer;
|
||||
layer?.Remove(_container);
|
||||
IsClosed = true;
|
||||
}
|
||||
layer?.Remove(_container);
|
||||
IsClosed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class DialogContainer : AdornerDecorator
|
||||
{
|
||||
public class DialogContainer : AdornerDecorator
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,419 +11,418 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[ContentProperty("Content")]
|
||||
public class Drawer : FrameworkElement
|
||||
{
|
||||
[ContentProperty("Content")]
|
||||
public class Drawer : FrameworkElement
|
||||
private Storyboard _storyboard;
|
||||
|
||||
private AdornerContainer _container;
|
||||
|
||||
private ContentControl _animationControl;
|
||||
|
||||
private TranslateTransform _translateTransform;
|
||||
|
||||
private double _animationLength;
|
||||
|
||||
private string _animationPropertyName;
|
||||
|
||||
private FrameworkElement _maskElement;
|
||||
|
||||
private AdornerLayer _layer;
|
||||
|
||||
private UIElement _contentElement;
|
||||
|
||||
private Point _contentRenderTransformOrigin;
|
||||
|
||||
static Drawer()
|
||||
{
|
||||
private Storyboard _storyboard;
|
||||
DataContextProperty.OverrideMetadata(typeof(Drawer), new FrameworkPropertyMetadata(DataContextPropertyChanged));
|
||||
}
|
||||
|
||||
private AdornerContainer _container;
|
||||
public Drawer()
|
||||
{
|
||||
Loaded += Drawer_Loaded;
|
||||
Unloaded += Drawer_Unloaded;
|
||||
}
|
||||
|
||||
private ContentControl _animationControl;
|
||||
|
||||
private TranslateTransform _translateTransform;
|
||||
|
||||
private double _animationLength;
|
||||
|
||||
private string _animationPropertyName;
|
||||
|
||||
private FrameworkElement _maskElement;
|
||||
|
||||
private AdornerLayer _layer;
|
||||
|
||||
private UIElement _contentElement;
|
||||
|
||||
private Point _contentRenderTransformOrigin;
|
||||
|
||||
static Drawer()
|
||||
private void Drawer_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (IsOpen)
|
||||
{
|
||||
DataContextProperty.OverrideMetadata(typeof(Drawer), new FrameworkPropertyMetadata(DataContextPropertyChanged));
|
||||
OnIsOpenChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void Drawer_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Loaded -= Drawer_Loaded;
|
||||
|
||||
if (_maskElement != null)
|
||||
{
|
||||
_maskElement.PreviewMouseLeftButtonDown -= MaskElement_PreviewMouseLeftButtonDown;
|
||||
}
|
||||
|
||||
public Drawer()
|
||||
if (_storyboard != null)
|
||||
{
|
||||
Loaded += Drawer_Loaded;
|
||||
Unloaded += Drawer_Unloaded;
|
||||
_storyboard.Completed -= Storyboard_Completed;
|
||||
}
|
||||
|
||||
private void Drawer_Loaded(object sender, RoutedEventArgs e)
|
||||
_container = null;
|
||||
}
|
||||
|
||||
private static void DataContextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
|
||||
((Drawer) d).OnDataContextPropertyChanged(e);
|
||||
|
||||
private void OnDataContextPropertyChanged(DependencyPropertyChangedEventArgs e) => UpdateDataContext(_animationControl, e.OldValue, e.NewValue);
|
||||
|
||||
public static readonly RoutedEvent OpenedEvent =
|
||||
EventManager.RegisterRoutedEvent("Opened", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(Drawer));
|
||||
|
||||
public event RoutedEventHandler Opened
|
||||
{
|
||||
add => AddHandler(OpenedEvent, value);
|
||||
remove => RemoveHandler(OpenedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent ClosedEvent =
|
||||
EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(Drawer));
|
||||
|
||||
public event RoutedEventHandler Closed
|
||||
{
|
||||
add => AddHandler(ClosedEvent, value);
|
||||
remove => RemoveHandler(ClosedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register(
|
||||
"IsOpen", typeof(bool), typeof(Drawer), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsOpenChanged));
|
||||
|
||||
private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Drawer) d;
|
||||
ctl.OnIsOpenChanged((bool) e.NewValue);
|
||||
}
|
||||
|
||||
public bool IsOpen
|
||||
{
|
||||
get => (bool) GetValue(IsOpenProperty);
|
||||
set => SetValue(IsOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaskCanCloseProperty = DependencyProperty.Register(
|
||||
"MaskCanClose", typeof(bool), typeof(Drawer), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool MaskCanClose
|
||||
{
|
||||
get => (bool) GetValue(MaskCanCloseProperty);
|
||||
set => SetValue(MaskCanCloseProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowMaskProperty = DependencyProperty.Register(
|
||||
"ShowMask", typeof(bool), typeof(Drawer), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool ShowMask
|
||||
{
|
||||
get => (bool) GetValue(ShowMaskProperty);
|
||||
set => SetValue(ShowMaskProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DockProperty = DependencyProperty.Register(
|
||||
"Dock", typeof(Dock), typeof(Drawer), new PropertyMetadata(default(Dock)));
|
||||
|
||||
public Dock Dock
|
||||
{
|
||||
get => (Dock) GetValue(DockProperty);
|
||||
set => SetValue(DockProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowModeProperty = DependencyProperty.Register(
|
||||
"ShowMode", typeof(DrawerShowMode), typeof(Drawer), new PropertyMetadata(default(DrawerShowMode)));
|
||||
|
||||
public DrawerShowMode ShowMode
|
||||
{
|
||||
get => (DrawerShowMode) GetValue(ShowModeProperty);
|
||||
set => SetValue(ShowModeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaskBrushProperty = DependencyProperty.Register(
|
||||
"MaskBrush", typeof(Brush), typeof(Drawer), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public Brush MaskBrush
|
||||
{
|
||||
get => (Brush) GetValue(MaskBrushProperty);
|
||||
set => SetValue(MaskBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
"Content", typeof(object), typeof(Drawer), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
private void CreateContainer()
|
||||
{
|
||||
_storyboard = new Storyboard();
|
||||
_storyboard.Completed += Storyboard_Completed;
|
||||
|
||||
_translateTransform = new TranslateTransform();
|
||||
_animationControl = new ContentControl
|
||||
{
|
||||
if (IsOpen)
|
||||
Content = Content,
|
||||
RenderTransform = _translateTransform,
|
||||
DataContext = this
|
||||
};
|
||||
|
||||
var panel = new SimplePanel
|
||||
{
|
||||
ClipToBounds = true
|
||||
};
|
||||
|
||||
if (ShowMask)
|
||||
{
|
||||
_maskElement = new Border
|
||||
{
|
||||
OnIsOpenChanged(true);
|
||||
}
|
||||
Background = MaskBrush,
|
||||
Opacity = 0
|
||||
};
|
||||
_maskElement.PreviewMouseLeftButtonDown += MaskElement_PreviewMouseLeftButtonDown;
|
||||
panel.Children.Add(_maskElement);
|
||||
}
|
||||
|
||||
private void Drawer_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Loaded -= Drawer_Loaded;
|
||||
_animationControl.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
var size = _animationControl.DesiredSize;
|
||||
|
||||
switch (Dock)
|
||||
{
|
||||
case Dock.Left:
|
||||
_animationControl.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
_animationControl.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
_translateTransform.X = -size.Width;
|
||||
_animationLength = -size.Width;
|
||||
_animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.X)";
|
||||
break;
|
||||
case Dock.Top:
|
||||
_animationControl.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
_animationControl.VerticalAlignment = VerticalAlignment.Top;
|
||||
_translateTransform.Y = -size.Height;
|
||||
_animationLength = -size.Height;
|
||||
_animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.Y)";
|
||||
break;
|
||||
case Dock.Right:
|
||||
_animationControl.HorizontalAlignment = HorizontalAlignment.Right;
|
||||
_animationControl.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
_translateTransform.X = size.Width;
|
||||
_animationLength = size.Width;
|
||||
_animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.X)";
|
||||
break;
|
||||
case Dock.Bottom:
|
||||
_animationControl.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
_animationControl.VerticalAlignment = VerticalAlignment.Bottom;
|
||||
_translateTransform.Y = size.Height;
|
||||
_animationLength = size.Height;
|
||||
_animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.Y)";
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
_animationControl.DataContext = DataContext;
|
||||
_animationControl.CommandBindings.Clear();
|
||||
_animationControl.CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => SetCurrentValue(IsOpenProperty, ValueBoxes.FalseBox)));
|
||||
panel.Children.Add(_animationControl);
|
||||
_container = new AdornerContainer(_layer)
|
||||
{
|
||||
Child = panel,
|
||||
ClipToBounds = true
|
||||
};
|
||||
}
|
||||
|
||||
private void Storyboard_Completed(object sender, EventArgs e)
|
||||
{
|
||||
if (!IsOpen)
|
||||
{
|
||||
_contentElement.SetCurrentValue(RenderTransformOriginProperty, _contentRenderTransformOrigin);
|
||||
_layer.Remove(_container);
|
||||
RaiseEvent(new RoutedEventArgs(ClosedEvent, this));
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseEvent(new RoutedEventArgs(OpenedEvent, this));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIsOpenChanged(bool isOpen)
|
||||
{
|
||||
if (Content == null || DesignerHelper.IsInDesignMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AdornerDecorator decorator;
|
||||
var parent = VisualHelper.GetParent<DrawerContainer>(this);
|
||||
if (parent != null)
|
||||
{
|
||||
_contentElement = parent.Child;
|
||||
decorator = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
var window = WindowHelper.GetActiveWindow();
|
||||
if (window == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
decorator = VisualHelper.GetChild<AdornerDecorator>(window);
|
||||
_contentElement = window.Content as UIElement;
|
||||
}
|
||||
|
||||
if (_contentElement == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_layer = decorator?.AdornerLayer;
|
||||
if (_layer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_contentRenderTransformOrigin = _contentElement.RenderTransformOrigin;
|
||||
|
||||
if (_container == null)
|
||||
{
|
||||
CreateContainer();
|
||||
}
|
||||
|
||||
switch (ShowMode)
|
||||
{
|
||||
case DrawerShowMode.Push:
|
||||
ShowByPush(isOpen);
|
||||
break;
|
||||
case DrawerShowMode.Press:
|
||||
_contentElement.SetCurrentValue(RenderTransformOriginProperty, new Point(0.5, 0.5));
|
||||
ShowByPress(isOpen);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isOpen)
|
||||
{
|
||||
if (_maskElement != null)
|
||||
{
|
||||
_maskElement.PreviewMouseLeftButtonDown -= MaskElement_PreviewMouseLeftButtonDown;
|
||||
var maskAnimation = AnimationHelper.CreateAnimation(1);
|
||||
Storyboard.SetTarget(maskAnimation, _maskElement);
|
||||
Storyboard.SetTargetProperty(maskAnimation, new PropertyPath(OpacityProperty.Name));
|
||||
_storyboard.Children.Add(maskAnimation);
|
||||
}
|
||||
|
||||
if (_storyboard != null)
|
||||
var drawerAnimation = AnimationHelper.CreateAnimation(0);
|
||||
Storyboard.SetTarget(drawerAnimation, _animationControl);
|
||||
Storyboard.SetTargetProperty(drawerAnimation, new PropertyPath(_animationPropertyName));
|
||||
_storyboard.Children.Add(drawerAnimation);
|
||||
_layer.Remove(_container);
|
||||
_layer.Add(_container);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_maskElement != null)
|
||||
{
|
||||
_storyboard.Completed -= Storyboard_Completed;
|
||||
var maskAnimation = AnimationHelper.CreateAnimation(0);
|
||||
Storyboard.SetTarget(maskAnimation, _maskElement);
|
||||
Storyboard.SetTargetProperty(maskAnimation, new PropertyPath(OpacityProperty.Name));
|
||||
_storyboard.Children.Add(maskAnimation);
|
||||
}
|
||||
|
||||
_container = null;
|
||||
var drawerAnimation = AnimationHelper.CreateAnimation(_animationLength);
|
||||
Storyboard.SetTarget(drawerAnimation, _animationControl);
|
||||
Storyboard.SetTargetProperty(drawerAnimation, new PropertyPath(_animationPropertyName));
|
||||
_storyboard.Children.Add(drawerAnimation);
|
||||
}
|
||||
_storyboard.Begin();
|
||||
}
|
||||
|
||||
private static void DataContextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
|
||||
((Drawer) d).OnDataContextPropertyChanged(e);
|
||||
private void ShowByPush(bool isOpen)
|
||||
{
|
||||
string animationPropertyName;
|
||||
|
||||
private void OnDataContextPropertyChanged(DependencyPropertyChangedEventArgs e) => UpdateDataContext(_animationControl, e.OldValue, e.NewValue);
|
||||
|
||||
public static readonly RoutedEvent OpenedEvent =
|
||||
EventManager.RegisterRoutedEvent("Opened", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(Drawer));
|
||||
|
||||
public event RoutedEventHandler Opened
|
||||
switch (Dock)
|
||||
{
|
||||
add => AddHandler(OpenedEvent, value);
|
||||
remove => RemoveHandler(OpenedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent ClosedEvent =
|
||||
EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(Drawer));
|
||||
|
||||
public event RoutedEventHandler Closed
|
||||
{
|
||||
add => AddHandler(ClosedEvent, value);
|
||||
remove => RemoveHandler(ClosedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register(
|
||||
"IsOpen", typeof(bool), typeof(Drawer), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsOpenChanged));
|
||||
|
||||
private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Drawer) d;
|
||||
ctl.OnIsOpenChanged((bool) e.NewValue);
|
||||
}
|
||||
|
||||
public bool IsOpen
|
||||
{
|
||||
get => (bool) GetValue(IsOpenProperty);
|
||||
set => SetValue(IsOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaskCanCloseProperty = DependencyProperty.Register(
|
||||
"MaskCanClose", typeof(bool), typeof(Drawer), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool MaskCanClose
|
||||
{
|
||||
get => (bool) GetValue(MaskCanCloseProperty);
|
||||
set => SetValue(MaskCanCloseProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowMaskProperty = DependencyProperty.Register(
|
||||
"ShowMask", typeof(bool), typeof(Drawer), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool ShowMask
|
||||
{
|
||||
get => (bool) GetValue(ShowMaskProperty);
|
||||
set => SetValue(ShowMaskProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DockProperty = DependencyProperty.Register(
|
||||
"Dock", typeof(Dock), typeof(Drawer), new PropertyMetadata(default(Dock)));
|
||||
|
||||
public Dock Dock
|
||||
{
|
||||
get => (Dock) GetValue(DockProperty);
|
||||
set => SetValue(DockProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowModeProperty = DependencyProperty.Register(
|
||||
"ShowMode", typeof(DrawerShowMode), typeof(Drawer), new PropertyMetadata(default(DrawerShowMode)));
|
||||
|
||||
public DrawerShowMode ShowMode
|
||||
{
|
||||
get => (DrawerShowMode) GetValue(ShowModeProperty);
|
||||
set => SetValue(ShowModeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaskBrushProperty = DependencyProperty.Register(
|
||||
"MaskBrush", typeof(Brush), typeof(Drawer), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public Brush MaskBrush
|
||||
{
|
||||
get => (Brush) GetValue(MaskBrushProperty);
|
||||
set => SetValue(MaskBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
"Content", typeof(object), typeof(Drawer), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
private void CreateContainer()
|
||||
{
|
||||
_storyboard = new Storyboard();
|
||||
_storyboard.Completed += Storyboard_Completed;
|
||||
|
||||
_translateTransform = new TranslateTransform();
|
||||
_animationControl = new ContentControl
|
||||
{
|
||||
Content = Content,
|
||||
RenderTransform = _translateTransform,
|
||||
DataContext = this
|
||||
};
|
||||
|
||||
var panel = new SimplePanel
|
||||
{
|
||||
ClipToBounds = true
|
||||
};
|
||||
|
||||
if (ShowMask)
|
||||
{
|
||||
_maskElement = new Border
|
||||
case Dock.Left:
|
||||
case Dock.Right:
|
||||
animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.X)";
|
||||
_contentElement.RenderTransform = new TranslateTransform
|
||||
{
|
||||
Background = MaskBrush,
|
||||
Opacity = 0
|
||||
X = isOpen ? 0 : -_animationLength
|
||||
};
|
||||
_maskElement.PreviewMouseLeftButtonDown += MaskElement_PreviewMouseLeftButtonDown;
|
||||
panel.Children.Add(_maskElement);
|
||||
}
|
||||
|
||||
_animationControl.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
var size = _animationControl.DesiredSize;
|
||||
|
||||
switch (Dock)
|
||||
{
|
||||
case Dock.Left:
|
||||
_animationControl.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
_animationControl.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
_translateTransform.X = -size.Width;
|
||||
_animationLength = -size.Width;
|
||||
_animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.X)";
|
||||
break;
|
||||
case Dock.Top:
|
||||
_animationControl.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
_animationControl.VerticalAlignment = VerticalAlignment.Top;
|
||||
_translateTransform.Y = -size.Height;
|
||||
_animationLength = -size.Height;
|
||||
_animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.Y)";
|
||||
break;
|
||||
case Dock.Right:
|
||||
_animationControl.HorizontalAlignment = HorizontalAlignment.Right;
|
||||
_animationControl.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
_translateTransform.X = size.Width;
|
||||
_animationLength = size.Width;
|
||||
_animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.X)";
|
||||
break;
|
||||
case Dock.Bottom:
|
||||
_animationControl.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
_animationControl.VerticalAlignment = VerticalAlignment.Bottom;
|
||||
_translateTransform.Y = size.Height;
|
||||
_animationLength = size.Height;
|
||||
_animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.Y)";
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
_animationControl.DataContext = DataContext;
|
||||
_animationControl.CommandBindings.Clear();
|
||||
_animationControl.CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => SetCurrentValue(IsOpenProperty, ValueBoxes.FalseBox)));
|
||||
panel.Children.Add(_animationControl);
|
||||
_container = new AdornerContainer(_layer)
|
||||
{
|
||||
Child = panel,
|
||||
ClipToBounds = true
|
||||
};
|
||||
}
|
||||
|
||||
private void Storyboard_Completed(object sender, EventArgs e)
|
||||
{
|
||||
if (!IsOpen)
|
||||
{
|
||||
_contentElement.SetCurrentValue(RenderTransformOriginProperty, _contentRenderTransformOrigin);
|
||||
_layer.Remove(_container);
|
||||
RaiseEvent(new RoutedEventArgs(ClosedEvent, this));
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseEvent(new RoutedEventArgs(OpenedEvent, this));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIsOpenChanged(bool isOpen)
|
||||
{
|
||||
if (Content == null || DesignerHelper.IsInDesignMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AdornerDecorator decorator;
|
||||
var parent = VisualHelper.GetParent<DrawerContainer>(this);
|
||||
if (parent != null)
|
||||
{
|
||||
_contentElement = parent.Child;
|
||||
decorator = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
var window = WindowHelper.GetActiveWindow();
|
||||
if (window == null)
|
||||
break;
|
||||
case Dock.Top:
|
||||
case Dock.Bottom:
|
||||
animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.Y)";
|
||||
_contentElement.RenderTransform = new TranslateTransform
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
decorator = VisualHelper.GetChild<AdornerDecorator>(window);
|
||||
_contentElement = window.Content as UIElement;
|
||||
}
|
||||
|
||||
if (_contentElement == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_layer = decorator?.AdornerLayer;
|
||||
if (_layer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_contentRenderTransformOrigin = _contentElement.RenderTransformOrigin;
|
||||
|
||||
if (_container == null)
|
||||
{
|
||||
CreateContainer();
|
||||
}
|
||||
|
||||
switch (ShowMode)
|
||||
{
|
||||
case DrawerShowMode.Push:
|
||||
ShowByPush(isOpen);
|
||||
break;
|
||||
case DrawerShowMode.Press:
|
||||
_contentElement.SetCurrentValue(RenderTransformOriginProperty, new Point(0.5, 0.5));
|
||||
ShowByPress(isOpen);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isOpen)
|
||||
{
|
||||
if (_maskElement != null)
|
||||
{
|
||||
var maskAnimation = AnimationHelper.CreateAnimation(1);
|
||||
Storyboard.SetTarget(maskAnimation, _maskElement);
|
||||
Storyboard.SetTargetProperty(maskAnimation, new PropertyPath(OpacityProperty.Name));
|
||||
_storyboard.Children.Add(maskAnimation);
|
||||
}
|
||||
|
||||
var drawerAnimation = AnimationHelper.CreateAnimation(0);
|
||||
Storyboard.SetTarget(drawerAnimation, _animationControl);
|
||||
Storyboard.SetTargetProperty(drawerAnimation, new PropertyPath(_animationPropertyName));
|
||||
_storyboard.Children.Add(drawerAnimation);
|
||||
_layer.Remove(_container);
|
||||
_layer.Add(_container);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_maskElement != null)
|
||||
{
|
||||
var maskAnimation = AnimationHelper.CreateAnimation(0);
|
||||
Storyboard.SetTarget(maskAnimation, _maskElement);
|
||||
Storyboard.SetTargetProperty(maskAnimation, new PropertyPath(OpacityProperty.Name));
|
||||
_storyboard.Children.Add(maskAnimation);
|
||||
}
|
||||
|
||||
var drawerAnimation = AnimationHelper.CreateAnimation(_animationLength);
|
||||
Storyboard.SetTarget(drawerAnimation, _animationControl);
|
||||
Storyboard.SetTargetProperty(drawerAnimation, new PropertyPath(_animationPropertyName));
|
||||
_storyboard.Children.Add(drawerAnimation);
|
||||
}
|
||||
_storyboard.Begin();
|
||||
}
|
||||
|
||||
private void ShowByPush(bool isOpen)
|
||||
{
|
||||
string animationPropertyName;
|
||||
|
||||
switch (Dock)
|
||||
{
|
||||
case Dock.Left:
|
||||
case Dock.Right:
|
||||
animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.X)";
|
||||
_contentElement.RenderTransform = new TranslateTransform
|
||||
{
|
||||
X = isOpen ? 0 : -_animationLength
|
||||
};
|
||||
break;
|
||||
case Dock.Top:
|
||||
case Dock.Bottom:
|
||||
animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.Y)";
|
||||
_contentElement.RenderTransform = new TranslateTransform
|
||||
{
|
||||
Y = isOpen ? 0 : -_animationLength
|
||||
};
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
var animation = isOpen
|
||||
? AnimationHelper.CreateAnimation(-_animationLength)
|
||||
: AnimationHelper.CreateAnimation(0);
|
||||
Storyboard.SetTarget(animation, _contentElement);
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath(animationPropertyName));
|
||||
|
||||
_storyboard.Children.Add(animation);
|
||||
}
|
||||
|
||||
private void ShowByPress(bool isOpen)
|
||||
{
|
||||
_contentElement.RenderTransform = isOpen
|
||||
? new ScaleTransform()
|
||||
: new ScaleTransform
|
||||
{
|
||||
ScaleX = 0.9,
|
||||
ScaleY = 0.9
|
||||
Y = isOpen ? 0 : -_animationLength
|
||||
};
|
||||
|
||||
var animationX = isOpen
|
||||
? AnimationHelper.CreateAnimation(.9)
|
||||
: AnimationHelper.CreateAnimation(1);
|
||||
Storyboard.SetTarget(animationX, _contentElement);
|
||||
Storyboard.SetTargetProperty(animationX, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleX)"));
|
||||
|
||||
_storyboard.Children.Add(animationX);
|
||||
|
||||
var animationY = isOpen
|
||||
? AnimationHelper.CreateAnimation(.9)
|
||||
: AnimationHelper.CreateAnimation(1);
|
||||
Storyboard.SetTarget(animationY, _contentElement);
|
||||
Storyboard.SetTargetProperty(animationY, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleY)"));
|
||||
|
||||
_storyboard.Children.Add(animationY);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
private void MaskElement_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (MaskCanClose)
|
||||
{
|
||||
SetCurrentValue(IsOpenProperty, ValueBoxes.FalseBox);
|
||||
}
|
||||
}
|
||||
var animation = isOpen
|
||||
? AnimationHelper.CreateAnimation(-_animationLength)
|
||||
: AnimationHelper.CreateAnimation(0);
|
||||
Storyboard.SetTarget(animation, _contentElement);
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath(animationPropertyName));
|
||||
|
||||
private void UpdateDataContext(FrameworkElement target, object oldValue, object newValue)
|
||||
{
|
||||
if (target == null || BindingOperations.GetBindingExpression(target, DataContextProperty) != null) return;
|
||||
if (ReferenceEquals(this, target.DataContext) || Equals(oldValue, target.DataContext))
|
||||
_storyboard.Children.Add(animation);
|
||||
}
|
||||
|
||||
private void ShowByPress(bool isOpen)
|
||||
{
|
||||
_contentElement.RenderTransform = isOpen
|
||||
? new ScaleTransform()
|
||||
: new ScaleTransform
|
||||
{
|
||||
target.DataContext = newValue ?? this;
|
||||
}
|
||||
ScaleX = 0.9,
|
||||
ScaleY = 0.9
|
||||
};
|
||||
|
||||
var animationX = isOpen
|
||||
? AnimationHelper.CreateAnimation(.9)
|
||||
: AnimationHelper.CreateAnimation(1);
|
||||
Storyboard.SetTarget(animationX, _contentElement);
|
||||
Storyboard.SetTargetProperty(animationX, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleX)"));
|
||||
|
||||
_storyboard.Children.Add(animationX);
|
||||
|
||||
var animationY = isOpen
|
||||
? AnimationHelper.CreateAnimation(.9)
|
||||
: AnimationHelper.CreateAnimation(1);
|
||||
Storyboard.SetTarget(animationY, _contentElement);
|
||||
Storyboard.SetTargetProperty(animationY, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleY)"));
|
||||
|
||||
_storyboard.Children.Add(animationY);
|
||||
}
|
||||
|
||||
private void MaskElement_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (MaskCanClose)
|
||||
{
|
||||
SetCurrentValue(IsOpenProperty, ValueBoxes.FalseBox);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDataContext(FrameworkElement target, object oldValue, object newValue)
|
||||
{
|
||||
if (target == null || BindingOperations.GetBindingExpression(target, DataContextProperty) != null) return;
|
||||
if (ReferenceEquals(this, target.DataContext) || Equals(oldValue, target.DataContext))
|
||||
{
|
||||
target.DataContext = newValue ?? this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class DrawerContainer : AdornerDecorator
|
||||
{
|
||||
public class DrawerContainer : AdornerDecorator
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -4,39 +4,38 @@ using System.Windows.Controls;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public sealed class GrowlWindow : Window
|
||||
{
|
||||
public sealed class GrowlWindow : Window
|
||||
internal Panel GrowlPanel { get; set; }
|
||||
|
||||
internal GrowlWindow()
|
||||
{
|
||||
internal Panel GrowlPanel { get; set; }
|
||||
WindowStyle = WindowStyle.None;
|
||||
AllowsTransparency = true;
|
||||
|
||||
internal GrowlWindow()
|
||||
GrowlPanel = new StackPanel
|
||||
{
|
||||
WindowStyle = WindowStyle.None;
|
||||
AllowsTransparency = true;
|
||||
VerticalAlignment = VerticalAlignment.Top
|
||||
};
|
||||
|
||||
GrowlPanel = new StackPanel
|
||||
{
|
||||
VerticalAlignment = VerticalAlignment.Top
|
||||
};
|
||||
|
||||
Content = new ScrollViewer
|
||||
{
|
||||
VerticalScrollBarVisibility = ScrollBarVisibility.Hidden,
|
||||
IsInertiaEnabled = true,
|
||||
Content = GrowlPanel
|
||||
};
|
||||
}
|
||||
|
||||
internal void Init()
|
||||
Content = new ScrollViewer
|
||||
{
|
||||
var desktopWorkingArea = SystemParameters.WorkArea;
|
||||
Height = desktopWorkingArea.Height;
|
||||
Left = desktopWorkingArea.Right - Width;
|
||||
Top = 0;
|
||||
}
|
||||
|
||||
protected override void OnSourceInitialized(EventArgs e)
|
||||
=> InteropMethods.IntDestroyMenu(this.GetHwndSource().CreateHandleRef());
|
||||
VerticalScrollBarVisibility = ScrollBarVisibility.Hidden,
|
||||
IsInertiaEnabled = true,
|
||||
Content = GrowlPanel
|
||||
};
|
||||
}
|
||||
|
||||
internal void Init()
|
||||
{
|
||||
var desktopWorkingArea = SystemParameters.WorkArea;
|
||||
Height = desktopWorkingArea.Height;
|
||||
Left = desktopWorkingArea.Right - Width;
|
||||
Top = 0;
|
||||
}
|
||||
|
||||
protected override void OnSourceInitialized(EventArgs e)
|
||||
=> InteropMethods.IntDestroyMenu(this.GetHwndSource().CreateHandleRef());
|
||||
}
|
||||
@@ -15,504 +15,503 @@ using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class GifImage : Image, IDisposable
|
||||
{
|
||||
public class GifImage : Image, IDisposable
|
||||
private static readonly Guid GifGuid = new("{b96b3caa-0728-11d3-9d7b-0000f81ef32e}");
|
||||
|
||||
private static readonly Guid GifSingleFrameGuid = new("{b96b3cb0-0728-11d3-9d7b-0000f81ef32e}");
|
||||
|
||||
internal IntPtr NativeImage;
|
||||
|
||||
private byte[] _rawData;
|
||||
|
||||
private bool _isStart;
|
||||
|
||||
private bool _isLoaded;
|
||||
|
||||
static GifImage()
|
||||
{
|
||||
private static readonly Guid GifGuid = new("{b96b3caa-0728-11d3-9d7b-0000f81ef32e}");
|
||||
VisibilityProperty.OverrideMetadata(typeof(GifImage), new PropertyMetadata(default(Visibility), OnVisibilityChanged));
|
||||
}
|
||||
|
||||
private static readonly Guid GifSingleFrameGuid = new("{b96b3cb0-0728-11d3-9d7b-0000f81ef32e}");
|
||||
public static readonly DependencyProperty UriProperty = DependencyProperty.Register(
|
||||
"Uri", typeof(Uri), typeof(GifImage), new PropertyMetadata(default(Uri), OnUriChanged));
|
||||
|
||||
internal IntPtr NativeImage;
|
||||
private static void OnUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (GifImage) d;
|
||||
ctl.StopAnimate();
|
||||
|
||||
private byte[] _rawData;
|
||||
|
||||
private bool _isStart;
|
||||
|
||||
private bool _isLoaded;
|
||||
|
||||
static GifImage()
|
||||
if (e.NewValue != null)
|
||||
{
|
||||
VisibilityProperty.OverrideMetadata(typeof(GifImage), new PropertyMetadata(default(Visibility), OnVisibilityChanged));
|
||||
var v = (Uri) e.NewValue;
|
||||
ctl.GetGifStreamFromPack(v);
|
||||
ctl.StartAnimate();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.Source = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Uri Uri
|
||||
{
|
||||
get => (Uri) GetValue(UriProperty);
|
||||
set => SetValue(UriProperty, value);
|
||||
}
|
||||
|
||||
private static void OnVisibilityChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (GifImage) s;
|
||||
if (ctl.NativeImage == IntPtr.Zero) return;
|
||||
|
||||
var v = (Visibility) e.NewValue;
|
||||
if (v != Visibility.Visible)
|
||||
{
|
||||
ctl.StopAnimate();
|
||||
}
|
||||
else if (!ctl._isStart)
|
||||
{
|
||||
ctl.StartAnimate();
|
||||
}
|
||||
}
|
||||
|
||||
~GifImage() => Dispose(false);
|
||||
|
||||
public GifImage()
|
||||
{
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
if (DesignerProperties.GetIsInDesignMode(this)) return;
|
||||
if (_isLoaded) return;
|
||||
_isLoaded = true;
|
||||
if (Uri != null)
|
||||
{
|
||||
GetGifStreamFromPack(Uri);
|
||||
StartAnimate();
|
||||
}
|
||||
else if (Source is BitmapImage image)
|
||||
{
|
||||
GetGifStreamFromPack(image.UriSource);
|
||||
StartAnimate();
|
||||
}
|
||||
};
|
||||
|
||||
Unloaded += (s, e) => Dispose();
|
||||
}
|
||||
|
||||
public GifImage(string filename)
|
||||
{
|
||||
Source = null;
|
||||
CreateSourceFromFile(filename);
|
||||
StartAnimate();
|
||||
}
|
||||
|
||||
public GifImage(Stream stream)
|
||||
{
|
||||
Source = null;
|
||||
CreateSourceFromStream(stream);
|
||||
StartAnimate();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (NativeImage == IntPtr.Zero) return;
|
||||
try
|
||||
{
|
||||
StopAnimate();
|
||||
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(this, NativeImage));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeImage = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateSourceFromFile(string filename)
|
||||
{
|
||||
filename = Path.GetFullPath(filename);
|
||||
|
||||
var status = InteropMethods.Gdip.GdipCreateBitmapFromFile(filename, out var bitmap);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UriProperty = DependencyProperty.Register(
|
||||
"Uri", typeof(Uri), typeof(GifImage), new PropertyMetadata(default(Uri), OnUriChanged));
|
||||
SetNativeImage(bitmap);
|
||||
|
||||
private static void OnUriChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
EnsureSave(this, filename, null);
|
||||
}
|
||||
|
||||
private void CreateSourceFromStream(Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
throw new ArgumentException("stream null");
|
||||
|
||||
var status = InteropMethods.Gdip.GdipCreateBitmapFromStream(new GPStream(stream), out var bitmap);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
var ctl = (GifImage) d;
|
||||
ctl.StopAnimate();
|
||||
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
if (e.NewValue != null)
|
||||
SetNativeImage(bitmap);
|
||||
|
||||
EnsureSave(this, null, stream);
|
||||
}
|
||||
|
||||
private void GetGifStreamFromPack(Uri uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
StreamResourceInfo streamInfo;
|
||||
|
||||
if (!uri.IsAbsoluteUri)
|
||||
{
|
||||
var v = (Uri) e.NewValue;
|
||||
ctl.GetGifStreamFromPack(v);
|
||||
ctl.StartAnimate();
|
||||
streamInfo = Application.GetContentStream(uri) ?? Application.GetResourceStream(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.Source = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Uri Uri
|
||||
{
|
||||
get => (Uri) GetValue(UriProperty);
|
||||
set => SetValue(UriProperty, value);
|
||||
}
|
||||
|
||||
private static void OnVisibilityChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (GifImage) s;
|
||||
if (ctl.NativeImage == IntPtr.Zero) return;
|
||||
|
||||
var v = (Visibility) e.NewValue;
|
||||
if (v != Visibility.Visible)
|
||||
{
|
||||
ctl.StopAnimate();
|
||||
}
|
||||
else if (!ctl._isStart)
|
||||
{
|
||||
ctl.StartAnimate();
|
||||
}
|
||||
}
|
||||
|
||||
~GifImage() => Dispose(false);
|
||||
|
||||
public GifImage()
|
||||
{
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
if (DesignerProperties.GetIsInDesignMode(this)) return;
|
||||
if (_isLoaded) return;
|
||||
_isLoaded = true;
|
||||
if (Uri != null)
|
||||
if (uri.GetLeftPart(UriPartial.Authority).Contains("siteoforigin"))
|
||||
{
|
||||
GetGifStreamFromPack(Uri);
|
||||
StartAnimate();
|
||||
}
|
||||
else if (Source is BitmapImage image)
|
||||
{
|
||||
GetGifStreamFromPack(image.UriSource);
|
||||
StartAnimate();
|
||||
}
|
||||
};
|
||||
|
||||
Unloaded += (s, e) => Dispose();
|
||||
}
|
||||
|
||||
public GifImage(string filename)
|
||||
{
|
||||
Source = null;
|
||||
CreateSourceFromFile(filename);
|
||||
StartAnimate();
|
||||
}
|
||||
|
||||
public GifImage(Stream stream)
|
||||
{
|
||||
Source = null;
|
||||
CreateSourceFromStream(stream);
|
||||
StartAnimate();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (NativeImage == IntPtr.Zero) return;
|
||||
try
|
||||
{
|
||||
StopAnimate();
|
||||
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(this, NativeImage));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeImage = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateSourceFromFile(string filename)
|
||||
{
|
||||
filename = Path.GetFullPath(filename);
|
||||
|
||||
var status = InteropMethods.Gdip.GdipCreateBitmapFromFile(filename, out var bitmap);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
SetNativeImage(bitmap);
|
||||
|
||||
EnsureSave(this, filename, null);
|
||||
}
|
||||
|
||||
private void CreateSourceFromStream(Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
throw new ArgumentException("stream null");
|
||||
|
||||
var status = InteropMethods.Gdip.GdipCreateBitmapFromStream(new GPStream(stream), out var bitmap);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
SetNativeImage(bitmap);
|
||||
|
||||
EnsureSave(this, null, stream);
|
||||
}
|
||||
|
||||
private void GetGifStreamFromPack(Uri uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
StreamResourceInfo streamInfo;
|
||||
|
||||
if (!uri.IsAbsoluteUri)
|
||||
{
|
||||
streamInfo = Application.GetContentStream(uri) ?? Application.GetResourceStream(uri);
|
||||
streamInfo = Application.GetRemoteStream(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (uri.GetLeftPart(UriPartial.Authority).Contains("siteoforigin"))
|
||||
{
|
||||
streamInfo = Application.GetRemoteStream(uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
streamInfo = Application.GetContentStream(uri) ?? Application.GetResourceStream(uri);
|
||||
}
|
||||
}
|
||||
|
||||
if (streamInfo == null)
|
||||
{
|
||||
throw new FileNotFoundException("Resource not found.", uri.ToString());
|
||||
}
|
||||
|
||||
CreateSourceFromStream(streamInfo.Stream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchToCommonImage()
|
||||
{
|
||||
if (Source == null && Uri != null)
|
||||
{
|
||||
SetCurrentValue(SourceProperty, new BitmapImage(Uri));
|
||||
}
|
||||
}
|
||||
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
|
||||
internal static void EnsureSave(GifImage image, string filename, Stream dataStream)
|
||||
{
|
||||
if (!image.RawGuid.Equals(GifGuid) && !image.RawGuid.Equals(GifSingleFrameGuid))
|
||||
{
|
||||
image.SwitchToCommonImage();
|
||||
return;
|
||||
}
|
||||
|
||||
var animatedGif = false;
|
||||
var dimensions = image.FrameDimensionsList;
|
||||
if (dimensions.Select(guid => new GifFrameDimension(guid)).Contains(GifFrameDimension.Time))
|
||||
{
|
||||
animatedGif = image.GetFrameCount(GifFrameDimension.Time) > 1;
|
||||
}
|
||||
|
||||
if (!animatedGif)
|
||||
{
|
||||
image.SwitchToCommonImage();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Stream created = null;
|
||||
long lastPos = 0;
|
||||
if (dataStream != null)
|
||||
{
|
||||
lastPos = dataStream.Position;
|
||||
dataStream.Position = 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (dataStream == null)
|
||||
{
|
||||
created = dataStream = File.OpenRead(filename);
|
||||
}
|
||||
|
||||
image._rawData = new byte[(int) dataStream.Length];
|
||||
dataStream.Read(image._rawData, 0, (int) dataStream.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (created != null)
|
||||
{
|
||||
created.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ReSharper disable once PossibleNullReferenceException
|
||||
dataStream.Position = lastPos;
|
||||
}
|
||||
streamInfo = Application.GetContentStream(uri) ?? Application.GetResourceStream(uri);
|
||||
}
|
||||
}
|
||||
// possible exceptions for reading the filename
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
}
|
||||
// possible exceptions for setting/getting the position inside dataStream
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
// possible exception when reading stuff into dataStream
|
||||
catch (ArgumentException)
|
||||
|
||||
if (streamInfo == null)
|
||||
{
|
||||
throw new FileNotFoundException("Resource not found.", uri.ToString());
|
||||
}
|
||||
|
||||
CreateSourceFromStream(streamInfo.Stream);
|
||||
}
|
||||
|
||||
internal void SetNativeImage(IntPtr handle)
|
||||
catch
|
||||
{
|
||||
if (handle == IntPtr.Zero)
|
||||
throw new ArgumentException("NativeHandle0");
|
||||
|
||||
NativeImage = handle;
|
||||
}
|
||||
|
||||
internal Guid RawGuid
|
||||
{
|
||||
get
|
||||
{
|
||||
var guid = new Guid();
|
||||
|
||||
var status = InteropMethods.Gdip.GdipGetImageRawFormat(new HandleRef(this, NativeImage), ref guid);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
return guid;
|
||||
}
|
||||
}
|
||||
|
||||
internal void StartAnimate()
|
||||
{
|
||||
ImageAnimator.Animate(this, OnFrameChanged);
|
||||
_isStart = true;
|
||||
}
|
||||
|
||||
internal void StopAnimate()
|
||||
{
|
||||
ImageAnimator.StopAnimate(this, OnFrameChanged);
|
||||
_isStart = false;
|
||||
}
|
||||
|
||||
internal Guid[] FrameDimensionsList
|
||||
{
|
||||
get
|
||||
{
|
||||
var status = InteropMethods.Gdip.GdipImageGetFrameDimensionsCount(new HandleRef(this, NativeImage), out var count);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
if (count <= 0)
|
||||
{
|
||||
return new Guid[0];
|
||||
}
|
||||
|
||||
var size = Marshal.SizeOf(typeof(Guid));
|
||||
|
||||
var buffer = Marshal.AllocHGlobal(checked(size * count));
|
||||
if (buffer == IntPtr.Zero)
|
||||
{
|
||||
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
|
||||
}
|
||||
|
||||
status = InteropMethods.Gdip.GdipImageGetFrameDimensionsList(new HandleRef(this, NativeImage), buffer, count);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
Marshal.FreeHGlobal(buffer);
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
var guids = new Guid[count];
|
||||
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
guids[i] = (Guid) InteropMethods.PtrToStructure((IntPtr) ((long) buffer + size * i), typeof(Guid));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(buffer);
|
||||
}
|
||||
|
||||
return guids;
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetFrameCount(GifFrameDimension dimension)
|
||||
{
|
||||
var count = new[] { 0 };
|
||||
|
||||
var dimensionId = dimension.Guid;
|
||||
var status = InteropMethods.Gdip.GdipImageGetFrameCount(new HandleRef(this, NativeImage), ref dimensionId, count);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
return count[0];
|
||||
}
|
||||
|
||||
internal GifPropertyItem GetPropertyItem(int propid)
|
||||
{
|
||||
GifPropertyItem propitem;
|
||||
|
||||
var status = InteropMethods.Gdip.GdipGetPropertyItemSize(new HandleRef(this, NativeImage), propid, out var size);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
if (size == 0)
|
||||
return null;
|
||||
|
||||
var propdata = Marshal.AllocHGlobal(size);
|
||||
|
||||
if (propdata == IntPtr.Zero)
|
||||
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
|
||||
|
||||
status = InteropMethods.Gdip.GdipGetPropertyItem(new HandleRef(this, NativeImage), propid, size, propdata);
|
||||
|
||||
try
|
||||
{
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
propitem = GifPropertyItemInternal.ConvertFromMemory(propdata, 1)[0];
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(propdata);
|
||||
}
|
||||
|
||||
return propitem;
|
||||
}
|
||||
|
||||
internal int SelectActiveFrame(GifFrameDimension dimension, int frameIndex)
|
||||
{
|
||||
var count = new[] { 0 };
|
||||
|
||||
var dimensionId = dimension.Guid;
|
||||
var status = InteropMethods.Gdip.GdipImageSelectActiveFrame(new HandleRef(this, NativeImage), ref dimensionId, frameIndex);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
return count[0];
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
[ResourceConsumption(ResourceScope.Machine)]
|
||||
internal IntPtr GetHbitmap() => GetHbitmap(Colors.LightGray);
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
[ResourceConsumption(ResourceScope.Machine)]
|
||||
internal IntPtr GetHbitmap(Color background)
|
||||
{
|
||||
var status = InteropMethods.Gdip.GdipCreateHBITMAPFromBitmap(new HandleRef(this, NativeImage), out var hBitmap,
|
||||
ColorHelper.ToWin32(background));
|
||||
if (status == 2 && (Width >= short.MaxValue || Height >= short.MaxValue))
|
||||
{
|
||||
throw new ArgumentException("GdiplusInvalidSize");
|
||||
}
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok && NativeImage != IntPtr.Zero)
|
||||
{
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
private void GetBitmapSource()
|
||||
{
|
||||
var handle = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
handle = GetHbitmap();
|
||||
Source = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty,
|
||||
BitmapSizeOptions.FromEmptyOptions());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
InteropMethods.DeleteObject(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFrameChanged(object sender, EventArgs e)
|
||||
{
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
ImageAnimator.UpdateFrames();
|
||||
Source?.Freeze();
|
||||
GetBitmapSource();
|
||||
InvalidateVisual();
|
||||
}));
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchToCommonImage()
|
||||
{
|
||||
if (Source == null && Uri != null)
|
||||
{
|
||||
SetCurrentValue(SourceProperty, new BitmapImage(Uri));
|
||||
}
|
||||
}
|
||||
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
|
||||
internal static void EnsureSave(GifImage image, string filename, Stream dataStream)
|
||||
{
|
||||
if (!image.RawGuid.Equals(GifGuid) && !image.RawGuid.Equals(GifSingleFrameGuid))
|
||||
{
|
||||
image.SwitchToCommonImage();
|
||||
return;
|
||||
}
|
||||
|
||||
var animatedGif = false;
|
||||
var dimensions = image.FrameDimensionsList;
|
||||
if (dimensions.Select(guid => new GifFrameDimension(guid)).Contains(GifFrameDimension.Time))
|
||||
{
|
||||
animatedGif = image.GetFrameCount(GifFrameDimension.Time) > 1;
|
||||
}
|
||||
|
||||
if (!animatedGif)
|
||||
{
|
||||
image.SwitchToCommonImage();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Stream created = null;
|
||||
long lastPos = 0;
|
||||
if (dataStream != null)
|
||||
{
|
||||
lastPos = dataStream.Position;
|
||||
dataStream.Position = 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (dataStream == null)
|
||||
{
|
||||
created = dataStream = File.OpenRead(filename);
|
||||
}
|
||||
|
||||
image._rawData = new byte[(int) dataStream.Length];
|
||||
dataStream.Read(image._rawData, 0, (int) dataStream.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (created != null)
|
||||
{
|
||||
created.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ReSharper disable once PossibleNullReferenceException
|
||||
dataStream.Position = lastPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
// possible exceptions for reading the filename
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
}
|
||||
// possible exceptions for setting/getting the position inside dataStream
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
// possible exception when reading stuff into dataStream
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetNativeImage(IntPtr handle)
|
||||
{
|
||||
if (handle == IntPtr.Zero)
|
||||
throw new ArgumentException("NativeHandle0");
|
||||
|
||||
NativeImage = handle;
|
||||
}
|
||||
|
||||
internal Guid RawGuid
|
||||
{
|
||||
get
|
||||
{
|
||||
var guid = new Guid();
|
||||
|
||||
var status = InteropMethods.Gdip.GdipGetImageRawFormat(new HandleRef(this, NativeImage), ref guid);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
return guid;
|
||||
}
|
||||
}
|
||||
|
||||
internal void StartAnimate()
|
||||
{
|
||||
ImageAnimator.Animate(this, OnFrameChanged);
|
||||
_isStart = true;
|
||||
}
|
||||
|
||||
internal void StopAnimate()
|
||||
{
|
||||
ImageAnimator.StopAnimate(this, OnFrameChanged);
|
||||
_isStart = false;
|
||||
}
|
||||
|
||||
internal Guid[] FrameDimensionsList
|
||||
{
|
||||
get
|
||||
{
|
||||
var status = InteropMethods.Gdip.GdipImageGetFrameDimensionsCount(new HandleRef(this, NativeImage), out var count);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
if (count <= 0)
|
||||
{
|
||||
return new Guid[0];
|
||||
}
|
||||
|
||||
var size = Marshal.SizeOf(typeof(Guid));
|
||||
|
||||
var buffer = Marshal.AllocHGlobal(checked(size * count));
|
||||
if (buffer == IntPtr.Zero)
|
||||
{
|
||||
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
|
||||
}
|
||||
|
||||
status = InteropMethods.Gdip.GdipImageGetFrameDimensionsList(new HandleRef(this, NativeImage), buffer, count);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
Marshal.FreeHGlobal(buffer);
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
var guids = new Guid[count];
|
||||
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
guids[i] = (Guid) InteropMethods.PtrToStructure((IntPtr) ((long) buffer + size * i), typeof(Guid));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(buffer);
|
||||
}
|
||||
|
||||
return guids;
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetFrameCount(GifFrameDimension dimension)
|
||||
{
|
||||
var count = new[] { 0 };
|
||||
|
||||
var dimensionId = dimension.Guid;
|
||||
var status = InteropMethods.Gdip.GdipImageGetFrameCount(new HandleRef(this, NativeImage), ref dimensionId, count);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
return count[0];
|
||||
}
|
||||
|
||||
internal GifPropertyItem GetPropertyItem(int propid)
|
||||
{
|
||||
GifPropertyItem propitem;
|
||||
|
||||
var status = InteropMethods.Gdip.GdipGetPropertyItemSize(new HandleRef(this, NativeImage), propid, out var size);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
if (size == 0)
|
||||
return null;
|
||||
|
||||
var propdata = Marshal.AllocHGlobal(size);
|
||||
|
||||
if (propdata == IntPtr.Zero)
|
||||
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
|
||||
|
||||
status = InteropMethods.Gdip.GdipGetPropertyItem(new HandleRef(this, NativeImage), propid, size, propdata);
|
||||
|
||||
try
|
||||
{
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
{
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
propitem = GifPropertyItemInternal.ConvertFromMemory(propdata, 1)[0];
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(propdata);
|
||||
}
|
||||
|
||||
return propitem;
|
||||
}
|
||||
|
||||
internal int SelectActiveFrame(GifFrameDimension dimension, int frameIndex)
|
||||
{
|
||||
var count = new[] { 0 };
|
||||
|
||||
var dimensionId = dimension.Guid;
|
||||
var status = InteropMethods.Gdip.GdipImageSelectActiveFrame(new HandleRef(this, NativeImage), ref dimensionId, frameIndex);
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok)
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
|
||||
return count[0];
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
[ResourceConsumption(ResourceScope.Machine)]
|
||||
internal IntPtr GetHbitmap() => GetHbitmap(Colors.LightGray);
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
[ResourceConsumption(ResourceScope.Machine)]
|
||||
internal IntPtr GetHbitmap(Color background)
|
||||
{
|
||||
var status = InteropMethods.Gdip.GdipCreateHBITMAPFromBitmap(new HandleRef(this, NativeImage), out var hBitmap,
|
||||
ColorHelper.ToWin32(background));
|
||||
if (status == 2 && (Width >= short.MaxValue || Height >= short.MaxValue))
|
||||
{
|
||||
throw new ArgumentException("GdiplusInvalidSize");
|
||||
}
|
||||
|
||||
if (status != InteropMethods.Gdip.Ok && NativeImage != IntPtr.Zero)
|
||||
{
|
||||
throw InteropMethods.Gdip.StatusException(status);
|
||||
}
|
||||
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
private void GetBitmapSource()
|
||||
{
|
||||
var handle = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
handle = GetHbitmap();
|
||||
Source = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty,
|
||||
BitmapSizeOptions.FromEmptyOptions());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
InteropMethods.DeleteObject(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFrameChanged(object sender, EventArgs e)
|
||||
{
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
ImageAnimator.UpdateFrames();
|
||||
Source?.Freeze();
|
||||
GetBitmapSource();
|
||||
InvalidateVisual();
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -5,228 +5,227 @@ using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ImageBlock : FrameworkElement
|
||||
{
|
||||
public class ImageBlock : FrameworkElement
|
||||
private readonly DispatcherTimer _dispatcherTimer;
|
||||
|
||||
private BitmapSource _source;
|
||||
|
||||
private int _indexMax;
|
||||
|
||||
private int _indexMin;
|
||||
|
||||
private int _currentIndex;
|
||||
|
||||
private int _blockWidth;
|
||||
|
||||
private int _blockHeight;
|
||||
|
||||
private bool _isDisposed;
|
||||
|
||||
private int _columns = 1;
|
||||
|
||||
public ImageBlock()
|
||||
{
|
||||
private readonly DispatcherTimer _dispatcherTimer;
|
||||
|
||||
private BitmapSource _source;
|
||||
|
||||
private int _indexMax;
|
||||
|
||||
private int _indexMin;
|
||||
|
||||
private int _currentIndex;
|
||||
|
||||
private int _blockWidth;
|
||||
|
||||
private int _blockHeight;
|
||||
|
||||
private bool _isDisposed;
|
||||
|
||||
private int _columns = 1;
|
||||
|
||||
public ImageBlock()
|
||||
_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Render)
|
||||
{
|
||||
_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Render)
|
||||
Interval = Interval
|
||||
};
|
||||
|
||||
IsVisibleChanged += ImageBlock_IsVisibleChanged;
|
||||
}
|
||||
|
||||
~ImageBlock() => Dispose();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
|
||||
IsVisibleChanged -= ImageBlock_IsVisibleChanged;
|
||||
_dispatcherTimer.Stop();
|
||||
_isDisposed = true;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void ImageBlock_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (IsVisible)
|
||||
{
|
||||
_dispatcherTimer.Tick += DispatcherTimer_Tick;
|
||||
if (IsPlaying)
|
||||
{
|
||||
Interval = Interval
|
||||
};
|
||||
|
||||
IsVisibleChanged += ImageBlock_IsVisibleChanged;
|
||||
_dispatcherTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
~ImageBlock() => Dispose();
|
||||
|
||||
public void Dispose()
|
||||
else
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
|
||||
IsVisibleChanged -= ImageBlock_IsVisibleChanged;
|
||||
_dispatcherTimer.Stop();
|
||||
_isDisposed = true;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void ImageBlock_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (IsVisible)
|
||||
{
|
||||
_dispatcherTimer.Tick += DispatcherTimer_Tick;
|
||||
if (IsPlaying)
|
||||
{
|
||||
_dispatcherTimer.Start();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_dispatcherTimer.Stop();
|
||||
_dispatcherTimer.Tick -= DispatcherTimer_Tick;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDatas()
|
||||
{
|
||||
if (_source == null) return;
|
||||
|
||||
_indexMin = StartRow * _columns + StartColumn;
|
||||
_indexMax = EndRow * _columns + EndColumn;
|
||||
_currentIndex = _indexMin;
|
||||
_blockWidth = _source.PixelWidth / _columns;
|
||||
_blockHeight = _source.PixelHeight / Rows;
|
||||
}
|
||||
|
||||
private static void OnPositionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ImageBlock) d;
|
||||
|
||||
if (e.Property == ColumnsProperty)
|
||||
{
|
||||
ctl._columns = (int) e.NewValue;
|
||||
}
|
||||
|
||||
ctl.UpdateDatas();
|
||||
}
|
||||
|
||||
private void DispatcherTimer_Tick(object sender, EventArgs e) => InvalidateVisual();
|
||||
|
||||
public static readonly DependencyProperty StartColumnProperty = DependencyProperty.Register(
|
||||
"StartColumn", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
|
||||
|
||||
public int StartColumn
|
||||
{
|
||||
get => (int) GetValue(StartColumnProperty);
|
||||
set => SetValue(StartColumnProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StartRowProperty = DependencyProperty.Register(
|
||||
"StartRow", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
|
||||
|
||||
public int StartRow
|
||||
{
|
||||
get => (int) GetValue(StartRowProperty);
|
||||
set => SetValue(StartRowProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EndColumnProperty = DependencyProperty.Register(
|
||||
"EndColumn", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
|
||||
|
||||
public int EndColumn
|
||||
{
|
||||
get => (int) GetValue(EndColumnProperty);
|
||||
set => SetValue(EndColumnProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EndRowProperty = DependencyProperty.Register(
|
||||
"EndRow", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
|
||||
|
||||
public int EndRow
|
||||
{
|
||||
get => (int) GetValue(EndRowProperty);
|
||||
set => SetValue(EndRowProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(
|
||||
"IsPlaying", typeof(bool), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnIsPlayingChanged));
|
||||
|
||||
private static void OnIsPlayingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ImageBlock) d;
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
ctl._dispatcherTimer.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl._dispatcherTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPlaying
|
||||
{
|
||||
get => (bool) GetValue(IsPlayingProperty);
|
||||
set => SetValue(IsPlayingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register(
|
||||
"Columns", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int1Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged), obj => (int) obj >= 1);
|
||||
|
||||
public int Columns
|
||||
{
|
||||
get => (int) GetValue(ColumnsProperty);
|
||||
set => SetValue(ColumnsProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RowsProperty = DependencyProperty.Register(
|
||||
"Rows", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int1Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged), obj => (int) obj >= 1);
|
||||
|
||||
public int Rows
|
||||
{
|
||||
get => (int) GetValue(RowsProperty);
|
||||
set => SetValue(RowsProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register(
|
||||
"Interval", typeof(TimeSpan), typeof(ImageBlock), new PropertyMetadata(TimeSpan.FromSeconds(1), OnIntervalChanged));
|
||||
|
||||
private static void OnIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ImageBlock) d;
|
||||
ctl._dispatcherTimer.Interval = (TimeSpan) e.NewValue;
|
||||
}
|
||||
|
||||
public TimeSpan Interval
|
||||
{
|
||||
get => (TimeSpan) GetValue(IntervalProperty);
|
||||
set => SetValue(IntervalProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
|
||||
"Source", typeof(ImageSource), typeof(ImageBlock), new FrameworkPropertyMetadata(default(ImageSource),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnSourceChanged));
|
||||
|
||||
private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ImageBlock) d;
|
||||
ctl._source = e.NewValue as BitmapSource;
|
||||
ctl.UpdateDatas();
|
||||
}
|
||||
|
||||
public ImageSource Source
|
||||
{
|
||||
get => (ImageSource) GetValue(SourceProperty);
|
||||
set => SetValue(SourceProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
{
|
||||
if (_source == null) return;
|
||||
var croppedBitmap = new CroppedBitmap(_source, CalDisplayRect());
|
||||
dc.DrawImage(croppedBitmap, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
|
||||
}
|
||||
|
||||
private Int32Rect CalDisplayRect()
|
||||
{
|
||||
if (_currentIndex > _indexMax)
|
||||
{
|
||||
_currentIndex = _indexMin;
|
||||
}
|
||||
|
||||
var x = _currentIndex % _columns * _blockWidth;
|
||||
var y = _currentIndex / _columns * _blockHeight;
|
||||
|
||||
var rect = new Int32Rect(x, y, _blockWidth, _blockHeight);
|
||||
_currentIndex++;
|
||||
return rect;
|
||||
_dispatcherTimer.Tick -= DispatcherTimer_Tick;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDatas()
|
||||
{
|
||||
if (_source == null) return;
|
||||
|
||||
_indexMin = StartRow * _columns + StartColumn;
|
||||
_indexMax = EndRow * _columns + EndColumn;
|
||||
_currentIndex = _indexMin;
|
||||
_blockWidth = _source.PixelWidth / _columns;
|
||||
_blockHeight = _source.PixelHeight / Rows;
|
||||
}
|
||||
|
||||
private static void OnPositionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ImageBlock) d;
|
||||
|
||||
if (e.Property == ColumnsProperty)
|
||||
{
|
||||
ctl._columns = (int) e.NewValue;
|
||||
}
|
||||
|
||||
ctl.UpdateDatas();
|
||||
}
|
||||
|
||||
private void DispatcherTimer_Tick(object sender, EventArgs e) => InvalidateVisual();
|
||||
|
||||
public static readonly DependencyProperty StartColumnProperty = DependencyProperty.Register(
|
||||
"StartColumn", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
|
||||
|
||||
public int StartColumn
|
||||
{
|
||||
get => (int) GetValue(StartColumnProperty);
|
||||
set => SetValue(StartColumnProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StartRowProperty = DependencyProperty.Register(
|
||||
"StartRow", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
|
||||
|
||||
public int StartRow
|
||||
{
|
||||
get => (int) GetValue(StartRowProperty);
|
||||
set => SetValue(StartRowProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EndColumnProperty = DependencyProperty.Register(
|
||||
"EndColumn", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
|
||||
|
||||
public int EndColumn
|
||||
{
|
||||
get => (int) GetValue(EndColumnProperty);
|
||||
set => SetValue(EndColumnProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EndRowProperty = DependencyProperty.Register(
|
||||
"EndRow", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int0Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged));
|
||||
|
||||
public int EndRow
|
||||
{
|
||||
get => (int) GetValue(EndRowProperty);
|
||||
set => SetValue(EndRowProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(
|
||||
"IsPlaying", typeof(bool), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.FalseBox,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnIsPlayingChanged));
|
||||
|
||||
private static void OnIsPlayingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ImageBlock) d;
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
ctl._dispatcherTimer.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl._dispatcherTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPlaying
|
||||
{
|
||||
get => (bool) GetValue(IsPlayingProperty);
|
||||
set => SetValue(IsPlayingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register(
|
||||
"Columns", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int1Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged), obj => (int) obj >= 1);
|
||||
|
||||
public int Columns
|
||||
{
|
||||
get => (int) GetValue(ColumnsProperty);
|
||||
set => SetValue(ColumnsProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RowsProperty = DependencyProperty.Register(
|
||||
"Rows", typeof(int), typeof(ImageBlock), new FrameworkPropertyMetadata(ValueBoxes.Int1Box,
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnPositionsChanged), obj => (int) obj >= 1);
|
||||
|
||||
public int Rows
|
||||
{
|
||||
get => (int) GetValue(RowsProperty);
|
||||
set => SetValue(RowsProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IntervalProperty = DependencyProperty.Register(
|
||||
"Interval", typeof(TimeSpan), typeof(ImageBlock), new PropertyMetadata(TimeSpan.FromSeconds(1), OnIntervalChanged));
|
||||
|
||||
private static void OnIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ImageBlock) d;
|
||||
ctl._dispatcherTimer.Interval = (TimeSpan) e.NewValue;
|
||||
}
|
||||
|
||||
public TimeSpan Interval
|
||||
{
|
||||
get => (TimeSpan) GetValue(IntervalProperty);
|
||||
set => SetValue(IntervalProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
|
||||
"Source", typeof(ImageSource), typeof(ImageBlock), new FrameworkPropertyMetadata(default(ImageSource),
|
||||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnSourceChanged));
|
||||
|
||||
private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (ImageBlock) d;
|
||||
ctl._source = e.NewValue as BitmapSource;
|
||||
ctl.UpdateDatas();
|
||||
}
|
||||
|
||||
public ImageSource Source
|
||||
{
|
||||
get => (ImageSource) GetValue(SourceProperty);
|
||||
set => SetValue(SourceProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
{
|
||||
if (_source == null) return;
|
||||
var croppedBitmap = new CroppedBitmap(_source, CalDisplayRect());
|
||||
dc.DrawImage(croppedBitmap, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
|
||||
}
|
||||
|
||||
private Int32Rect CalDisplayRect()
|
||||
{
|
||||
if (_currentIndex > _indexMax)
|
||||
{
|
||||
_currentIndex = _indexMin;
|
||||
}
|
||||
|
||||
var x = _currentIndex % _columns * _blockWidth;
|
||||
var y = _currentIndex / _columns * _blockHeight;
|
||||
|
||||
var rect = new Int32Rect(x, y, _blockWidth, _blockHeight);
|
||||
_currentIndex++;
|
||||
return rect;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
+117
-118
@@ -4,156 +4,155 @@ using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools.Helper;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = SearchTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
public class AutoCompleteTextBox : ComboBox
|
||||
{
|
||||
[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()
|
||||
{
|
||||
private const string SearchTextBox = "PART_SearchTextBox";
|
||||
TextProperty.OverrideMetadata(typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
}
|
||||
|
||||
private bool ignoreTextChanging;
|
||||
|
||||
private System.Windows.Controls.TextBox _searchTextBox;
|
||||
|
||||
private object _selectedItem;
|
||||
|
||||
static AutoCompleteTextBox()
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
TextProperty.OverrideMetadata(typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
_searchTextBox.GotFocus -= SearchTextBoxGotFocus;
|
||||
_searchTextBox.KeyDown -= SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged -= SearchTextBoxTextChanged;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_searchTextBox = GetTemplateChild(SearchTextBox) as System.Windows.Controls.TextBox;
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
_searchTextBox.GotFocus -= SearchTextBoxGotFocus;
|
||||
_searchTextBox.KeyDown -= SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged -= SearchTextBoxTextChanged;
|
||||
}
|
||||
_searchTextBox.GotFocus += SearchTextBoxGotFocus;
|
||||
_searchTextBox.PreviewKeyDown += SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged += SearchTextBoxTextChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
UpdateTextBoxBySelectedItem(_selectedItem);
|
||||
}
|
||||
|
||||
_searchTextBox = GetTemplateChild(SearchTextBox) as System.Windows.Controls.TextBox;
|
||||
if (_searchTextBox != null)
|
||||
{
|
||||
_searchTextBox.GotFocus += SearchTextBoxGotFocus;
|
||||
_searchTextBox.PreviewKeyDown += SearchTextBoxKeyDown;
|
||||
_searchTextBox.TextChanged += SearchTextBoxTextChanged;
|
||||
}
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
base.OnSelectionChanged(e);
|
||||
|
||||
if (e.AddedItems.Count > 0)
|
||||
{
|
||||
_selectedItem = e.AddedItems[0];
|
||||
UpdateTextBoxBySelectedItem(_selectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
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)
|
||||
{
|
||||
base.OnSelectionChanged(e);
|
||||
|
||||
if (e.AddedItems.Count > 0)
|
||||
{
|
||||
_selectedItem = e.AddedItems[0];
|
||||
UpdateTextBoxBySelectedItem(_selectedItem);
|
||||
}
|
||||
ignoreTextChanging = false;
|
||||
return;
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is AutoCompleteTextBoxItem;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new AutoCompleteTextBoxItem();
|
||||
|
||||
private void SearchTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
Text = _searchTextBox.Text;
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
{
|
||||
_selectedItem = null;
|
||||
SelectedIndex = -1;
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
_searchTextBox.Focus();
|
||||
}
|
||||
else if (_searchTextBox.IsFocused)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
|
||||
if (ignoreTextChanging)
|
||||
private void SearchTextBoxKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Up)
|
||||
{
|
||||
var index = SelectedIndex - 1;
|
||||
if (index < 0)
|
||||
{
|
||||
ignoreTextChanging = false;
|
||||
return;
|
||||
index = Items.Count - 1;
|
||||
}
|
||||
|
||||
Text = _searchTextBox.Text;
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
UpdateTextBoxBySelectedIndex(index);
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
var index = SelectedIndex + 1;
|
||||
if (index >= Items.Count)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.FalseBox);
|
||||
_searchTextBox.Focus();
|
||||
}
|
||||
else if (_searchTextBox.IsFocused)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
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;
|
||||
}
|
||||
|
||||
private void SearchTextBoxKeyDown(object sender, KeyEventArgs e)
|
||||
ignoreTextChanging = true;
|
||||
|
||||
if (ItemContainerGenerator.ContainerFromIndex(selectedIndex) is AutoCompleteTextBoxItem boxItem)
|
||||
{
|
||||
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.Text = BindingHelper.GetString(boxItem.Content, DisplayMemberPath);
|
||||
_searchTextBox.CaretIndex = _searchTextBox.Text.Length;
|
||||
|
||||
ignoreTextChanging = true;
|
||||
SelectedIndex = selectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
Text = _searchTextBox.Text;
|
||||
|
||||
ignoreTextChanging = false;
|
||||
private void UpdateTextBoxBySelectedItem(object selectedItem)
|
||||
{
|
||||
if (_searchTextBox == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private void SearchTextBoxGotFocus(object sender, RoutedEventArgs e)
|
||||
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))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
SetCurrentValue(IsDropDownOpenProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -1,9 +1,8 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class AutoCompleteTextBoxItem : ComboBoxItem
|
||||
{
|
||||
public class AutoCompleteTextBoxItem : ComboBoxItem
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,284 +9,283 @@ using System.Windows.Threading;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
[TemplatePart(Name = ElementSelectAll, Type = typeof(CheckComboBoxItem))]
|
||||
public class CheckComboBox : ListBox, IDataInput
|
||||
{
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
[TemplatePart(Name = ElementSelectAll, Type = typeof(CheckComboBoxItem))]
|
||||
public class CheckComboBox : ListBox, IDataInput
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
|
||||
private const string ElementSelectAll = "PART_SelectAll";
|
||||
|
||||
private Panel _panel;
|
||||
|
||||
private CheckComboBoxItem _selectAllItem;
|
||||
|
||||
private bool _isInternalAction;
|
||||
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private const string ElementSelectAll = "PART_SelectAll";
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(CheckComboBox), new PropertyMetadata(default(string)));
|
||||
|
||||
private Panel _panel;
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
private CheckComboBoxItem _selectAllItem;
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(CheckComboBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
private bool _isInternalAction;
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaxDropDownHeightProperty =
|
||||
System.Windows.Controls.ComboBox.MaxDropDownHeightProperty.AddOwner(typeof(CheckComboBox),
|
||||
new FrameworkPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3));
|
||||
|
||||
[Bindable(true), Category("Layout")]
|
||||
[TypeConverter(typeof(LengthConverter))]
|
||||
public double MaxDropDownHeight
|
||||
{
|
||||
get => (double) GetValue(MaxDropDownHeightProperty);
|
||||
set => SetValue(MaxDropDownHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
|
||||
"IsDropDownOpen", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox, OnIsDropDownOpenChanged));
|
||||
|
||||
private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (CheckComboBox) d;
|
||||
|
||||
if (!(bool) e.NewValue)
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(CheckComboBox), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(CheckComboBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaxDropDownHeightProperty =
|
||||
System.Windows.Controls.ComboBox.MaxDropDownHeightProperty.AddOwner(typeof(CheckComboBox),
|
||||
new FrameworkPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3));
|
||||
|
||||
[Bindable(true), Category("Layout")]
|
||||
[TypeConverter(typeof(LengthConverter))]
|
||||
public double MaxDropDownHeight
|
||||
{
|
||||
get => (double) GetValue(MaxDropDownHeightProperty);
|
||||
set => SetValue(MaxDropDownHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register(
|
||||
"IsDropDownOpen", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox, OnIsDropDownOpenChanged));
|
||||
|
||||
private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (CheckComboBox) d;
|
||||
|
||||
if (!(bool) e.NewValue)
|
||||
ctl.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
ctl.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
Mouse.Capture(null);
|
||||
}), DispatcherPriority.Send);
|
||||
Mouse.Capture(null);
|
||||
}), DispatcherPriority.Send);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDropDownOpen
|
||||
{
|
||||
get => (bool) GetValue(IsDropDownOpenProperty);
|
||||
set => SetValue(IsDropDownOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TagStyleProperty = DependencyProperty.Register(
|
||||
"TagStyle", typeof(Style), typeof(CheckComboBox), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style TagStyle
|
||||
{
|
||||
get => (Style) GetValue(TagStyleProperty);
|
||||
set => SetValue(TagStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowSelectAllButtonProperty = DependencyProperty.Register(
|
||||
"ShowSelectAllButton", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowSelectAllButton
|
||||
{
|
||||
get => (bool) GetValue(ShowSelectAllButtonProperty);
|
||||
set => SetValue(ShowSelectAllButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public CheckComboBox()
|
||||
{
|
||||
AddHandler(Controls.Tag.ClosedEvent, new RoutedEventHandler(Tags_OnClosed));
|
||||
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
SetCurrentValue(SelectedValueProperty, null);
|
||||
SetCurrentValue(SelectedItemProperty, null);
|
||||
SetCurrentValue(SelectedIndexProperty, -1);
|
||||
SelectedItems.Clear();
|
||||
}));
|
||||
|
||||
ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
|
||||
}
|
||||
|
||||
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
|
||||
{
|
||||
UpdateTags();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_selectAllItem.Selected -= SelectAllItem_Selected;
|
||||
_selectAllItem.Unselected -= SelectAllItem_Unselected;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_panel = GetTemplateChild(ElementPanel) as Panel;
|
||||
_selectAllItem = GetTemplateChild(ElementSelectAll) as CheckComboBoxItem;
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_selectAllItem.Selected += SelectAllItem_Selected;
|
||||
_selectAllItem.Unselected += SelectAllItem_Unselected;
|
||||
}
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
IsDropDownOpen = true;
|
||||
IsDropDownOpen = false;
|
||||
}), DispatcherPriority.DataBind);
|
||||
}
|
||||
|
||||
public bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedItems.Count > 0)
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDropDownOpen
|
||||
{
|
||||
get => (bool) GetValue(IsDropDownOpenProperty);
|
||||
set => SetValue(IsDropDownOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TagStyleProperty = DependencyProperty.Register(
|
||||
"TagStyle", typeof(Style), typeof(CheckComboBox), new PropertyMetadata(default(Style)));
|
||||
|
||||
public Style TagStyle
|
||||
{
|
||||
get => (Style) GetValue(TagStyleProperty);
|
||||
set => SetValue(TagStyleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowSelectAllButtonProperty = DependencyProperty.Register(
|
||||
"ShowSelectAllButton", typeof(bool), typeof(CheckComboBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowSelectAllButton
|
||||
{
|
||||
get => (bool) GetValue(ShowSelectAllButtonProperty);
|
||||
set => SetValue(ShowSelectAllButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public CheckComboBox()
|
||||
{
|
||||
AddHandler(Controls.Tag.ClosedEvent, new RoutedEventHandler(Tags_OnClosed));
|
||||
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
SetCurrentValue(SelectedValueProperty, null);
|
||||
SetCurrentValue(SelectedItemProperty, null);
|
||||
SetCurrentValue(SelectedIndexProperty, -1);
|
||||
SelectedItems.Clear();
|
||||
}));
|
||||
|
||||
ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
|
||||
}
|
||||
|
||||
private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
|
||||
{
|
||||
UpdateTags();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_selectAllItem.Selected -= SelectAllItem_Selected;
|
||||
_selectAllItem.Unselected -= SelectAllItem_Unselected;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_panel = GetTemplateChild(ElementPanel) as Panel;
|
||||
_selectAllItem = GetTemplateChild(ElementSelectAll) as CheckComboBoxItem;
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_selectAllItem.Selected += SelectAllItem_Selected;
|
||||
_selectAllItem.Unselected += SelectAllItem_Unselected;
|
||||
}
|
||||
|
||||
Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
IsDropDownOpen = true;
|
||||
IsDropDownOpen = false;
|
||||
}), DispatcherPriority.DataBind);
|
||||
}
|
||||
|
||||
public bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(null);
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedItems.Count > 0)
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
UpdateTags();
|
||||
VerifyData();
|
||||
|
||||
base.OnSelectionChanged(e);
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is CheckComboBoxItem;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new CheckComboBoxItem();
|
||||
|
||||
protected override void OnDisplayMemberPathChanged(string oldDisplayMemberPath, string newDisplayMemberPath) => UpdateTags();
|
||||
|
||||
private void Tags_OnClosed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is Tag { Tag: CheckComboBoxItem checkComboBoxItem })
|
||||
{
|
||||
checkComboBoxItem.SetCurrentValue(IsSelectedProperty, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchAllItems(bool selected)
|
||||
{
|
||||
if (_isInternalAction) return;
|
||||
_isInternalAction = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (ItemContainerGenerator.ContainerFromItem(item) is CheckComboBoxItem checkComboBoxItem)
|
||||
{
|
||||
checkComboBoxItem.SetCurrentValue(ListBoxItem.IsSelectedProperty, selected);
|
||||
}
|
||||
}
|
||||
|
||||
_isInternalAction = false;
|
||||
UpdateTags();
|
||||
}
|
||||
|
||||
private void SelectAllItem_Selected(object sender, RoutedEventArgs e) => SwitchAllItems(true);
|
||||
|
||||
private void SelectAllItem_Unselected(object sender, RoutedEventArgs e) => SwitchAllItems(false);
|
||||
|
||||
private void UpdateTags()
|
||||
{
|
||||
if (_panel == null || _isInternalAction) return;
|
||||
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_isInternalAction = true;
|
||||
_selectAllItem.SetCurrentValue(IsSelectedProperty, SelectedItems.Count == Items.Count);
|
||||
_isInternalAction = false;
|
||||
}
|
||||
|
||||
_panel.Children.Clear();
|
||||
|
||||
foreach (var item in SelectedItems)
|
||||
{
|
||||
if (ItemContainerGenerator.ContainerFromItem(item) is CheckComboBoxItem checkComboBoxItem)
|
||||
{
|
||||
var tag = new Tag
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
Style = TagStyle,
|
||||
Tag = checkComboBoxItem
|
||||
};
|
||||
|
||||
if (ItemsSource != null)
|
||||
{
|
||||
tag.SetBinding(ContentControl.ContentProperty, new Binding(DisplayMemberPath) { Source = item });
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
tag.Content = checkComboBoxItem.Content;
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
UpdateTags();
|
||||
VerifyData();
|
||||
|
||||
base.OnSelectionChanged(e);
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item) => item is CheckComboBoxItem;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new CheckComboBoxItem();
|
||||
|
||||
protected override void OnDisplayMemberPathChanged(string oldDisplayMemberPath, string newDisplayMemberPath) => UpdateTags();
|
||||
|
||||
private void Tags_OnClosed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is Tag { Tag: CheckComboBoxItem checkComboBoxItem })
|
||||
{
|
||||
checkComboBoxItem.SetCurrentValue(IsSelectedProperty, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchAllItems(bool selected)
|
||||
{
|
||||
if (_isInternalAction) return;
|
||||
_isInternalAction = true;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (ItemContainerGenerator.ContainerFromItem(item) is CheckComboBoxItem checkComboBoxItem)
|
||||
{
|
||||
checkComboBoxItem.SetCurrentValue(ListBoxItem.IsSelectedProperty, selected);
|
||||
}
|
||||
}
|
||||
|
||||
_isInternalAction = false;
|
||||
UpdateTags();
|
||||
}
|
||||
|
||||
private void SelectAllItem_Selected(object sender, RoutedEventArgs e) => SwitchAllItems(true);
|
||||
|
||||
private void SelectAllItem_Unselected(object sender, RoutedEventArgs e) => SwitchAllItems(false);
|
||||
|
||||
private void UpdateTags()
|
||||
{
|
||||
if (_panel == null || _isInternalAction) return;
|
||||
|
||||
if (_selectAllItem != null)
|
||||
{
|
||||
_isInternalAction = true;
|
||||
_selectAllItem.SetCurrentValue(IsSelectedProperty, SelectedItems.Count == Items.Count);
|
||||
_isInternalAction = false;
|
||||
}
|
||||
|
||||
_panel.Children.Clear();
|
||||
|
||||
foreach (var item in SelectedItems)
|
||||
{
|
||||
if (ItemContainerGenerator.ContainerFromItem(item) is CheckComboBoxItem checkComboBoxItem)
|
||||
{
|
||||
var tag = new Tag
|
||||
{
|
||||
Style = TagStyle,
|
||||
Tag = checkComboBoxItem
|
||||
};
|
||||
|
||||
if (ItemsSource != null)
|
||||
{
|
||||
tag.SetBinding(ContentControl.ContentProperty, new Binding(DisplayMemberPath) { Source = item });
|
||||
}
|
||||
else
|
||||
{
|
||||
tag.Content = checkComboBoxItem.Content;
|
||||
}
|
||||
|
||||
_panel.Children.Add(tag);
|
||||
}
|
||||
_panel.Children.Add(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class CheckComboBoxItem : ListBoxItem
|
||||
{
|
||||
public class CheckComboBoxItem : ListBoxItem
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -12,435 +12,434 @@ using System.Windows.Threading;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[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
|
||||
{
|
||||
[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 NET40
|
||||
|
||||
private string _searchText;
|
||||
private string _searchText;
|
||||
|
||||
private DispatcherTimer _autoCompleteTimer;
|
||||
private DispatcherTimer _autoCompleteTimer;
|
||||
|
||||
#endif
|
||||
private bool _isAutoCompleteAction = true;
|
||||
private bool _isAutoCompleteAction = true;
|
||||
|
||||
private Panel _autoCompletePanel;
|
||||
private Panel _autoCompletePanel;
|
||||
|
||||
private System.Windows.Controls.TextBox _editableTextBox;
|
||||
private System.Windows.Controls.TextBox _editableTextBox;
|
||||
|
||||
private Popup _autoPopupAutoComplete;
|
||||
private Popup _autoPopupAutoComplete;
|
||||
|
||||
private const string AutoCompletePanel = "PART_AutoCompletePanel";
|
||||
private const string AutoCompletePanel = "PART_AutoCompletePanel";
|
||||
|
||||
private const string AutoPopupAutoComplete = "PART_Popup_AutoComplete";
|
||||
private const string AutoPopupAutoComplete = "PART_Popup_AutoComplete";
|
||||
|
||||
private const string EditableTextBox = "PART_EditableTextBox";
|
||||
private const string EditableTextBox = "PART_EditableTextBox";
|
||||
|
||||
public ComboBox()
|
||||
public ComboBox()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
SetCurrentValue(SelectedValueProperty, null);
|
||||
SetCurrentValue(SelectedItemProperty, null);
|
||||
SetCurrentValue(SelectedIndexProperty, -1);
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
SetCurrentValue(SelectedValueProperty, null);
|
||||
SetCurrentValue(SelectedItemProperty, null);
|
||||
SetCurrentValue(SelectedIndexProperty, -1);
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_editableTextBox != null)
|
||||
{
|
||||
BindingOperations.ClearBinding(_editableTextBox, System.Windows.Controls.TextBox.TextProperty);
|
||||
_editableTextBox.GotFocus -= EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus -= EditableTextBox_LostFocus;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (IsEditable)
|
||||
{
|
||||
_editableTextBox = GetTemplateChild(EditableTextBox) as System.Windows.Controls.TextBox;
|
||||
|
||||
if (_editableTextBox != null)
|
||||
{
|
||||
BindingOperations.ClearBinding(_editableTextBox, System.Windows.Controls.TextBox.TextProperty);
|
||||
_editableTextBox.GotFocus -= EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus -= EditableTextBox_LostFocus;
|
||||
}
|
||||
_editableTextBox.TextChanged += EditableTextBox_TextChanged;
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (IsEditable)
|
||||
{
|
||||
_editableTextBox = GetTemplateChild(EditableTextBox) as System.Windows.Controls.TextBox;
|
||||
|
||||
if (_editableTextBox != null)
|
||||
{
|
||||
_editableTextBox.TextChanged += EditableTextBox_TextChanged;
|
||||
|
||||
_editableTextBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
_editableTextBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
_editableTextBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_editableTextBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
if (AutoComplete)
|
||||
{
|
||||
if (AutoComplete)
|
||||
{
|
||||
#if NET40
|
||||
_autoCompleteTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(500)
|
||||
};
|
||||
_autoCompleteTimer.Tick += AutoCompleteTimer_Tick;
|
||||
_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,
|
||||
_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 !NET40
|
||||
Delay = 500,
|
||||
Delay = 500,
|
||||
#endif
|
||||
Source = this
|
||||
});
|
||||
_editableTextBox.GotFocus += EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus += EditableTextBox_LostFocus;
|
||||
}
|
||||
Source = this
|
||||
});
|
||||
_editableTextBox.GotFocus += EditableTextBox_GotFocus;
|
||||
_editableTextBox.LostFocus += EditableTextBox_LostFocus;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NET40
|
||||
|
||||
private void AutoCompleteTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSearchItems(_searchText);
|
||||
_autoCompleteTimer.Stop();
|
||||
}
|
||||
private void AutoCompleteTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSearchItems(_searchText);
|
||||
_autoCompleteTimer.Stop();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private void EditableTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
private void EditableTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void EditableTextBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_autoPopupAutoComplete != null)
|
||||
{
|
||||
VerifyData();
|
||||
_autoPopupAutoComplete.IsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET40
|
||||
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 NET40
|
||||
_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);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
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);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyPropertyKey TextTypePropertyKey =
|
||||
DependencyProperty.RegisterReadOnly("TextType", typeof(TextType), typeof(ComboBox),
|
||||
new PropertyMetadata(default(TextType)));
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = TextTypePropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
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);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(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>
|
||||
public bool AutoComplete
|
||||
{
|
||||
get => (bool) GetValue(AutoCompleteProperty);
|
||||
set => SetValue(AutoCompleteProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <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 NET40
|
||||
ctl._searchText = e.NewValue as string;
|
||||
ctl._autoCompleteTimer.Stop();
|
||||
ctl._autoCompleteTimer.Start();
|
||||
#else
|
||||
ctl.UpdateSearchItems(e.NewValue as string);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void EditableTextBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
ctl._isAutoCompleteAction = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搜索文本
|
||||
/// </summary>
|
||||
internal string SearchText
|
||||
{
|
||||
get => (string) GetValue(SearchTextProperty);
|
||||
set => SetValue(SearchTextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, 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(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET40
|
||||
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 NET40
|
||||
_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);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
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);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyPropertyKey TextTypePropertyKey =
|
||||
DependencyProperty.RegisterReadOnly("TextType", typeof(TextType), typeof(ComboBox),
|
||||
new PropertyMetadata(default(TextType)));
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = TextTypePropertyKey.DependencyProperty;
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
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);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(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>
|
||||
public bool AutoComplete
|
||||
{
|
||||
get => (bool) GetValue(AutoCompleteProperty);
|
||||
set => SetValue(AutoCompleteProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <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 NET40
|
||||
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);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(ComboBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, 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(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
SelectedValue = comboBoxItem.Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,171 +8,170 @@ using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(DatePickerTextBox))]
|
||||
public class DatePicker : System.Windows.Controls.DatePicker, IDataInput
|
||||
{
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(DatePickerTextBox))]
|
||||
public class DatePicker : System.Windows.Controls.DatePicker, IDataInput
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private System.Windows.Controls.TextBox _textBox;
|
||||
|
||||
public DatePicker()
|
||||
{
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private System.Windows.Controls.TextBox _textBox;
|
||||
|
||||
public DatePicker()
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
SetCurrentValue(SelectedDateProperty, null);
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
SetCurrentValue(SelectedDateProperty, null);
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_textBox = GetTemplateChild(ElementTextBox) as System.Windows.Controls.TextBox;
|
||||
if (_textBox != null)
|
||||
{
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_textBox = GetTemplateChild(ElementTextBox) as System.Windows.Controls.TextBox;
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
_textBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
_textBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) => VerifyData();
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(DatePicker), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(DatePicker), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(DatePicker), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(DatePicker), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
return !isError;
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) => VerifyData();
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(DatePicker), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(DatePicker), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(DatePicker), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(DatePicker), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(DatePicker));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
return !isError;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,42 +2,41 @@
|
||||
using HandyControl.Data;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 表示可以成为一个数据输入控件
|
||||
/// </summary>
|
||||
public interface IDataInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示可以成为一个数据输入控件
|
||||
/// 验证数据
|
||||
/// </summary>
|
||||
public interface IDataInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool VerifyData();
|
||||
/// <returns></returns>
|
||||
bool VerifyData();
|
||||
|
||||
/// <summary>
|
||||
/// 数据验证委托
|
||||
/// </summary>
|
||||
Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
/// <summary>
|
||||
/// 数据验证委托
|
||||
/// </summary>
|
||||
Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
bool IsError { get; set; }
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
bool IsError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
string ErrorStr { get; set; }
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
string ErrorStr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
TextType TextType { get; set; }
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
TextType TextType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
bool ShowClearButton { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
bool ShowClearButton { get; set; }
|
||||
}
|
||||
@@ -8,130 +8,129 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ImageSelector : Control
|
||||
{
|
||||
public class ImageSelector : Control
|
||||
public static readonly RoutedEvent ImageSelectedEvent =
|
||||
EventManager.RegisterRoutedEvent("ImageSelected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(ImageSelector));
|
||||
|
||||
public event RoutedEventHandler ImageSelected
|
||||
{
|
||||
public static readonly RoutedEvent ImageSelectedEvent =
|
||||
EventManager.RegisterRoutedEvent("ImageSelected", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(ImageSelector));
|
||||
add => AddHandler(ImageSelectedEvent, value);
|
||||
remove => RemoveHandler(ImageSelectedEvent, value);
|
||||
}
|
||||
|
||||
public event RoutedEventHandler ImageSelected
|
||||
public ImageSelector() => CommandBindings.Add(new CommandBinding(ControlCommands.Switch, SwitchImage));
|
||||
|
||||
private void SwitchImage(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
if (!HasValue)
|
||||
{
|
||||
add => AddHandler(ImageSelectedEvent, value);
|
||||
remove => RemoveHandler(ImageSelectedEvent, value);
|
||||
}
|
||||
|
||||
public ImageSelector() => CommandBindings.Add(new CommandBinding(ControlCommands.Switch, SwitchImage));
|
||||
|
||||
private void SwitchImage(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
if (!HasValue)
|
||||
var dialog = new OpenFileDialog
|
||||
{
|
||||
var dialog = new OpenFileDialog
|
||||
{
|
||||
RestoreDirectory = true,
|
||||
Filter = Filter,
|
||||
DefaultExt = DefaultExt
|
||||
};
|
||||
RestoreDirectory = true,
|
||||
Filter = Filter,
|
||||
DefaultExt = DefaultExt
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
SetValue(UriPropertyKey, new Uri(dialog.FileName, UriKind.RelativeOrAbsolute));
|
||||
SetValue(PreviewBrushPropertyKey, new ImageBrush(BitmapFrame.Create(Uri, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.None))
|
||||
{
|
||||
Stretch = Stretch
|
||||
});
|
||||
SetValue(HasValuePropertyKey, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ToolTipProperty, dialog.FileName);
|
||||
RaiseEvent(new RoutedEventArgs(ImageSelectedEvent, this));
|
||||
}
|
||||
}
|
||||
else
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
SetValue(UriPropertyKey, default(Uri));
|
||||
SetValue(PreviewBrushPropertyKey, default(Brush));
|
||||
SetValue(HasValuePropertyKey, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ToolTipProperty, default);
|
||||
SetValue(UriPropertyKey, new Uri(dialog.FileName, UriKind.RelativeOrAbsolute));
|
||||
SetValue(PreviewBrushPropertyKey, new ImageBrush(BitmapFrame.Create(Uri, BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.None))
|
||||
{
|
||||
Stretch = Stretch
|
||||
});
|
||||
SetValue(HasValuePropertyKey, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ToolTipProperty, dialog.FileName);
|
||||
RaiseEvent(new RoutedEventArgs(ImageSelectedEvent, this));
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StretchProperty = DependencyProperty.Register(
|
||||
"Stretch", typeof(Stretch), typeof(ImageSelector), new PropertyMetadata(default(Stretch)));
|
||||
|
||||
public Stretch Stretch
|
||||
else
|
||||
{
|
||||
get => (Stretch) GetValue(StretchProperty);
|
||||
set => SetValue(StretchProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey UriPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"Uri", typeof(Uri), typeof(ImageSelector), new PropertyMetadata(default(Uri)));
|
||||
|
||||
public static readonly DependencyProperty UriProperty = UriPropertyKey.DependencyProperty;
|
||||
|
||||
public Uri Uri
|
||||
{
|
||||
get => (Uri) GetValue(UriProperty);
|
||||
set => SetValue(UriProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey PreviewBrushPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"PreviewBrush", typeof(Brush), typeof(ImageSelector), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public static readonly DependencyProperty PreviewBrushProperty = PreviewBrushPropertyKey.DependencyProperty;
|
||||
|
||||
public Brush PreviewBrush
|
||||
{
|
||||
get => (Brush) GetValue(PreviewBrushProperty);
|
||||
set => SetValue(PreviewBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
|
||||
"StrokeThickness", typeof(double), typeof(ImageSelector), new FrameworkPropertyMetadata(ValueBoxes.Double1Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get => (double) GetValue(StrokeThicknessProperty);
|
||||
set => SetValue(StrokeThicknessProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
|
||||
"StrokeDashArray", typeof(DoubleCollection), typeof(ImageSelector), new FrameworkPropertyMetadata(default(DoubleCollection), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public DoubleCollection StrokeDashArray
|
||||
{
|
||||
get => (DoubleCollection) GetValue(StrokeDashArrayProperty);
|
||||
set => SetValue(StrokeDashArrayProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DefaultExtProperty = DependencyProperty.Register(
|
||||
"DefaultExt", typeof(string), typeof(ImageSelector), new PropertyMetadata(".jpg"));
|
||||
|
||||
public string DefaultExt
|
||||
{
|
||||
get => (string) GetValue(DefaultExtProperty);
|
||||
set => SetValue(DefaultExtProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FilterProperty = DependencyProperty.Register(
|
||||
"Filter", typeof(string), typeof(ImageSelector), new PropertyMetadata("(.jpg)|*.jpg|(.png)|*.png"));
|
||||
|
||||
public string Filter
|
||||
{
|
||||
get => (string) GetValue(FilterProperty);
|
||||
set => SetValue(FilterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey HasValuePropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"HasValue", typeof(bool), typeof(ImageSelector), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static readonly DependencyProperty HasValueProperty = HasValuePropertyKey.DependencyProperty;
|
||||
|
||||
public bool HasValue
|
||||
{
|
||||
get => (bool) GetValue(HasValueProperty);
|
||||
set => SetValue(HasValueProperty, ValueBoxes.BooleanBox(value));
|
||||
SetValue(UriPropertyKey, default(Uri));
|
||||
SetValue(PreviewBrushPropertyKey, default(Brush));
|
||||
SetValue(HasValuePropertyKey, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ToolTipProperty, default);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StretchProperty = DependencyProperty.Register(
|
||||
"Stretch", typeof(Stretch), typeof(ImageSelector), new PropertyMetadata(default(Stretch)));
|
||||
|
||||
public Stretch Stretch
|
||||
{
|
||||
get => (Stretch) GetValue(StretchProperty);
|
||||
set => SetValue(StretchProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey UriPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"Uri", typeof(Uri), typeof(ImageSelector), new PropertyMetadata(default(Uri)));
|
||||
|
||||
public static readonly DependencyProperty UriProperty = UriPropertyKey.DependencyProperty;
|
||||
|
||||
public Uri Uri
|
||||
{
|
||||
get => (Uri) GetValue(UriProperty);
|
||||
set => SetValue(UriProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey PreviewBrushPropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"PreviewBrush", typeof(Brush), typeof(ImageSelector), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public static readonly DependencyProperty PreviewBrushProperty = PreviewBrushPropertyKey.DependencyProperty;
|
||||
|
||||
public Brush PreviewBrush
|
||||
{
|
||||
get => (Brush) GetValue(PreviewBrushProperty);
|
||||
set => SetValue(PreviewBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
|
||||
"StrokeThickness", typeof(double), typeof(ImageSelector), new FrameworkPropertyMetadata(ValueBoxes.Double1Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get => (double) GetValue(StrokeThicknessProperty);
|
||||
set => SetValue(StrokeThicknessProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StrokeDashArrayProperty = DependencyProperty.Register(
|
||||
"StrokeDashArray", typeof(DoubleCollection), typeof(ImageSelector), new FrameworkPropertyMetadata(default(DoubleCollection), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public DoubleCollection StrokeDashArray
|
||||
{
|
||||
get => (DoubleCollection) GetValue(StrokeDashArrayProperty);
|
||||
set => SetValue(StrokeDashArrayProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DefaultExtProperty = DependencyProperty.Register(
|
||||
"DefaultExt", typeof(string), typeof(ImageSelector), new PropertyMetadata(".jpg"));
|
||||
|
||||
public string DefaultExt
|
||||
{
|
||||
get => (string) GetValue(DefaultExtProperty);
|
||||
set => SetValue(DefaultExtProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FilterProperty = DependencyProperty.Register(
|
||||
"Filter", typeof(string), typeof(ImageSelector), new PropertyMetadata("(.jpg)|*.jpg|(.png)|*.png"));
|
||||
|
||||
public string Filter
|
||||
{
|
||||
get => (string) GetValue(FilterProperty);
|
||||
set => SetValue(FilterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyPropertyKey HasValuePropertyKey = DependencyProperty.RegisterReadOnly(
|
||||
"HasValue", typeof(bool), typeof(ImageSelector), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static readonly DependencyProperty HasValueProperty = HasValuePropertyKey.DependencyProperty;
|
||||
|
||||
public bool HasValue
|
||||
{
|
||||
get => (bool) GetValue(HasValueProperty);
|
||||
set => SetValue(HasValueProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
}
|
||||
@@ -9,512 +9,334 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 数值选择控件
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(TextBox))]
|
||||
public class NumericUpDown : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// 数值选择控件
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(TextBox))]
|
||||
[TemplatePart(Name = ElementErrorTip, Type = typeof(UIElement))]
|
||||
public class NumericUpDown : Control, IDataInput
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private TextBox _textBox;
|
||||
|
||||
public NumericUpDown()
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private const string ElementErrorTip = "PART_ErrorTip";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Data
|
||||
|
||||
private TextBox _textBox;
|
||||
|
||||
private UIElement _errorTip;
|
||||
|
||||
private bool _updateText;
|
||||
|
||||
#endregion Data
|
||||
|
||||
public NumericUpDown()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Prev, (s, e) =>
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
Value += Increment;
|
||||
}));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Next, (s, e) =>
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
Value -= Increment;
|
||||
}));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
SetCurrentValue(ValueProperty, ValueBoxes.Double0Box);
|
||||
}));
|
||||
|
||||
Loaded += (s, e) => OnApplyTemplate();
|
||||
}
|
||||
|
||||
protected override void OnGotFocus(RoutedEventArgs e)
|
||||
{
|
||||
base.OnGotFocus(e);
|
||||
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox?.Focus();
|
||||
_textBox.Select(_textBox.Text.Length, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (_textBox != null)
|
||||
{
|
||||
TextCompositionManager.RemovePreviewTextInputHandler(_textBox, PreviewTextInputHandler);
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
_textBox.PreviewKeyDown -= TextBox_PreviewKeyDown;
|
||||
_textBox.LostFocus -= TextBox_LostFocus;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_textBox = GetTemplateChild(ElementTextBox) as TextBox;
|
||||
_errorTip = GetTemplateChild(ElementErrorTip) as UIElement;
|
||||
|
||||
if (_textBox != null)
|
||||
{
|
||||
_textBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
_textBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
_textBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
TextCompositionManager.AddPreviewTextInputHandler(_textBox, PreviewTextInputHandler);
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
_textBox.PreviewKeyDown += TextBox_PreviewKeyDown;
|
||||
_textBox.LostFocus += TextBox_LostFocus;
|
||||
_textBox.Text = CurrentText;
|
||||
}
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) => UpdateData();
|
||||
|
||||
private void UpdateData()
|
||||
{
|
||||
if (!VerifyData())
|
||||
{
|
||||
_updateText = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_updateText = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_textBox.Text))
|
||||
{
|
||||
Value = 0;
|
||||
|
||||
SetCurrentValue(ErrorStrProperty, string.Empty);
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
}
|
||||
else if (double.TryParse(_textBox.Text, out var value))
|
||||
{
|
||||
Value = value;
|
||||
|
||||
if (Validation.GetHasError(this))
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
}
|
||||
}
|
||||
|
||||
_updateText = true;
|
||||
}
|
||||
|
||||
private void PreviewTextInputHandler(object sender, TextCompositionEventArgs e) => UpdateData();
|
||||
|
||||
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (IsError && _errorTip != null) return;
|
||||
_textBox.Text = CurrentText;
|
||||
}
|
||||
|
||||
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Prev, (s, e) =>
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
if (e.Key == Key.Up)
|
||||
{
|
||||
Value += Increment;
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
Value -= Increment;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
SetCurrentValue(ValueProperty, Value + Increment);
|
||||
}));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Next, (s, e) =>
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
if (IsReadOnly) return;
|
||||
|
||||
if (_textBox.IsFocused && !IsReadOnly)
|
||||
{
|
||||
Value += e.Delta > 0 ? Increment : -Increment;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private string CurrentText => string.IsNullOrWhiteSpace(ValueFormat)
|
||||
? DecimalPlaces.HasValue
|
||||
? Value.ToString($"#0.{new string('0', DecimalPlaces.Value)}")
|
||||
: Value.ToString()
|
||||
: Value.ToString(ValueFormat);
|
||||
|
||||
protected virtual void OnValueChanged(FunctionEventArgs<double> e) => RaiseEvent(e);
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent ValueChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<double>>), typeof(NumericUpDown));
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public event EventHandler<FunctionEventArgs<double>> ValueChanged
|
||||
SetCurrentValue(ValueProperty, Value - Increment);
|
||||
}));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
add => AddHandler(ValueChangedEvent, value);
|
||||
remove => RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
if (IsReadOnly) return;
|
||||
|
||||
/// <summary>
|
||||
/// 当前值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
|
||||
"Value", typeof(double), typeof(NumericUpDown),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
OnValueChanged, CoerceValue), ValidateHelper.IsInRangeOfDouble);
|
||||
SetCurrentValue(ValueProperty, ValueBoxes.Double0Box);
|
||||
}));
|
||||
}
|
||||
|
||||
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_textBox = GetTemplateChild(ElementTextBox) as TextBox;
|
||||
|
||||
if (_textBox != null)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
var v = (double) e.NewValue;
|
||||
ctl.SetText();
|
||||
_textBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
_textBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
_textBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
_textBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
ctl.OnValueChanged(new FunctionEventArgs<double>(ValueChangedEvent, ctl)
|
||||
{
|
||||
Info = v
|
||||
});
|
||||
_textBox.PreviewKeyDown += TextBox_PreviewKeyDown;
|
||||
_textBox.Text = CurrentText;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetText()
|
||||
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (IsReadOnly) return;
|
||||
|
||||
if (e.Key == Key.Up)
|
||||
{
|
||||
if (_updateText && _textBox != null)
|
||||
{
|
||||
_textBox.Text = CurrentText;
|
||||
_textBox.Select(_textBox.Text.Length, 0);
|
||||
}
|
||||
Value += Increment;
|
||||
}
|
||||
|
||||
private static object CoerceValue(DependencyObject d, object basevalue)
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
var minimum = ctl.Minimum;
|
||||
var num = (double) basevalue;
|
||||
if (num < minimum)
|
||||
{
|
||||
ctl.Value = minimum;
|
||||
return minimum;
|
||||
}
|
||||
var maximum = ctl.Maximum;
|
||||
if (num > maximum)
|
||||
{
|
||||
ctl.Value = maximum;
|
||||
}
|
||||
ctl.SetText();
|
||||
return num > maximum ? maximum : num;
|
||||
Value -= Increment;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前值
|
||||
/// </summary>
|
||||
public double Value
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
|
||||
if (_textBox.IsFocused && !IsReadOnly)
|
||||
{
|
||||
get => (double) GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
Value += e.Delta > 0 ? Increment : -Increment;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
|
||||
"Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum), ValidateHelper.IsInRangeOfDouble);
|
||||
private string CurrentText => string.IsNullOrWhiteSpace(ValueFormat)
|
||||
? DecimalPlaces.HasValue
|
||||
? Value.ToString($"#0.{new string('0', DecimalPlaces.Value)}")
|
||||
: Value.ToString()
|
||||
: Value.ToString(ValueFormat);
|
||||
|
||||
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
protected virtual void OnValueChanged(FunctionEventArgs<double> e) => RaiseEvent(e);
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent ValueChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<double>>), typeof(NumericUpDown));
|
||||
|
||||
/// <summary>
|
||||
/// 值改变事件
|
||||
/// </summary>
|
||||
public event EventHandler<FunctionEventArgs<double>> ValueChanged
|
||||
{
|
||||
add => AddHandler(ValueChangedEvent, value);
|
||||
remove => RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
|
||||
"Value", typeof(double), typeof(NumericUpDown),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
OnValueChanged, CoerceValue), ValidateHelper.IsInRangeOfDouble);
|
||||
|
||||
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
var v = (double) e.NewValue;
|
||||
ctl.SetText();
|
||||
|
||||
ctl.OnValueChanged(new FunctionEventArgs<double>(ValueChangedEvent, ctl)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
ctl.CoerceValue(MinimumProperty);
|
||||
ctl.CoerceValue(ValueProperty);
|
||||
}
|
||||
Info = v
|
||||
});
|
||||
}
|
||||
|
||||
private static object CoerceMaximum(DependencyObject d, object basevalue)
|
||||
private void SetText()
|
||||
{
|
||||
if (_textBox != null)
|
||||
{
|
||||
var minimum = ((NumericUpDown) d).Minimum;
|
||||
return (double) basevalue < minimum ? minimum : basevalue;
|
||||
_textBox.Text = CurrentText;
|
||||
_textBox.Select(_textBox.Text.Length, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大值
|
||||
/// </summary>
|
||||
public double Maximum
|
||||
private static object CoerceValue(DependencyObject d, object basevalue)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
var minimum = ctl.Minimum;
|
||||
var num = (double) basevalue;
|
||||
if (num < minimum)
|
||||
{
|
||||
get => (double) GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
ctl.Value = minimum;
|
||||
return minimum;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最小值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
|
||||
"Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MinValue, OnMinimumChanged, CoerceMinimum), ValidateHelper.IsInRangeOfDouble);
|
||||
|
||||
private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
var maximum = ctl.Maximum;
|
||||
if (num > maximum)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
ctl.CoerceValue(MaximumProperty);
|
||||
ctl.CoerceValue(ValueProperty);
|
||||
ctl.Value = maximum;
|
||||
}
|
||||
ctl.SetText();
|
||||
return num > maximum ? maximum : num;
|
||||
}
|
||||
|
||||
private static object CoerceMinimum(DependencyObject d, object basevalue)
|
||||
{
|
||||
var maximum = ((NumericUpDown) d).Maximum;
|
||||
return (double) basevalue > maximum ? maximum : basevalue;
|
||||
}
|
||||
/// <summary>
|
||||
/// 当前值
|
||||
/// </summary>
|
||||
public double Value
|
||||
{
|
||||
get => (double) GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最小值
|
||||
/// </summary>
|
||||
public double Minimum
|
||||
{
|
||||
get => (double) GetValue(MinimumProperty);
|
||||
set => SetValue(MinimumProperty, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 最大值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
|
||||
"Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum), ValidateHelper.IsInRangeOfDouble);
|
||||
|
||||
/// <summary>
|
||||
/// 指示每单击一下按钮时增加或减少的数量
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IncrementProperty = DependencyProperty.Register(
|
||||
"Increment", typeof(double), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.Double1Box));
|
||||
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
ctl.CoerceValue(MinimumProperty);
|
||||
ctl.CoerceValue(ValueProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示每单击一下按钮时增加或减少的数量
|
||||
/// </summary>
|
||||
public double Increment
|
||||
{
|
||||
get => (double) GetValue(IncrementProperty);
|
||||
set => SetValue(IncrementProperty, value);
|
||||
}
|
||||
private static object CoerceMaximum(DependencyObject d, object basevalue)
|
||||
{
|
||||
var minimum = ((NumericUpDown) d).Minimum;
|
||||
return (double) basevalue < minimum ? minimum : basevalue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示要显示的小数位数
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DecimalPlacesProperty = DependencyProperty.Register(
|
||||
"DecimalPlaces", typeof(int?), typeof(NumericUpDown), new PropertyMetadata(default(int?)));
|
||||
/// <summary>
|
||||
/// 最大值
|
||||
/// </summary>
|
||||
public double Maximum
|
||||
{
|
||||
get => (double) GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示要显示的小数位数
|
||||
/// </summary>
|
||||
public int? DecimalPlaces
|
||||
{
|
||||
get => (int?) GetValue(DecimalPlacesProperty);
|
||||
set => SetValue(DecimalPlacesProperty, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 最小值
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register(
|
||||
"Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(double.MinValue, OnMinimumChanged, CoerceMinimum), ValidateHelper.IsInRangeOfDouble);
|
||||
|
||||
/// <summary>
|
||||
/// 指示要显示的数字的格式
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueFormatProperty = DependencyProperty.Register(
|
||||
"ValueFormat", typeof(string), typeof(NumericUpDown), new PropertyMetadata(default(string)));
|
||||
private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (NumericUpDown) d;
|
||||
ctl.CoerceValue(MaximumProperty);
|
||||
ctl.CoerceValue(ValueProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示要显示的数字的格式,这将会覆盖 <see cref="DecimalPlaces"/> 属性
|
||||
/// </summary>
|
||||
public string ValueFormat
|
||||
{
|
||||
get => (string) GetValue(ValueFormatProperty);
|
||||
set => SetValue(ValueFormatProperty, value);
|
||||
}
|
||||
private static object CoerceMinimum(DependencyObject d, object basevalue)
|
||||
{
|
||||
var maximum = ((NumericUpDown) d).Maximum;
|
||||
return (double) basevalue > maximum ? maximum : basevalue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示上下调值按钮
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty ShowUpDownButtonProperty = DependencyProperty.Register(
|
||||
"ShowUpDownButton", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
/// <summary>
|
||||
/// 最小值
|
||||
/// </summary>
|
||||
public double Minimum
|
||||
{
|
||||
get => (double) GetValue(MinimumProperty);
|
||||
set => SetValue(MinimumProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示上下调值按钮
|
||||
/// </summary>
|
||||
internal bool ShowUpDownButton
|
||||
{
|
||||
get => (bool) GetValue(ShowUpDownButtonProperty);
|
||||
set => SetValue(ShowUpDownButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
/// <summary>
|
||||
/// 指示每单击一下按钮时增加或减少的数量
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IncrementProperty = DependencyProperty.Register(
|
||||
"Increment", typeof(double), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.Double1Box));
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
/// <summary>
|
||||
/// 指示每单击一下按钮时增加或减少的数量
|
||||
/// </summary>
|
||||
public double Increment
|
||||
{
|
||||
get => (double) GetValue(IncrementProperty);
|
||||
set => SetValue(IncrementProperty, value);
|
||||
}
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
/// <summary>
|
||||
/// 指示要显示的小数位数
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DecimalPlacesProperty = DependencyProperty.Register(
|
||||
"DecimalPlaces", typeof(int?), typeof(NumericUpDown), new PropertyMetadata(default(int?)));
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(NumericUpDown), new PropertyMetadata(default(string)));
|
||||
/// <summary>
|
||||
/// 指示要显示的小数位数
|
||||
/// </summary>
|
||||
public int? DecimalPlaces
|
||||
{
|
||||
get => (int?) GetValue(DecimalPlacesProperty);
|
||||
set => SetValue(DecimalPlacesProperty, value);
|
||||
}
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 指示要显示的数字的格式
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ValueFormatProperty = DependencyProperty.Register(
|
||||
"ValueFormat", typeof(string), typeof(NumericUpDown), new PropertyMetadata(default(string)));
|
||||
|
||||
public static readonly DependencyPropertyKey TextTypePropertyKey =
|
||||
DependencyProperty.RegisterReadOnly("TextType", typeof(TextType), typeof(NumericUpDown),
|
||||
new PropertyMetadata(default(TextType)));
|
||||
/// <summary>
|
||||
/// 指示要显示的数字的格式,这将会覆盖 <see cref="DecimalPlaces"/> 属性
|
||||
/// </summary>
|
||||
public string ValueFormat
|
||||
{
|
||||
get => (string) GetValue(ValueFormatProperty);
|
||||
set => SetValue(ValueFormatProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = TextTypePropertyKey.DependencyProperty;
|
||||
/// <summary>
|
||||
/// 是否显示上下调值按钮
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty ShowUpDownButtonProperty = DependencyProperty.Register(
|
||||
"ShowUpDownButton", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否显示上下调值按钮
|
||||
/// </summary>
|
||||
internal bool ShowUpDownButton
|
||||
{
|
||||
get => (bool) GetValue(ShowUpDownButtonProperty);
|
||||
set => SetValue(ShowUpDownButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
/// <summary>
|
||||
/// 标识 IsReadOnly 依赖属性。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(
|
||||
"IsReadOnly", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取或设置一个值,该值指示NumericUpDown是否只读。
|
||||
/// </summary>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get => (bool) GetValue(IsReadOnlyProperty);
|
||||
set => SetValue(IsReadOnlyProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标识 IsReadOnly 依赖属性。
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(
|
||||
"IsReadOnly", typeof(bool), typeof(NumericUpDown), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置一个值,该值指示NumericUpDown是否只读。
|
||||
/// </summary>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get => (bool) GetValue(IsReadOnlyProperty);
|
||||
set => SetValue(IsReadOnlyProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(NumericUpDown));
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(NumericUpDown));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(_textBox.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_textBox.Text))
|
||||
{
|
||||
if (double.TryParse(_textBox.Text, out var value))
|
||||
{
|
||||
if (value < Minimum || value > Maximum)
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.OutOfRange);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.FormatError);
|
||||
}
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.BooleanBox(!result.Data));
|
||||
return result.Data;
|
||||
}
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -12,383 +12,382 @@ using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Properties.Langs;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementPasswordBox, Type = typeof(System.Windows.Controls.PasswordBox))]
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
public class PasswordBox : Control, IDataInput
|
||||
{
|
||||
[TemplatePart(Name = ElementPasswordBox, Type = typeof(System.Windows.Controls.PasswordBox))]
|
||||
[TemplatePart(Name = ElementTextBox, Type = typeof(System.Windows.Controls.TextBox))]
|
||||
public class PasswordBox : Control, IDataInput
|
||||
private const string ElementPasswordBox = "PART_PasswordBox";
|
||||
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
|
||||
private SecureString _password;
|
||||
|
||||
private System.Windows.Controls.TextBox _textBox;
|
||||
|
||||
/// <summary>
|
||||
/// 掩码字符
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordCharProperty =
|
||||
System.Windows.Controls.PasswordBox.PasswordCharProperty.AddOwner(typeof(PasswordBox),
|
||||
new FrameworkPropertyMetadata('●'));
|
||||
|
||||
public char PasswordChar
|
||||
{
|
||||
private const string ElementPasswordBox = "PART_PasswordBox";
|
||||
get => (char) GetValue(PasswordCharProperty);
|
||||
set => SetValue(PasswordCharProperty, value);
|
||||
}
|
||||
|
||||
private const string ElementTextBox = "PART_TextBox";
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
private SecureString _password;
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private System.Windows.Controls.TextBox _textBox;
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(PasswordBox), new PropertyMetadata(default(string)));
|
||||
|
||||
/// <summary>
|
||||
/// 掩码字符
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordCharProperty =
|
||||
System.Windows.Controls.PasswordBox.PasswordCharProperty.AddOwner(typeof(PasswordBox),
|
||||
new FrameworkPropertyMetadata('●'));
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
public char PasswordChar
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(PasswordBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowEyeButtonProperty = DependencyProperty.Register(
|
||||
"ShowEyeButton", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowEyeButton
|
||||
{
|
||||
get => (bool) GetValue(ShowEyeButtonProperty);
|
||||
set => SetValue(ShowEyeButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowPasswordProperty = DependencyProperty.Register(
|
||||
"ShowPassword", typeof(bool), typeof(PasswordBox),
|
||||
new PropertyMetadata(ValueBoxes.FalseBox, OnShowPasswordChanged));
|
||||
|
||||
public bool ShowPassword
|
||||
{
|
||||
get => (bool) GetValue(ShowPasswordProperty);
|
||||
set => SetValue(ShowPasswordProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsSafeEnabledProperty = DependencyProperty.Register(
|
||||
"IsSafeEnabled", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.TrueBox, OnIsSafeEnabledChanged));
|
||||
|
||||
private static void OnIsSafeEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (PasswordBox) d;
|
||||
p.SetCurrentValue(UnsafePasswordProperty, !(bool) e.NewValue ? p.Password : string.Empty);
|
||||
}
|
||||
|
||||
public bool IsSafeEnabled
|
||||
{
|
||||
get => (bool) GetValue(IsSafeEnabledProperty);
|
||||
set => SetValue(IsSafeEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UnsafePasswordProperty = DependencyProperty.Register(
|
||||
"UnsafePassword", typeof(string), typeof(PasswordBox), new FrameworkPropertyMetadata(default(string),
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnUnsafePasswordChanged));
|
||||
|
||||
private static void OnUnsafePasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (PasswordBox) d;
|
||||
if (!p.IsSafeEnabled)
|
||||
{
|
||||
get => (char) GetValue(PasswordCharProperty);
|
||||
set => SetValue(PasswordCharProperty, value);
|
||||
p.Password = e.NewValue != null ? e.NewValue.ToString() : string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
public string UnsafePassword
|
||||
{
|
||||
get => (string) GetValue(UnsafePasswordProperty);
|
||||
set => SetValue(UnsafePasswordProperty, value);
|
||||
}
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
public static readonly DependencyProperty MaxLengthProperty =
|
||||
System.Windows.Controls.TextBox.MaxLengthProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(PasswordBox), new PropertyMetadata(default(string)));
|
||||
public int MaxLength
|
||||
{
|
||||
get => (int) GetValue(MaxLengthProperty);
|
||||
set => SetValue(MaxLengthProperty, value);
|
||||
}
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(PasswordBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowEyeButtonProperty = DependencyProperty.Register(
|
||||
"ShowEyeButton", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowEyeButton
|
||||
{
|
||||
get => (bool) GetValue(ShowEyeButtonProperty);
|
||||
set => SetValue(ShowEyeButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowPasswordProperty = DependencyProperty.Register(
|
||||
"ShowPassword", typeof(bool), typeof(PasswordBox),
|
||||
new PropertyMetadata(ValueBoxes.FalseBox, OnShowPasswordChanged));
|
||||
|
||||
public bool ShowPassword
|
||||
{
|
||||
get => (bool) GetValue(ShowPasswordProperty);
|
||||
set => SetValue(ShowPasswordProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsSafeEnabledProperty = DependencyProperty.Register(
|
||||
"IsSafeEnabled", typeof(bool), typeof(PasswordBox), new PropertyMetadata(ValueBoxes.TrueBox, OnIsSafeEnabledChanged));
|
||||
|
||||
private static void OnIsSafeEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (PasswordBox) d;
|
||||
p.SetCurrentValue(UnsafePasswordProperty, !(bool) e.NewValue ? p.Password : string.Empty);
|
||||
}
|
||||
|
||||
public bool IsSafeEnabled
|
||||
{
|
||||
get => (bool) GetValue(IsSafeEnabledProperty);
|
||||
set => SetValue(IsSafeEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UnsafePasswordProperty = DependencyProperty.Register(
|
||||
"UnsafePassword", typeof(string), typeof(PasswordBox), new FrameworkPropertyMetadata(default(string),
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnUnsafePasswordChanged));
|
||||
|
||||
private static void OnUnsafePasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var p = (PasswordBox) d;
|
||||
if (!p.IsSafeEnabled)
|
||||
{
|
||||
p.Password = e.NewValue != null ? e.NewValue.ToString() : string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public string UnsafePassword
|
||||
{
|
||||
get => (string) GetValue(UnsafePasswordProperty);
|
||||
set => SetValue(UnsafePasswordProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaxLengthProperty =
|
||||
System.Windows.Controls.TextBox.MaxLengthProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public int MaxLength
|
||||
{
|
||||
get => (int) GetValue(MaxLengthProperty);
|
||||
set => SetValue(MaxLengthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(PasswordBox));
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !NET40
|
||||
|
||||
public static readonly DependencyProperty IsSelectionActiveProperty =
|
||||
TextBoxBase.IsSelectionActiveProperty.AddOwner(typeof(PasswordBox));
|
||||
public static readonly DependencyProperty IsSelectionActiveProperty =
|
||||
TextBoxBase.IsSelectionActiveProperty.AddOwner(typeof(PasswordBox));
|
||||
|
||||
public bool IsSelectionActive => ActualPasswordBox != null && (bool) ActualPasswordBox.GetValue(IsSelectionActiveProperty);
|
||||
public bool IsSelectionActive => ActualPasswordBox != null && (bool) ActualPasswordBox.GetValue(IsSelectionActiveProperty);
|
||||
|
||||
#endif
|
||||
|
||||
public PasswordBox() => CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) => Clear()));
|
||||
public PasswordBox() => CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) => Clear()));
|
||||
|
||||
public System.Windows.Controls.PasswordBox ActualPasswordBox { get; set; }
|
||||
public System.Windows.Controls.PasswordBox ActualPasswordBox { get; set; }
|
||||
|
||||
[DefaultValue("")]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public string Password
|
||||
[DefaultValue("")]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
return _textBox.Text;
|
||||
}
|
||||
return ActualPasswordBox?.Password;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (ActualPasswordBox == null)
|
||||
{
|
||||
_password = new SecureString();
|
||||
value ??= string.Empty;
|
||||
foreach (var item in value)
|
||||
_password.AppendChar(item);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Equals(ActualPasswordBox.Password, value)) return;
|
||||
ActualPasswordBox.Password = value;
|
||||
return _textBox.Text;
|
||||
}
|
||||
return ActualPasswordBox?.Password;
|
||||
}
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public SecureString SecurePassword => ActualPasswordBox?.SecurePassword;
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public virtual bool VerifyData()
|
||||
set
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
if (ActualPasswordBox == null)
|
||||
{
|
||||
_password = new SecureString();
|
||||
value ??= string.Empty;
|
||||
foreach (var item in value)
|
||||
_password.AppendChar(item);
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(ShowEyeButton && ShowPassword
|
||||
? _textBox.Text
|
||||
: ActualPasswordBox.Password);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ShowEyeButton && ShowPassword
|
||||
|
||||
if (Equals(ActualPasswordBox.Password, value)) return;
|
||||
ActualPasswordBox.Password = value;
|
||||
}
|
||||
}
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public SecureString SecurePassword => ActualPasswordBox?.SecurePassword;
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(ShowEyeButton && ShowPassword
|
||||
? _textBox.Text
|
||||
: ActualPasswordBox.Password);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ShowEyeButton && ShowPassword
|
||||
? _textBox.Text
|
||||
: ActualPasswordBox.Password))
|
||||
result = OperationResult.Success();
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
result = OperationResult.Failed(Lang.IsNecessary);
|
||||
else
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
result = OperationResult.Success();
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
result = OperationResult.Failed(Lang.IsNecessary);
|
||||
else
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
return !isError;
|
||||
}
|
||||
|
||||
private static void OnShowPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (PasswordBox) d;
|
||||
if (!ctl.ShowEyeButton) return;
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
ctl._textBox.Text = ctl.ActualPasswordBox.Password;
|
||||
ctl._textBox.Select(string.IsNullOrEmpty(ctl._textBox.Text) ? 0 : ctl._textBox.Text.Length, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.ActualPasswordBox.Password = ctl._textBox.Text;
|
||||
ctl._textBox.Clear();
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
return !isError;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
private static void OnShowPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (PasswordBox) d;
|
||||
if (!ctl.ShowEyeButton) return;
|
||||
if ((bool) e.NewValue)
|
||||
{
|
||||
if (ActualPasswordBox != null)
|
||||
ActualPasswordBox.PasswordChanged -= PasswordBox_PasswordChanged;
|
||||
ctl._textBox.Text = ctl.ActualPasswordBox.Password;
|
||||
ctl._textBox.Select(string.IsNullOrEmpty(ctl._textBox.Text) ? 0 : ctl._textBox.Text.Length, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.ActualPasswordBox.Password = ctl._textBox.Text;
|
||||
ctl._textBox.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (_textBox != null)
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (ActualPasswordBox != null)
|
||||
ActualPasswordBox.PasswordChanged -= PasswordBox_PasswordChanged;
|
||||
|
||||
base.OnApplyTemplate();
|
||||
if (_textBox != null)
|
||||
_textBox.TextChanged -= TextBox_TextChanged;
|
||||
|
||||
ActualPasswordBox = GetTemplateChild(ElementPasswordBox) as System.Windows.Controls.PasswordBox;
|
||||
_textBox = GetTemplateChild(ElementTextBox) as System.Windows.Controls.TextBox;
|
||||
if (ActualPasswordBox != null)
|
||||
{
|
||||
ActualPasswordBox.PasswordChanged += PasswordBox_PasswordChanged;
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.MaxLengthProperty, new Binding(MaxLengthProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
base.OnApplyTemplate();
|
||||
|
||||
ActualPasswordBox = GetTemplateChild(ElementPasswordBox) as System.Windows.Controls.PasswordBox;
|
||||
_textBox = GetTemplateChild(ElementTextBox) as System.Windows.Controls.TextBox;
|
||||
if (ActualPasswordBox != null)
|
||||
{
|
||||
ActualPasswordBox.PasswordChanged += PasswordBox_PasswordChanged;
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.MaxLengthProperty, new Binding(MaxLengthProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
ActualPasswordBox.SetBinding(System.Windows.Controls.PasswordBox.CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
if (_password is { Length: > 0 })
|
||||
{
|
||||
var valuePtr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(_password);
|
||||
ActualPasswordBox.Password = Marshal.PtrToStringUni(valuePtr) ?? throw new InvalidOperationException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
|
||||
_password.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_textBox != null)
|
||||
if (_password is { Length: > 0 })
|
||||
{
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
var valuePtr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(_password);
|
||||
ActualPasswordBox.Password = Marshal.PtrToStringUni(valuePtr) ?? throw new InvalidOperationException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
|
||||
_password.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Paste()
|
||||
if (_textBox != null)
|
||||
{
|
||||
ActualPasswordBox.Paste();
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
_textBox.TextChanged += TextBox_TextChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public void Paste()
|
||||
{
|
||||
ActualPasswordBox.Paste();
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
_textBox.Text = ActualPasswordBox.Password;
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectAll()
|
||||
{
|
||||
ActualPasswordBox.SelectAll();
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
_textBox.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ActualPasswordBox.Clear();
|
||||
_textBox.Clear();
|
||||
}
|
||||
|
||||
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!IsSafeEnabled)
|
||||
{
|
||||
SetCurrentValue(UnsafePasswordProperty, ActualPasswordBox.Password);
|
||||
|
||||
if (ShowPassword)
|
||||
{
|
||||
_textBox.Text = ActualPasswordBox.Password;
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectAll()
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (!IsSafeEnabled && ShowPassword)
|
||||
{
|
||||
ActualPasswordBox.SelectAll();
|
||||
if (ShowEyeButton && ShowPassword)
|
||||
{
|
||||
_textBox.SelectAll();
|
||||
}
|
||||
Password = _textBox.Text;
|
||||
SetCurrentValue(UnsafePasswordProperty, Password);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ActualPasswordBox.Clear();
|
||||
_textBox.Clear();
|
||||
}
|
||||
|
||||
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!IsSafeEnabled)
|
||||
{
|
||||
SetCurrentValue(UnsafePasswordProperty, ActualPasswordBox.Password);
|
||||
|
||||
if (ShowPassword)
|
||||
{
|
||||
_textBox.Text = ActualPasswordBox.Password;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (!IsSafeEnabled && ShowPassword)
|
||||
{
|
||||
Password = _textBox.Text;
|
||||
SetCurrentValue(UnsafePasswordProperty, Password);
|
||||
}
|
||||
|
||||
VerifyData();
|
||||
}
|
||||
VerifyData();
|
||||
}
|
||||
}
|
||||
@@ -13,398 +13,397 @@ using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
public class PinBox : Control
|
||||
{
|
||||
[TemplatePart(Name = ElementPanel, Type = typeof(Panel))]
|
||||
public class PinBox : Control
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
|
||||
private static readonly object MinLength = 4;
|
||||
|
||||
private Panel _panel;
|
||||
|
||||
private int _inputIndex;
|
||||
|
||||
private bool _changed;
|
||||
|
||||
private bool _isInternalAction;
|
||||
|
||||
private List<SecureString> _passwordList;
|
||||
|
||||
private RoutedEventHandler _passwordBoxsGotFocusEventHandler;
|
||||
|
||||
private RoutedEventHandler _passwordBoxsPasswordChangedEventHandler;
|
||||
|
||||
public PinBox()
|
||||
{
|
||||
private const string ElementPanel = "PART_Panel";
|
||||
Loaded += PinBox_Loaded;
|
||||
Unloaded += PinBox_Unloaded;
|
||||
}
|
||||
|
||||
private static readonly object MinLength = 4;
|
||||
private void PinBox_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RemoveHandler(System.Windows.Controls.PasswordBox.PasswordChangedEvent, _passwordBoxsPasswordChangedEventHandler);
|
||||
RemoveHandler(GotFocusEvent, _passwordBoxsGotFocusEventHandler);
|
||||
|
||||
private Panel _panel;
|
||||
Loaded -= PinBox_Loaded;
|
||||
Unloaded -= PinBox_Unloaded;
|
||||
}
|
||||
|
||||
private int _inputIndex;
|
||||
private void PinBox_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_passwordBoxsPasswordChangedEventHandler = PasswordBoxsPasswordChanged;
|
||||
AddHandler(System.Windows.Controls.PasswordBox.PasswordChangedEvent, _passwordBoxsPasswordChangedEventHandler);
|
||||
|
||||
private bool _changed;
|
||||
_passwordBoxsGotFocusEventHandler = PasswordBoxsGotFocus;
|
||||
AddHandler(GotFocusEvent, _passwordBoxsGotFocusEventHandler);
|
||||
|
||||
private bool _isInternalAction;
|
||||
FocusPasswordBox();
|
||||
}
|
||||
|
||||
private List<SecureString> _passwordList;
|
||||
|
||||
private RoutedEventHandler _passwordBoxsGotFocusEventHandler;
|
||||
|
||||
private RoutedEventHandler _passwordBoxsPasswordChangedEventHandler;
|
||||
|
||||
public PinBox()
|
||||
private void FocusPasswordBox()
|
||||
{
|
||||
if (!IsFocused)
|
||||
{
|
||||
Loaded += PinBox_Loaded;
|
||||
Unloaded += PinBox_Unloaded;
|
||||
return;
|
||||
}
|
||||
|
||||
private void PinBox_Unloaded(object sender, RoutedEventArgs e)
|
||||
if (_panel.Children.Count == 0)
|
||||
{
|
||||
RemoveHandler(System.Windows.Controls.PasswordBox.PasswordChangedEvent, _passwordBoxsPasswordChangedEventHandler);
|
||||
RemoveHandler(GotFocusEvent, _passwordBoxsGotFocusEventHandler);
|
||||
|
||||
Loaded -= PinBox_Loaded;
|
||||
Unloaded -= PinBox_Unloaded;
|
||||
return;
|
||||
}
|
||||
|
||||
private void PinBox_Loaded(object sender, RoutedEventArgs e)
|
||||
if (_panel.Children.OfType<System.Windows.Controls.PasswordBox>().Any(box => box.IsFocused))
|
||||
{
|
||||
_passwordBoxsPasswordChangedEventHandler = PasswordBoxsPasswordChanged;
|
||||
AddHandler(System.Windows.Controls.PasswordBox.PasswordChangedEvent, _passwordBoxsPasswordChangedEventHandler);
|
||||
|
||||
_passwordBoxsGotFocusEventHandler = PasswordBoxsGotFocus;
|
||||
AddHandler(GotFocusEvent, _passwordBoxsGotFocusEventHandler);
|
||||
|
||||
FocusPasswordBox();
|
||||
return;
|
||||
}
|
||||
|
||||
private void FocusPasswordBox()
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[0]);
|
||||
}
|
||||
|
||||
private void PasswordBoxsPasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_isInternalAction) return;
|
||||
|
||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
if (!IsFocused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_panel.Children.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_panel.Children.OfType<System.Windows.Controls.PasswordBox>().Any(box => box.IsFocused))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[0]);
|
||||
}
|
||||
|
||||
private void PasswordBoxsPasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_isInternalAction) return;
|
||||
|
||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
if (passwordBox.Password.Length > 0)
|
||||
{
|
||||
if (++_inputIndex >= Length)
|
||||
{
|
||||
_inputIndex = Length - 1;
|
||||
|
||||
if (_panel.Children.OfType<System.Windows.Controls.PasswordBox>()
|
||||
.All(item => item.Password.Any()))
|
||||
{
|
||||
FocusManager.SetFocusedElement(this, null);
|
||||
Keyboard.ClearFocus();
|
||||
RaiseEvent(new RoutedEventArgs(CompletedEvent, this));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (--_inputIndex < 0)
|
||||
{
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_changed = true;
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
private void PasswordBoxsGotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
_inputIndex = _panel.Children.IndexOf(passwordBox);
|
||||
passwordBox.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyUp(e);
|
||||
|
||||
if (e.Key == Key.Left)
|
||||
{
|
||||
if (--_inputIndex < 0)
|
||||
{
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||
passwordBox?.SelectAll();
|
||||
|
||||
FocusManager.SetFocusedElement(this, passwordBox);
|
||||
}
|
||||
else if (e.Key == Key.Right)
|
||||
if (passwordBox.Password.Length > 0)
|
||||
{
|
||||
if (++_inputIndex >= Length)
|
||||
{
|
||||
_inputIndex = Length - 1;
|
||||
|
||||
if (_panel.Children.OfType<System.Windows.Controls.PasswordBox>()
|
||||
.All(item => item.Password.Any()))
|
||||
{
|
||||
FocusManager.SetFocusedElement(this, null);
|
||||
Keyboard.ClearFocus();
|
||||
RaiseEvent(new RoutedEventArgs(CompletedEvent, this));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||
passwordBox?.SelectAll();
|
||||
|
||||
FocusManager.SetFocusedElement(this, passwordBox);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyUp(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyUp(e);
|
||||
|
||||
if (_changed)
|
||||
else
|
||||
{
|
||||
_changed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Key == Key.Delete || e.Key == Key.Back)
|
||||
{
|
||||
if (_panel.Children[_inputIndex] is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
_isInternalAction = true;
|
||||
passwordBox.Clear();
|
||||
_isInternalAction = false;
|
||||
}
|
||||
|
||||
if (--_inputIndex < 0)
|
||||
{
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
public string Password
|
||||
_changed = true;
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
private void PasswordBoxsGotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
get
|
||||
_inputIndex = _panel.Children.IndexOf(passwordBox);
|
||||
passwordBox.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyUp(e);
|
||||
|
||||
if (e.Key == Key.Left)
|
||||
{
|
||||
if (--_inputIndex < 0)
|
||||
{
|
||||
return string.Join("", _panel.Children.OfType<System.Windows.Controls.PasswordBox>().Select(item => item.Password));
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
set
|
||||
|
||||
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||
passwordBox?.SelectAll();
|
||||
|
||||
FocusManager.SetFocusedElement(this, passwordBox);
|
||||
}
|
||||
else if (e.Key == Key.Right)
|
||||
{
|
||||
if (++_inputIndex >= Length)
|
||||
{
|
||||
if (_panel == null)
|
||||
{
|
||||
_passwordList = new List<SecureString>();
|
||||
|
||||
value ??= string.Empty;
|
||||
|
||||
foreach (var item in value)
|
||||
{
|
||||
var secureString = new SecureString();
|
||||
secureString.AppendChar(item);
|
||||
_passwordList.Add(secureString);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var length = Length;
|
||||
if (string.IsNullOrEmpty(value) || value.Length != length || value.Length != _panel.Children.Count)
|
||||
{
|
||||
_panel.Children.OfType<System.Windows.Controls.PasswordBox>().Do(item => item.Clear());
|
||||
}
|
||||
else
|
||||
{
|
||||
_panel.Children.OfType<System.Windows.Controls.PasswordBox>().DoWithIndex((item, index) => item.Password = value[index].ToString());
|
||||
}
|
||||
_inputIndex = Length - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
var passwordBox = _panel.Children[_inputIndex] as System.Windows.Controls.PasswordBox;
|
||||
passwordBox?.SelectAll();
|
||||
|
||||
FocusManager.SetFocusedElement(this, passwordBox);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyUp(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyUp(e);
|
||||
|
||||
if (_changed)
|
||||
{
|
||||
_changed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 掩码字符
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordCharProperty =
|
||||
System.Windows.Controls.PasswordBox.PasswordCharProperty.AddOwner(typeof(PinBox),
|
||||
new FrameworkPropertyMetadata('●'));
|
||||
|
||||
public char PasswordChar
|
||||
if (e.Key == Key.Delete || e.Key == Key.Back)
|
||||
{
|
||||
get => (char) GetValue(PasswordCharProperty);
|
||||
set => SetValue(PasswordCharProperty, value);
|
||||
if (_panel.Children[_inputIndex] is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
_isInternalAction = true;
|
||||
passwordBox.Clear();
|
||||
_isInternalAction = false;
|
||||
}
|
||||
|
||||
if (--_inputIndex < 0)
|
||||
{
|
||||
_inputIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
FocusManager.SetFocusedElement(this, _panel.Children[_inputIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LengthProperty = DependencyProperty.Register(
|
||||
"Length", typeof(int), typeof(PinBox), new PropertyMetadata(MinLength, OnLengthChanged, CoerceLength), ValidateHelper.IsInRangeOfPosInt);
|
||||
|
||||
private static void OnLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
public string Password
|
||||
{
|
||||
get
|
||||
{
|
||||
var ctl = (PinBox) d;
|
||||
ctl.UpdateItems();
|
||||
return string.Join("", _panel.Children.OfType<System.Windows.Controls.PasswordBox>().Select(item => item.Password));
|
||||
}
|
||||
|
||||
private static object CoerceLength(DependencyObject d, object basevalue) => (int) basevalue < 4 ? MinLength : basevalue;
|
||||
|
||||
public int Length
|
||||
set
|
||||
{
|
||||
get => (int) GetValue(LengthProperty);
|
||||
set => SetValue(LengthProperty, value);
|
||||
}
|
||||
if (_panel == null)
|
||||
{
|
||||
_passwordList = new List<SecureString>();
|
||||
|
||||
public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register(
|
||||
"ItemMargin", typeof(Thickness), typeof(PinBox), new PropertyMetadata(default(Thickness)));
|
||||
value ??= string.Empty;
|
||||
|
||||
public Thickness ItemMargin
|
||||
{
|
||||
get => (Thickness) GetValue(ItemMarginProperty);
|
||||
set => SetValue(ItemMarginProperty, value);
|
||||
}
|
||||
foreach (var item in value)
|
||||
{
|
||||
var secureString = new SecureString();
|
||||
secureString.AppendChar(item);
|
||||
_passwordList.Add(secureString);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register(
|
||||
"ItemWidth", typeof(double), typeof(PinBox), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
return;
|
||||
}
|
||||
|
||||
public double ItemWidth
|
||||
{
|
||||
get => (double) GetValue(ItemWidthProperty);
|
||||
set => SetValue(ItemWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register(
|
||||
"ItemHeight", typeof(double), typeof(PinBox), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double ItemHeight
|
||||
{
|
||||
get => (double) GetValue(ItemHeightProperty);
|
||||
set => SetValue(ItemHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent CompletedEvent =
|
||||
EventManager.RegisterRoutedEvent("Completed", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(PinBox));
|
||||
|
||||
public event RoutedEventHandler Completed
|
||||
{
|
||||
add => AddHandler(CompletedEvent, value);
|
||||
remove => RemoveHandler(CompletedEvent, value);
|
||||
}
|
||||
|
||||
private void UpdateItems()
|
||||
{
|
||||
if (_panel == null) return;
|
||||
|
||||
_panel.Children.Clear();
|
||||
var length = Length;
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
if (string.IsNullOrEmpty(value) || value.Length != length || value.Length != _panel.Children.Count)
|
||||
{
|
||||
_panel.Children.Add(CreatePasswordBox());
|
||||
_panel.Children.OfType<System.Windows.Controls.PasswordBox>().Do(item => item.Clear());
|
||||
}
|
||||
else
|
||||
{
|
||||
_panel.Children.OfType<System.Windows.Controls.PasswordBox>().DoWithIndex((item, index) => item.Password = value[index].ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private System.Windows.Controls.PasswordBox CreatePasswordBox()
|
||||
{
|
||||
var passwordBox = new System.Windows.Controls.PasswordBox
|
||||
{
|
||||
MaxLength = 1,
|
||||
HorizontalContentAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = ItemMargin,
|
||||
Width = ItemWidth,
|
||||
Height = ItemHeight,
|
||||
Padding = default,
|
||||
PasswordChar = PasswordChar,
|
||||
Foreground = Foreground
|
||||
};
|
||||
/// <summary>
|
||||
/// 掩码字符
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PasswordCharProperty =
|
||||
System.Windows.Controls.PasswordBox.PasswordCharProperty.AddOwner(typeof(PinBox),
|
||||
new FrameworkPropertyMetadata('●'));
|
||||
|
||||
public char PasswordChar
|
||||
{
|
||||
get => (char) GetValue(PasswordCharProperty);
|
||||
set => SetValue(PasswordCharProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LengthProperty = DependencyProperty.Register(
|
||||
"Length", typeof(int), typeof(PinBox), new PropertyMetadata(MinLength, OnLengthChanged, CoerceLength), ValidateHelper.IsInRangeOfPosInt);
|
||||
|
||||
private static void OnLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (PinBox) d;
|
||||
ctl.UpdateItems();
|
||||
}
|
||||
|
||||
private static object CoerceLength(DependencyObject d, object basevalue) => (int) basevalue < 4 ? MinLength : basevalue;
|
||||
|
||||
public int Length
|
||||
{
|
||||
get => (int) GetValue(LengthProperty);
|
||||
set => SetValue(LengthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemMarginProperty = DependencyProperty.Register(
|
||||
"ItemMargin", typeof(Thickness), typeof(PinBox), new PropertyMetadata(default(Thickness)));
|
||||
|
||||
public Thickness ItemMargin
|
||||
{
|
||||
get => (Thickness) GetValue(ItemMarginProperty);
|
||||
set => SetValue(ItemMarginProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register(
|
||||
"ItemWidth", typeof(double), typeof(PinBox), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double ItemWidth
|
||||
{
|
||||
get => (double) GetValue(ItemWidthProperty);
|
||||
set => SetValue(ItemWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register(
|
||||
"ItemHeight", typeof(double), typeof(PinBox), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double ItemHeight
|
||||
{
|
||||
get => (double) GetValue(ItemHeightProperty);
|
||||
set => SetValue(ItemHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty SelectionBrushProperty =
|
||||
TextBoxBase.SelectionBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush SelectionBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionBrushProperty);
|
||||
set => SetValue(SelectionBrushProperty, value);
|
||||
}
|
||||
|
||||
passwordBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
passwordBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
|
||||
public static readonly DependencyProperty SelectionTextBrushProperty =
|
||||
TextBoxBase.SelectionTextBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush SelectionTextBrush
|
||||
{
|
||||
get => (Brush) GetValue(SelectionTextBrushProperty);
|
||||
set => SetValue(SelectionTextBrushProperty, value);
|
||||
}
|
||||
|
||||
#endif
|
||||
passwordBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
passwordBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
return passwordBox;
|
||||
}
|
||||
public static readonly DependencyProperty SelectionOpacityProperty =
|
||||
TextBoxBase.SelectionOpacityProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
public double SelectionOpacity
|
||||
{
|
||||
get => (double) GetValue(SelectionOpacityProperty);
|
||||
set => SetValue(SelectionOpacityProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CaretBrushProperty =
|
||||
TextBoxBase.CaretBrushProperty.AddOwner(typeof(PinBox));
|
||||
|
||||
public Brush CaretBrush
|
||||
{
|
||||
get => (Brush) GetValue(CaretBrushProperty);
|
||||
set => SetValue(CaretBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent CompletedEvent =
|
||||
EventManager.RegisterRoutedEvent("Completed", RoutingStrategy.Bubble,
|
||||
typeof(RoutedEventHandler), typeof(PinBox));
|
||||
|
||||
public event RoutedEventHandler Completed
|
||||
{
|
||||
add => AddHandler(CompletedEvent, value);
|
||||
remove => RemoveHandler(CompletedEvent, value);
|
||||
}
|
||||
|
||||
private void UpdateItems()
|
||||
{
|
||||
if (_panel == null) return;
|
||||
|
||||
_panel.Children.Clear();
|
||||
var length = Length;
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
_panel.Children.Add(CreatePasswordBox());
|
||||
}
|
||||
}
|
||||
|
||||
_panel = GetTemplateChild(ElementPanel) as Panel;
|
||||
if (_panel != null)
|
||||
private System.Windows.Controls.PasswordBox CreatePasswordBox()
|
||||
{
|
||||
var passwordBox = new System.Windows.Controls.PasswordBox
|
||||
{
|
||||
MaxLength = 1,
|
||||
HorizontalContentAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = ItemMargin,
|
||||
Width = ItemWidth,
|
||||
Height = ItemHeight,
|
||||
Padding = default,
|
||||
PasswordChar = PasswordChar,
|
||||
Foreground = Foreground
|
||||
};
|
||||
|
||||
passwordBox.SetBinding(SelectionBrushProperty, new Binding(SelectionBrushProperty.Name) { Source = this });
|
||||
#if !(NET40 || NET45 || NET451 || NET452 || NET46 || NET461 || NET462 || NET47 || NET471 || NET472)
|
||||
passwordBox.SetBinding(SelectionTextBrushProperty, new Binding(SelectionTextBrushProperty.Name) { Source = this });
|
||||
#endif
|
||||
passwordBox.SetBinding(SelectionOpacityProperty, new Binding(SelectionOpacityProperty.Name) { Source = this });
|
||||
passwordBox.SetBinding(CaretBrushProperty, new Binding(CaretBrushProperty.Name) { Source = this });
|
||||
|
||||
return passwordBox;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_panel = GetTemplateChild(ElementPanel) as Panel;
|
||||
if (_panel != null)
|
||||
{
|
||||
UpdateItems();
|
||||
|
||||
var length = Length;
|
||||
if (_passwordList != null && _passwordList.Count == length && _panel.Children.Count == length)
|
||||
{
|
||||
UpdateItems();
|
||||
|
||||
var length = Length;
|
||||
if (_passwordList != null && _passwordList.Count == length && _panel.Children.Count == length)
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
for (var i = 0; i < length; i++)
|
||||
var password = _passwordList[i];
|
||||
if (password.Length > 0)
|
||||
{
|
||||
var password = _passwordList[i];
|
||||
if (password.Length > 0)
|
||||
var valuePtr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
var valuePtr = IntPtr.Zero;
|
||||
try
|
||||
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(password);
|
||||
if (_panel.Children[i] is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(password);
|
||||
if (_panel.Children[i] is System.Windows.Controls.PasswordBox passwordBox)
|
||||
{
|
||||
passwordBox.Password = Marshal.PtrToStringUni(valuePtr) ?? throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
|
||||
password.Clear();
|
||||
passwordBox.Password = Marshal.PtrToStringUni(valuePtr) ?? throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
|
||||
password.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
_passwordList.Clear();
|
||||
}
|
||||
|
||||
_passwordList.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,128 +5,126 @@ using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Interactivity;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class SearchBar : TextBox, ICommandSource
|
||||
{
|
||||
public class SearchBar : TextBox, ICommandSource
|
||||
public SearchBar()
|
||||
{
|
||||
public SearchBar()
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Search, (s, e) => OnSearchStarted()));
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent SearchStartedEvent =
|
||||
EventManager.RegisterRoutedEvent("SearchStarted", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<string>>), typeof(SearchBar));
|
||||
|
||||
public event EventHandler<FunctionEventArgs<string>> SearchStarted
|
||||
{
|
||||
add => AddHandler(SearchStartedEvent, value);
|
||||
remove => RemoveHandler(SearchStartedEvent, value);
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnKeyDown(e);
|
||||
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Search, (s, e) => OnSearchStarted()));
|
||||
}
|
||||
|
||||
public static readonly RoutedEvent SearchStartedEvent =
|
||||
EventManager.RegisterRoutedEvent("SearchStarted", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<string>>), typeof(SearchBar));
|
||||
|
||||
public event EventHandler<FunctionEventArgs<string>> SearchStarted
|
||||
{
|
||||
add => AddHandler(SearchStartedEvent, value);
|
||||
remove => RemoveHandler(SearchStartedEvent, value);
|
||||
}
|
||||
|
||||
protected override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnKeyDown(e);
|
||||
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
OnSearchStarted();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(TextChangedEventArgs e)
|
||||
{
|
||||
base.OnTextChanged(e);
|
||||
|
||||
if (IsRealTime)
|
||||
{
|
||||
OnSearchStarted();
|
||||
}
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
private void OnSearchStarted()
|
||||
{
|
||||
RaiseEvent(new FunctionEventArgs<string>(SearchStartedEvent, this)
|
||||
{
|
||||
Info = Text
|
||||
});
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
case null:
|
||||
return;
|
||||
case RoutedCommand command:
|
||||
command.Execute(CommandParameter, CommandTarget);
|
||||
break;
|
||||
default:
|
||||
Command.Execute(CommandParameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否实时搜索
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsRealTimeProperty = DependencyProperty.Register(
|
||||
"IsRealTime", typeof(bool), typeof(SearchBar), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否实时搜索
|
||||
/// </summary>
|
||||
public bool IsRealTime
|
||||
{
|
||||
get => (bool) GetValue(IsRealTimeProperty);
|
||||
set => SetValue(IsRealTimeProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
|
||||
"Command", typeof(ICommand), typeof(SearchBar), new PropertyMetadata(default(ICommand), OnCommandChanged));
|
||||
|
||||
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (SearchBar) d;
|
||||
if (e.OldValue is ICommand oldCommand)
|
||||
{
|
||||
oldCommand.CanExecuteChanged -= ctl.CanExecuteChanged;
|
||||
}
|
||||
if (e.NewValue is ICommand newCommand)
|
||||
{
|
||||
newCommand.CanExecuteChanged += ctl.CanExecuteChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get => (ICommand) GetValue(CommandProperty);
|
||||
set => SetValue(CommandProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
|
||||
"CommandParameter", typeof(object), typeof(SearchBar), new PropertyMetadata(default(object)));
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get => GetValue(CommandParameterProperty);
|
||||
set => SetValue(CommandParameterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register(
|
||||
"CommandTarget", typeof(IInputElement), typeof(SearchBar), new PropertyMetadata(default(IInputElement)));
|
||||
|
||||
public IInputElement CommandTarget
|
||||
{
|
||||
get => (IInputElement) GetValue(CommandTargetProperty);
|
||||
set => SetValue(CommandTargetProperty, value);
|
||||
}
|
||||
|
||||
private void CanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Command == null) return;
|
||||
|
||||
IsEnabled = Command is RoutedCommand command
|
||||
? command.CanExecute(CommandParameter, CommandTarget)
|
||||
: Command.CanExecute(CommandParameter);
|
||||
OnSearchStarted();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(TextChangedEventArgs e)
|
||||
{
|
||||
base.OnTextChanged(e);
|
||||
|
||||
if (IsRealTime)
|
||||
{
|
||||
OnSearchStarted();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSearchStarted()
|
||||
{
|
||||
RaiseEvent(new FunctionEventArgs<string>(SearchStartedEvent, this)
|
||||
{
|
||||
Info = Text
|
||||
});
|
||||
|
||||
switch (Command)
|
||||
{
|
||||
case null:
|
||||
return;
|
||||
case RoutedCommand command:
|
||||
command.Execute(CommandParameter, CommandTarget);
|
||||
break;
|
||||
default:
|
||||
Command.Execute(CommandParameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否实时搜索
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsRealTimeProperty = DependencyProperty.Register(
|
||||
"IsRealTime", typeof(bool), typeof(SearchBar), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否实时搜索
|
||||
/// </summary>
|
||||
public bool IsRealTime
|
||||
{
|
||||
get => (bool) GetValue(IsRealTimeProperty);
|
||||
set => SetValue(IsRealTimeProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
|
||||
"Command", typeof(ICommand), typeof(SearchBar), new PropertyMetadata(default(ICommand), OnCommandChanged));
|
||||
|
||||
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (SearchBar) d;
|
||||
if (e.OldValue is ICommand oldCommand)
|
||||
{
|
||||
oldCommand.CanExecuteChanged -= ctl.CanExecuteChanged;
|
||||
}
|
||||
if (e.NewValue is ICommand newCommand)
|
||||
{
|
||||
newCommand.CanExecuteChanged += ctl.CanExecuteChanged;
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get => (ICommand) GetValue(CommandProperty);
|
||||
set => SetValue(CommandProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
|
||||
"CommandParameter", typeof(object), typeof(SearchBar), new PropertyMetadata(default(object)));
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get => GetValue(CommandParameterProperty);
|
||||
set => SetValue(CommandParameterProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register(
|
||||
"CommandTarget", typeof(IInputElement), typeof(SearchBar), new PropertyMetadata(default(IInputElement)));
|
||||
|
||||
public IInputElement CommandTarget
|
||||
{
|
||||
get => (IInputElement) GetValue(CommandTargetProperty);
|
||||
set => SetValue(CommandTargetProperty, value);
|
||||
}
|
||||
|
||||
private void CanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (Command == null) return;
|
||||
|
||||
IsEnabled = Command is RoutedCommand command
|
||||
? command.CanExecute(CommandParameter, CommandTarget)
|
||||
: Command.CanExecute(CommandParameter);
|
||||
}
|
||||
}
|
||||
@@ -1,138 +1,15 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using System.Windows.Input;
|
||||
using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class TextBox : System.Windows.Controls.TextBox
|
||||
{
|
||||
public class TextBox : System.Windows.Controls.TextBox, IDataInput
|
||||
public TextBox()
|
||||
{
|
||||
public TextBox()
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Clear, (s, e) =>
|
||||
{
|
||||
SetCurrentValue(TextProperty, "");
|
||||
}));
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(TextChangedEventArgs e)
|
||||
{
|
||||
base.OnTextChanged(e);
|
||||
VerifyData();
|
||||
}
|
||||
|
||||
public Func<string, OperationResult<bool>> VerifyFunc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据是否错误
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsErrorProperty = DependencyProperty.Register(
|
||||
"IsError", typeof(bool), typeof(TextBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsError
|
||||
{
|
||||
get => (bool) GetValue(IsErrorProperty);
|
||||
set => SetValue(IsErrorProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 错误提示
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorStrProperty = DependencyProperty.Register(
|
||||
"ErrorStr", typeof(string), typeof(TextBox), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ErrorStr
|
||||
{
|
||||
get => (string) GetValue(ErrorStrProperty);
|
||||
set => SetValue(ErrorStrProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本类型
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextTypeProperty = DependencyProperty.Register(
|
||||
"TextType", typeof(TextType), typeof(TextBox), new PropertyMetadata(default(TextType)));
|
||||
|
||||
public TextType TextType
|
||||
{
|
||||
get => (TextType) GetValue(TextTypeProperty);
|
||||
set => SetValue(TextTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示清除按钮
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShowClearButtonProperty = DependencyProperty.Register(
|
||||
"ShowClearButton", typeof(bool), typeof(TextBox), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool ShowClearButton
|
||||
{
|
||||
get => (bool) GetValue(ShowClearButtonProperty);
|
||||
set => SetValue(ShowClearButtonProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public virtual bool VerifyData()
|
||||
{
|
||||
OperationResult<bool> result;
|
||||
|
||||
if (VerifyFunc != null)
|
||||
{
|
||||
result = VerifyFunc.Invoke(Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
if (TextType != TextType.Common)
|
||||
{
|
||||
var regexPattern = InfoElement.GetRegexPattern(this);
|
||||
result = string.IsNullOrEmpty(regexPattern)
|
||||
? Text.IsKindOf(TextType)
|
||||
? OperationResult.Success()
|
||||
: OperationResult.Failed(Properties.Langs.Lang.FormatError)
|
||||
: Text.IsKindOf(regexPattern)
|
||||
? OperationResult.Success()
|
||||
: OperationResult.Failed(Properties.Langs.Lang.FormatError);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
else if (InfoElement.GetNecessary(this))
|
||||
{
|
||||
result = OperationResult.Failed(Properties.Langs.Lang.IsNecessary);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OperationResult.Success();
|
||||
}
|
||||
}
|
||||
|
||||
var isError = !result.Data;
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.TrueBox);
|
||||
SetCurrentValue(ErrorStrProperty, result.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
isError = Validation.GetHasError(this);
|
||||
if (isError)
|
||||
{
|
||||
SetCurrentValue(ErrorStrProperty, Validation.GetErrors(this)[0].ErrorContent?.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetCurrentValue(IsErrorProperty, ValueBoxes.FalseBox);
|
||||
SetCurrentValue(ErrorStrProperty, default(string));
|
||||
}
|
||||
}
|
||||
|
||||
return !isError;
|
||||
}
|
||||
SetCurrentValue(TextProperty, string.Empty);
|
||||
}));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,35 +1,34 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class WatermarkTextBox : TextBox
|
||||
{
|
||||
public class WatermarkTextBox : TextBox
|
||||
#region Public Properties
|
||||
|
||||
#region Watermark
|
||||
|
||||
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
|
||||
"Watermark", typeof(object), typeof(WatermarkTextBox), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Watermark
|
||||
{
|
||||
#region Public Properties
|
||||
get => GetValue(WatermarkProperty);
|
||||
set => SetValue(WatermarkProperty, value);
|
||||
}
|
||||
|
||||
#region Watermark
|
||||
#endregion Watermark
|
||||
|
||||
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
|
||||
"Watermark", typeof(object), typeof(WatermarkTextBox), new PropertyMetadata(default(object)));
|
||||
#endregion Public Properties
|
||||
|
||||
public object Watermark
|
||||
protected override void OnGotFocus(RoutedEventArgs e)
|
||||
{
|
||||
base.OnGotFocus(e);
|
||||
if (IsEnabled)
|
||||
{
|
||||
get => GetValue(WatermarkProperty);
|
||||
set => SetValue(WatermarkProperty, value);
|
||||
}
|
||||
|
||||
#endregion Watermark
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
protected override void OnGotFocus(RoutedEventArgs e)
|
||||
{
|
||||
base.OnGotFocus(e);
|
||||
if (IsEnabled)
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
Select(0, Text.Length);
|
||||
}
|
||||
Select(0, Text.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,130 +7,129 @@ using System.Windows.Shapes;
|
||||
using HandyControl.Data;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public abstract class LoadingBase : ContentControl
|
||||
{
|
||||
public abstract class LoadingBase : ContentControl
|
||||
{
|
||||
protected Storyboard Storyboard;
|
||||
protected Storyboard Storyboard;
|
||||
|
||||
public static readonly DependencyProperty IsRunningProperty = DependencyProperty.Register(
|
||||
"IsRunning", typeof(bool), typeof(LoadingBase), new PropertyMetadata(ValueBoxes.TrueBox, (o, args) =>
|
||||
public static readonly DependencyProperty IsRunningProperty = DependencyProperty.Register(
|
||||
"IsRunning", typeof(bool), typeof(LoadingBase), new PropertyMetadata(ValueBoxes.TrueBox, (o, args) =>
|
||||
{
|
||||
var ctl = (LoadingBase) o;
|
||||
var v = (bool) args.NewValue;
|
||||
if (v)
|
||||
{
|
||||
var ctl = (LoadingBase) o;
|
||||
var v = (bool) args.NewValue;
|
||||
if (v)
|
||||
{
|
||||
ctl.Storyboard?.Resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.Storyboard?.Pause();
|
||||
}
|
||||
}));
|
||||
ctl.Storyboard?.Resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl.Storyboard?.Pause();
|
||||
}
|
||||
}));
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
get => (bool) GetValue(IsRunningProperty);
|
||||
set => SetValue(IsRunningProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
public bool IsRunning
|
||||
{
|
||||
get => (bool) GetValue(IsRunningProperty);
|
||||
set => SetValue(IsRunningProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DotCountProperty = DependencyProperty.Register(
|
||||
"DotCount", typeof(int), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Int5Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
public static readonly DependencyProperty DotCountProperty = DependencyProperty.Register(
|
||||
"DotCount", typeof(int), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Int5Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public static readonly DependencyProperty DotIntervalProperty = DependencyProperty.Register(
|
||||
"DotInterval", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double10Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
public static readonly DependencyProperty DotIntervalProperty = DependencyProperty.Register(
|
||||
"DotInterval", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double10Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public static readonly DependencyProperty DotBorderBrushProperty = DependencyProperty.Register(
|
||||
"DotBorderBrush", typeof(Brush), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
public static readonly DependencyProperty DotBorderBrushProperty = DependencyProperty.Register(
|
||||
"DotBorderBrush", typeof(Brush), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public static readonly DependencyProperty DotBorderThicknessProperty = DependencyProperty.Register(
|
||||
"DotBorderThickness", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
public static readonly DependencyProperty DotBorderThicknessProperty = DependencyProperty.Register(
|
||||
"DotBorderThickness", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public static readonly DependencyProperty DotDiameterProperty = DependencyProperty.Register(
|
||||
"DotDiameter", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(6.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
public static readonly DependencyProperty DotDiameterProperty = DependencyProperty.Register(
|
||||
"DotDiameter", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(6.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public static readonly DependencyProperty DotSpeedProperty = DependencyProperty.Register(
|
||||
"DotSpeed", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(4.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
public static readonly DependencyProperty DotSpeedProperty = DependencyProperty.Register(
|
||||
"DotSpeed", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(4.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public static readonly DependencyProperty DotDelayTimeProperty = DependencyProperty.Register(
|
||||
"DotDelayTime", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(80.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
public static readonly DependencyProperty DotDelayTimeProperty = DependencyProperty.Register(
|
||||
"DotDelayTime", typeof(double), typeof(LoadingBase),
|
||||
new FrameworkPropertyMetadata(80.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
protected readonly Canvas PrivateCanvas = new()
|
||||
{
|
||||
ClipToBounds = true
|
||||
};
|
||||
protected readonly Canvas PrivateCanvas = new()
|
||||
{
|
||||
ClipToBounds = true
|
||||
};
|
||||
|
||||
protected LoadingBase()
|
||||
{
|
||||
Content = PrivateCanvas;
|
||||
}
|
||||
protected LoadingBase()
|
||||
{
|
||||
Content = PrivateCanvas;
|
||||
}
|
||||
|
||||
public int DotCount
|
||||
{
|
||||
get => (int) GetValue(DotCountProperty);
|
||||
set => SetValue(DotCountProperty, value);
|
||||
}
|
||||
public int DotCount
|
||||
{
|
||||
get => (int) GetValue(DotCountProperty);
|
||||
set => SetValue(DotCountProperty, value);
|
||||
}
|
||||
|
||||
public double DotInterval
|
||||
{
|
||||
get => (double) GetValue(DotIntervalProperty);
|
||||
set => SetValue(DotIntervalProperty, value);
|
||||
}
|
||||
public double DotInterval
|
||||
{
|
||||
get => (double) GetValue(DotIntervalProperty);
|
||||
set => SetValue(DotIntervalProperty, value);
|
||||
}
|
||||
|
||||
public Brush DotBorderBrush
|
||||
{
|
||||
get => (Brush) GetValue(DotBorderBrushProperty);
|
||||
set => SetValue(DotBorderBrushProperty, value);
|
||||
}
|
||||
public Brush DotBorderBrush
|
||||
{
|
||||
get => (Brush) GetValue(DotBorderBrushProperty);
|
||||
set => SetValue(DotBorderBrushProperty, value);
|
||||
}
|
||||
|
||||
public double DotBorderThickness
|
||||
{
|
||||
get => (double) GetValue(DotBorderThicknessProperty);
|
||||
set => SetValue(DotBorderThicknessProperty, value);
|
||||
}
|
||||
public double DotBorderThickness
|
||||
{
|
||||
get => (double) GetValue(DotBorderThicknessProperty);
|
||||
set => SetValue(DotBorderThicknessProperty, value);
|
||||
}
|
||||
|
||||
public double DotDiameter
|
||||
{
|
||||
get => (double) GetValue(DotDiameterProperty);
|
||||
set => SetValue(DotDiameterProperty, value);
|
||||
}
|
||||
public double DotDiameter
|
||||
{
|
||||
get => (double) GetValue(DotDiameterProperty);
|
||||
set => SetValue(DotDiameterProperty, value);
|
||||
}
|
||||
|
||||
public double DotSpeed
|
||||
{
|
||||
get => (double) GetValue(DotSpeedProperty);
|
||||
set => SetValue(DotSpeedProperty, value);
|
||||
}
|
||||
public double DotSpeed
|
||||
{
|
||||
get => (double) GetValue(DotSpeedProperty);
|
||||
set => SetValue(DotSpeedProperty, value);
|
||||
}
|
||||
|
||||
public double DotDelayTime
|
||||
{
|
||||
get => (double) GetValue(DotDelayTimeProperty);
|
||||
set => SetValue(DotDelayTimeProperty, value);
|
||||
}
|
||||
public double DotDelayTime
|
||||
{
|
||||
get => (double) GetValue(DotDelayTimeProperty);
|
||||
set => SetValue(DotDelayTimeProperty, value);
|
||||
}
|
||||
|
||||
protected abstract void UpdateDots();
|
||||
protected abstract void UpdateDots();
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
base.OnRender(drawingContext);
|
||||
UpdateDots();
|
||||
}
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
base.OnRender(drawingContext);
|
||||
UpdateDots();
|
||||
}
|
||||
|
||||
protected virtual Ellipse CreateEllipse(int index)
|
||||
{
|
||||
var ellipse = new Ellipse();
|
||||
ellipse.SetBinding(WidthProperty, new Binding(DotDiameterProperty.Name) { Source = this });
|
||||
ellipse.SetBinding(HeightProperty, new Binding(DotDiameterProperty.Name) { Source = this });
|
||||
ellipse.SetBinding(Shape.FillProperty, new Binding(ForegroundProperty.Name) { Source = this });
|
||||
ellipse.SetBinding(Shape.StrokeThicknessProperty, new Binding(DotBorderThicknessProperty.Name) { Source = this });
|
||||
ellipse.SetBinding(Shape.StrokeProperty, new Binding(DotBorderBrushProperty.Name) { Source = this });
|
||||
return ellipse;
|
||||
}
|
||||
protected virtual Ellipse CreateEllipse(int index)
|
||||
{
|
||||
var ellipse = new Ellipse();
|
||||
ellipse.SetBinding(WidthProperty, new Binding(DotDiameterProperty.Name) { Source = this });
|
||||
ellipse.SetBinding(HeightProperty, new Binding(DotDiameterProperty.Name) { Source = this });
|
||||
ellipse.SetBinding(Shape.FillProperty, new Binding(ForegroundProperty.Name) { Source = this });
|
||||
ellipse.SetBinding(Shape.StrokeThicknessProperty, new Binding(DotBorderThicknessProperty.Name) { Source = this });
|
||||
ellipse.SetBinding(Shape.StrokeProperty, new Binding(DotBorderBrushProperty.Name) { Source = this });
|
||||
return ellipse;
|
||||
}
|
||||
}
|
||||
@@ -7,207 +7,206 @@ using System.Windows.Media.Animation;
|
||||
using HandyControl.Data;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class LoadingCircle : LoadingBase
|
||||
{
|
||||
public class LoadingCircle : LoadingBase
|
||||
public static readonly DependencyProperty DotOffSetProperty = DependencyProperty.Register(
|
||||
"DotOffSet", typeof(double), typeof(LoadingCircle),
|
||||
new FrameworkPropertyMetadata(20.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double DotOffSet
|
||||
{
|
||||
public static readonly DependencyProperty DotOffSetProperty = DependencyProperty.Register(
|
||||
"DotOffSet", typeof(double), typeof(LoadingCircle),
|
||||
new FrameworkPropertyMetadata(20.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
get => (double) GetValue(DotOffSetProperty);
|
||||
set => SetValue(DotOffSetProperty, value);
|
||||
}
|
||||
|
||||
public double DotOffSet
|
||||
public static readonly DependencyProperty NeedHiddenProperty = DependencyProperty.Register(
|
||||
"NeedHidden", typeof(bool), typeof(LoadingCircle),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool NeedHidden
|
||||
{
|
||||
get => (bool) GetValue(NeedHiddenProperty);
|
||||
set => SetValue(NeedHiddenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
static LoadingCircle()
|
||||
{
|
||||
DotSpeedProperty.OverrideMetadata(typeof(LoadingCircle),
|
||||
new FrameworkPropertyMetadata(6.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
DotDelayTimeProperty.OverrideMetadata(typeof(LoadingCircle),
|
||||
new FrameworkPropertyMetadata(220.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
}
|
||||
|
||||
protected sealed override void UpdateDots()
|
||||
{
|
||||
var dotCount = DotCount;
|
||||
var dotInterval = DotInterval;
|
||||
var dotSpeed = DotSpeed;
|
||||
var dotDelayTime = DotDelayTime;
|
||||
var needHidden = NeedHidden;
|
||||
|
||||
if (dotCount < 1) return;
|
||||
PrivateCanvas.Children.Clear();
|
||||
|
||||
//定义动画
|
||||
Storyboard = new Storyboard
|
||||
{
|
||||
get => (double) GetValue(DotOffSetProperty);
|
||||
set => SetValue(DotOffSetProperty, value);
|
||||
}
|
||||
RepeatBehavior = RepeatBehavior.Forever
|
||||
};
|
||||
|
||||
public static readonly DependencyProperty NeedHiddenProperty = DependencyProperty.Register(
|
||||
"NeedHidden", typeof(bool), typeof(LoadingCircle),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool NeedHidden
|
||||
//创建圆点
|
||||
for (var i = 0; i < dotCount; i++)
|
||||
{
|
||||
get => (bool) GetValue(NeedHiddenProperty);
|
||||
set => SetValue(NeedHiddenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
var border = CreateBorder(i, dotInterval, needHidden);
|
||||
|
||||
static LoadingCircle()
|
||||
{
|
||||
DotSpeedProperty.OverrideMetadata(typeof(LoadingCircle),
|
||||
new FrameworkPropertyMetadata(6.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
DotDelayTimeProperty.OverrideMetadata(typeof(LoadingCircle),
|
||||
new FrameworkPropertyMetadata(220.0, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
}
|
||||
|
||||
protected sealed override void UpdateDots()
|
||||
{
|
||||
var dotCount = DotCount;
|
||||
var dotInterval = DotInterval;
|
||||
var dotSpeed = DotSpeed;
|
||||
var dotDelayTime = DotDelayTime;
|
||||
var needHidden = NeedHidden;
|
||||
|
||||
if (dotCount < 1) return;
|
||||
PrivateCanvas.Children.Clear();
|
||||
|
||||
//定义动画
|
||||
Storyboard = new Storyboard
|
||||
var framesMove = new DoubleAnimationUsingKeyFrames
|
||||
{
|
||||
RepeatBehavior = RepeatBehavior.Forever
|
||||
BeginTime = TimeSpan.FromMilliseconds(dotDelayTime * i)
|
||||
};
|
||||
|
||||
//创建圆点
|
||||
for (var i = 0; i < dotCount; i++)
|
||||
var subAngle = -dotInterval * i;
|
||||
|
||||
//开始位置
|
||||
var frame0 = new LinearDoubleKeyFrame
|
||||
{
|
||||
var border = CreateBorder(i, dotInterval, needHidden);
|
||||
Value = 0 + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
|
||||
};
|
||||
|
||||
var framesMove = new DoubleAnimationUsingKeyFrames
|
||||
//开始位置到第一次匀速开始
|
||||
var frame1 = new EasingDoubleKeyFrame
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
BeginTime = TimeSpan.FromMilliseconds(dotDelayTime * i)
|
||||
};
|
||||
EasingMode = EasingMode.EaseOut
|
||||
},
|
||||
Value = 180 + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (0.75 / 7)))
|
||||
};
|
||||
|
||||
var subAngle = -dotInterval * i;
|
||||
//第一次匀速开始到第一次匀速结束
|
||||
var frame2 = new LinearDoubleKeyFrame
|
||||
{
|
||||
Value = 180 + DotOffSet + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (2.75 / 7)))
|
||||
};
|
||||
|
||||
//开始位置
|
||||
var frame0 = new LinearDoubleKeyFrame
|
||||
//第一次匀速结束到匀加速结束
|
||||
var frame3 = new EasingDoubleKeyFrame
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
Value = 0 + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
|
||||
};
|
||||
EasingMode = EasingMode.EaseIn
|
||||
},
|
||||
Value = 360 + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (3.5 / 7)))
|
||||
};
|
||||
|
||||
//开始位置到第一次匀速开始
|
||||
var frame1 = new EasingDoubleKeyFrame
|
||||
//匀加速结束到匀减速结束
|
||||
var frame4 = new EasingDoubleKeyFrame
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
},
|
||||
Value = 180 + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (0.75 / 7)))
|
||||
};
|
||||
EasingMode = EasingMode.EaseOut
|
||||
},
|
||||
Value = 540 + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (4.25 / 7)))
|
||||
};
|
||||
|
||||
//第一次匀速开始到第一次匀速结束
|
||||
var frame2 = new LinearDoubleKeyFrame
|
||||
{
|
||||
Value = 180 + DotOffSet + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (2.75 / 7)))
|
||||
};
|
||||
//匀减速结束到第二次匀速结束
|
||||
var frame5 = new LinearDoubleKeyFrame
|
||||
{
|
||||
Value = 540 + DotOffSet + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (6.25 / 7)))
|
||||
};
|
||||
|
||||
//第一次匀速结束到匀加速结束
|
||||
var frame3 = new EasingDoubleKeyFrame
|
||||
//第二次匀速结束到匀加速结束
|
||||
var frame6 = new EasingDoubleKeyFrame
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseIn
|
||||
},
|
||||
Value = 360 + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (3.5 / 7)))
|
||||
};
|
||||
EasingMode = EasingMode.EaseIn
|
||||
},
|
||||
Value = 720 + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed))
|
||||
};
|
||||
|
||||
//匀加速结束到匀减速结束
|
||||
var frame4 = new EasingDoubleKeyFrame
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
},
|
||||
Value = 540 + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (4.25 / 7)))
|
||||
};
|
||||
framesMove.KeyFrames.Add(frame0);
|
||||
framesMove.KeyFrames.Add(frame1);
|
||||
framesMove.KeyFrames.Add(frame2);
|
||||
framesMove.KeyFrames.Add(frame3);
|
||||
framesMove.KeyFrames.Add(frame4);
|
||||
framesMove.KeyFrames.Add(frame5);
|
||||
framesMove.KeyFrames.Add(frame6);
|
||||
|
||||
//匀减速结束到第二次匀速结束
|
||||
var frame5 = new LinearDoubleKeyFrame
|
||||
{
|
||||
Value = 540 + DotOffSet + subAngle,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (6.25 / 7)))
|
||||
};
|
||||
Storyboard.SetTarget(framesMove, border);
|
||||
Storyboard.SetTargetProperty(framesMove, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"));
|
||||
Storyboard.Children.Add(framesMove);
|
||||
|
||||
//第二次匀速结束到匀加速结束
|
||||
var frame6 = new EasingDoubleKeyFrame
|
||||
if (NeedHidden)
|
||||
{
|
||||
//隐藏一段时间
|
||||
var frame7 = new DiscreteObjectKeyFrame
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseIn
|
||||
},
|
||||
Value = 720 + subAngle,
|
||||
Value = Visibility.Collapsed,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed))
|
||||
};
|
||||
|
||||
framesMove.KeyFrames.Add(frame0);
|
||||
framesMove.KeyFrames.Add(frame1);
|
||||
framesMove.KeyFrames.Add(frame2);
|
||||
framesMove.KeyFrames.Add(frame3);
|
||||
framesMove.KeyFrames.Add(frame4);
|
||||
framesMove.KeyFrames.Add(frame5);
|
||||
framesMove.KeyFrames.Add(frame6);
|
||||
|
||||
Storyboard.SetTarget(framesMove, border);
|
||||
Storyboard.SetTargetProperty(framesMove, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"));
|
||||
Storyboard.Children.Add(framesMove);
|
||||
|
||||
if (NeedHidden)
|
||||
var frame8 = new DiscreteObjectKeyFrame
|
||||
{
|
||||
//隐藏一段时间
|
||||
var frame7 = new DiscreteObjectKeyFrame
|
||||
{
|
||||
Value = Visibility.Collapsed,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed))
|
||||
};
|
||||
Value = Visibility.Collapsed,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed + 0.4))
|
||||
};
|
||||
|
||||
var frame8 = new DiscreteObjectKeyFrame
|
||||
{
|
||||
Value = Visibility.Collapsed,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed + 0.4))
|
||||
};
|
||||
|
||||
var frame9 = new DiscreteObjectKeyFrame
|
||||
{
|
||||
Value = Visibility.Visible,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
|
||||
};
|
||||
var framesVisibility = new ObjectAnimationUsingKeyFrames
|
||||
{
|
||||
BeginTime = TimeSpan.FromMilliseconds(dotDelayTime * i)
|
||||
};
|
||||
framesVisibility.KeyFrames.Add(frame9);
|
||||
framesVisibility.KeyFrames.Add(frame7);
|
||||
framesVisibility.KeyFrames.Add(frame8);
|
||||
Storyboard.SetTarget(framesVisibility, border);
|
||||
Storyboard.SetTargetProperty(framesVisibility, new PropertyPath("(UIElement.Visibility)"));
|
||||
Storyboard.Children.Add(framesVisibility);
|
||||
}
|
||||
PrivateCanvas.Children.Add(border);
|
||||
}
|
||||
|
||||
Storyboard.Begin();
|
||||
if (!IsRunning)
|
||||
{
|
||||
Storyboard.Pause();
|
||||
var frame9 = new DiscreteObjectKeyFrame
|
||||
{
|
||||
Value = Visibility.Visible,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
|
||||
};
|
||||
var framesVisibility = new ObjectAnimationUsingKeyFrames
|
||||
{
|
||||
BeginTime = TimeSpan.FromMilliseconds(dotDelayTime * i)
|
||||
};
|
||||
framesVisibility.KeyFrames.Add(frame9);
|
||||
framesVisibility.KeyFrames.Add(frame7);
|
||||
framesVisibility.KeyFrames.Add(frame8);
|
||||
Storyboard.SetTarget(framesVisibility, border);
|
||||
Storyboard.SetTargetProperty(framesVisibility, new PropertyPath("(UIElement.Visibility)"));
|
||||
Storyboard.Children.Add(framesVisibility);
|
||||
}
|
||||
PrivateCanvas.Children.Add(border);
|
||||
}
|
||||
|
||||
private Border CreateBorder(int index, double dotInterval, bool needHidden)
|
||||
Storyboard.Begin();
|
||||
if (!IsRunning)
|
||||
{
|
||||
var ellipse = CreateEllipse(index);
|
||||
ellipse.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
ellipse.VerticalAlignment = VerticalAlignment.Bottom;
|
||||
var rt = new RotateTransform
|
||||
{
|
||||
Angle = -dotInterval * index
|
||||
};
|
||||
var myTransGroup = new TransformGroup();
|
||||
myTransGroup.Children.Add(rt);
|
||||
var border = new Border
|
||||
{
|
||||
RenderTransformOrigin = new Point(0.5, 0.5),
|
||||
RenderTransform = myTransGroup,
|
||||
Child = ellipse,
|
||||
Visibility = needHidden ? Visibility.Collapsed : Visibility.Visible
|
||||
};
|
||||
border.SetBinding(WidthProperty, new Binding("Width") { Source = this });
|
||||
border.SetBinding(HeightProperty, new Binding("Height") { Source = this });
|
||||
|
||||
return border;
|
||||
Storyboard.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
private Border CreateBorder(int index, double dotInterval, bool needHidden)
|
||||
{
|
||||
var ellipse = CreateEllipse(index);
|
||||
ellipse.HorizontalAlignment = HorizontalAlignment.Center;
|
||||
ellipse.VerticalAlignment = VerticalAlignment.Bottom;
|
||||
var rt = new RotateTransform
|
||||
{
|
||||
Angle = -dotInterval * index
|
||||
};
|
||||
var myTransGroup = new TransformGroup();
|
||||
myTransGroup.Children.Add(rt);
|
||||
var border = new Border
|
||||
{
|
||||
RenderTransformOrigin = new Point(0.5, 0.5),
|
||||
RenderTransform = myTransGroup,
|
||||
Child = ellipse,
|
||||
Visibility = needHidden ? Visibility.Collapsed : Visibility.Visible
|
||||
};
|
||||
border.SetBinding(WidthProperty, new Binding("Width") { Source = this });
|
||||
border.SetBinding(HeightProperty, new Binding("Height") { Source = this });
|
||||
|
||||
return border;
|
||||
}
|
||||
}
|
||||
@@ -5,112 +5,111 @@ using System.Windows.Media.Animation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class LoadingLine : LoadingBase
|
||||
{
|
||||
public class LoadingLine : LoadingBase
|
||||
private const double MoveLength = 80;
|
||||
|
||||
private const double UniformScale = .6;
|
||||
|
||||
public LoadingLine()
|
||||
{
|
||||
private const double MoveLength = 80;
|
||||
SetBinding(HeightProperty, new Binding("DotDiameter") { Source = this });
|
||||
}
|
||||
|
||||
private const double UniformScale = .6;
|
||||
protected sealed override void UpdateDots()
|
||||
{
|
||||
var dotCount = DotCount;
|
||||
var dotInterval = DotInterval;
|
||||
var dotDiameter = DotDiameter;
|
||||
var dotSpeed = DotSpeed;
|
||||
var dotDelayTime = DotDelayTime;
|
||||
|
||||
public LoadingLine()
|
||||
if (dotCount < 1) return;
|
||||
PrivateCanvas.Children.Clear();
|
||||
|
||||
//计算相关尺寸
|
||||
var centerWidth = dotDiameter * dotCount + dotInterval * (dotCount - 1) + MoveLength;
|
||||
var speedDownLength = (ActualWidth - MoveLength) / 2;
|
||||
var speedUniformLength = centerWidth / 2;
|
||||
|
||||
//定义动画
|
||||
Storyboard = new Storyboard
|
||||
{
|
||||
SetBinding(HeightProperty, new Binding("DotDiameter") { Source = this });
|
||||
}
|
||||
RepeatBehavior = RepeatBehavior.Forever
|
||||
};
|
||||
|
||||
protected sealed override void UpdateDots()
|
||||
//创建圆点
|
||||
for (var i = 0; i < dotCount; i++)
|
||||
{
|
||||
var dotCount = DotCount;
|
||||
var dotInterval = DotInterval;
|
||||
var dotDiameter = DotDiameter;
|
||||
var dotSpeed = DotSpeed;
|
||||
var dotDelayTime = DotDelayTime;
|
||||
var ellipse = CreateEllipse(i, dotInterval, dotDiameter);
|
||||
|
||||
if (dotCount < 1) return;
|
||||
PrivateCanvas.Children.Clear();
|
||||
|
||||
//计算相关尺寸
|
||||
var centerWidth = dotDiameter * dotCount + dotInterval * (dotCount - 1) + MoveLength;
|
||||
var speedDownLength = (ActualWidth - MoveLength) / 2;
|
||||
var speedUniformLength = centerWidth / 2;
|
||||
|
||||
//定义动画
|
||||
Storyboard = new Storyboard
|
||||
var frames = new ThicknessAnimationUsingKeyFrames
|
||||
{
|
||||
RepeatBehavior = RepeatBehavior.Forever
|
||||
BeginTime = TimeSpan.FromMilliseconds(dotDelayTime * i)
|
||||
};
|
||||
//开始位置
|
||||
var frame0 = new LinearThicknessKeyFrame
|
||||
{
|
||||
Value = new Thickness(ellipse.Margin.Left, 0, 0, 0),
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
|
||||
};
|
||||
|
||||
//创建圆点
|
||||
for (var i = 0; i < dotCount; i++)
|
||||
//开始位置到匀速开始
|
||||
var frame1 = new EasingThicknessKeyFrame
|
||||
{
|
||||
var ellipse = CreateEllipse(i, dotInterval, dotDiameter);
|
||||
|
||||
var frames = new ThicknessAnimationUsingKeyFrames
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
BeginTime = TimeSpan.FromMilliseconds(dotDelayTime * i)
|
||||
};
|
||||
//开始位置
|
||||
var frame0 = new LinearThicknessKeyFrame
|
||||
{
|
||||
Value = new Thickness(ellipse.Margin.Left, 0, 0, 0),
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
|
||||
};
|
||||
EasingMode = EasingMode.EaseOut
|
||||
},
|
||||
Value = new Thickness(speedDownLength + ellipse.Margin.Left, 0, 0, 0),
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (1 - UniformScale) / 2))
|
||||
};
|
||||
|
||||
//开始位置到匀速开始
|
||||
var frame1 = new EasingThicknessKeyFrame
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
},
|
||||
Value = new Thickness(speedDownLength + ellipse.Margin.Left, 0, 0, 0),
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (1 - UniformScale) / 2))
|
||||
};
|
||||
|
||||
//匀速开始到匀速结束
|
||||
var frame2 = new LinearThicknessKeyFrame
|
||||
{
|
||||
Value = new Thickness(speedDownLength + speedUniformLength + ellipse.Margin.Left, 0, 0, 0),
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (1 + UniformScale) / 2))
|
||||
};
|
||||
|
||||
//匀速结束到匀加速结束
|
||||
var frame3 = new EasingThicknessKeyFrame
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseIn
|
||||
},
|
||||
Value = new Thickness(ActualWidth + ellipse.Margin.Left + speedUniformLength, 0, 0, 0),
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed))
|
||||
};
|
||||
|
||||
frames.KeyFrames.Add(frame0);
|
||||
frames.KeyFrames.Add(frame1);
|
||||
frames.KeyFrames.Add(frame2);
|
||||
frames.KeyFrames.Add(frame3);
|
||||
|
||||
Storyboard.SetTarget(frames, ellipse);
|
||||
Storyboard.SetTargetProperty(frames, new PropertyPath(MarginProperty));
|
||||
Storyboard.Children.Add(frames);
|
||||
|
||||
PrivateCanvas.Children.Add(ellipse);
|
||||
}
|
||||
|
||||
Storyboard.Begin();
|
||||
if (!IsRunning)
|
||||
//匀速开始到匀速结束
|
||||
var frame2 = new LinearThicknessKeyFrame
|
||||
{
|
||||
Storyboard.Pause();
|
||||
}
|
||||
Value = new Thickness(speedDownLength + speedUniformLength + ellipse.Margin.Left, 0, 0, 0),
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed * (1 + UniformScale) / 2))
|
||||
};
|
||||
|
||||
//匀速结束到匀加速结束
|
||||
var frame3 = new EasingThicknessKeyFrame
|
||||
{
|
||||
EasingFunction = new PowerEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseIn
|
||||
},
|
||||
Value = new Thickness(ActualWidth + ellipse.Margin.Left + speedUniformLength, 0, 0, 0),
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(dotSpeed))
|
||||
};
|
||||
|
||||
frames.KeyFrames.Add(frame0);
|
||||
frames.KeyFrames.Add(frame1);
|
||||
frames.KeyFrames.Add(frame2);
|
||||
frames.KeyFrames.Add(frame3);
|
||||
|
||||
Storyboard.SetTarget(frames, ellipse);
|
||||
Storyboard.SetTargetProperty(frames, new PropertyPath(MarginProperty));
|
||||
Storyboard.Children.Add(frames);
|
||||
|
||||
PrivateCanvas.Children.Add(ellipse);
|
||||
}
|
||||
|
||||
private Ellipse CreateEllipse(int index, double dotInterval, double dotDiameter)
|
||||
Storyboard.Begin();
|
||||
if (!IsRunning)
|
||||
{
|
||||
var ellipse = base.CreateEllipse(index);
|
||||
ellipse.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
ellipse.VerticalAlignment = VerticalAlignment.Top;
|
||||
ellipse.Margin = new Thickness(-(dotInterval + dotDiameter) * index, 0, 0, 0);
|
||||
return ellipse;
|
||||
Storyboard.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
private Ellipse CreateEllipse(int index, double dotInterval, double dotDiameter)
|
||||
{
|
||||
var ellipse = base.CreateEllipse(index);
|
||||
ellipse.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
ellipse.VerticalAlignment = VerticalAlignment.Top;
|
||||
ellipse.Margin = new Thickness(-(dotInterval + dotDiameter) * index, 0, 0, 0);
|
||||
return ellipse;
|
||||
}
|
||||
}
|
||||
@@ -8,164 +8,163 @@ using HandyControl.Data;
|
||||
using HandyControl.Expression.Drawing;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class AnimationPath : Shape
|
||||
{
|
||||
public class AnimationPath : Shape
|
||||
private Storyboard _storyboard;
|
||||
|
||||
private double _pathLength;
|
||||
|
||||
public static readonly DependencyProperty DataProperty = DependencyProperty.Register(nameof(Data),
|
||||
typeof(Geometry), typeof(AnimationPath), new FrameworkPropertyMetadata(null,
|
||||
OnPropertiesChanged));
|
||||
|
||||
private static void OnPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
private Storyboard _storyboard;
|
||||
|
||||
private double _pathLength;
|
||||
|
||||
public static readonly DependencyProperty DataProperty = DependencyProperty.Register(nameof(Data),
|
||||
typeof(Geometry), typeof(AnimationPath), new FrameworkPropertyMetadata(null,
|
||||
OnPropertiesChanged));
|
||||
|
||||
private static void OnPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
if (d is AnimationPath path)
|
||||
{
|
||||
if (d is AnimationPath path)
|
||||
{
|
||||
path.UpdatePath();
|
||||
}
|
||||
path.UpdatePath();
|
||||
}
|
||||
|
||||
public Geometry Data
|
||||
{
|
||||
get => (Geometry) GetValue(DataProperty);
|
||||
set => SetValue(DataProperty, value);
|
||||
}
|
||||
|
||||
protected override Geometry DefiningGeometry => Data ?? Geometry.Empty;
|
||||
|
||||
public static readonly DependencyProperty PathLengthProperty = DependencyProperty.Register(
|
||||
"PathLength", typeof(double), typeof(AnimationPath), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, OnPropertiesChanged));
|
||||
|
||||
public double PathLength
|
||||
{
|
||||
get => (double) GetValue(PathLengthProperty);
|
||||
set => SetValue(PathLengthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register(
|
||||
"Duration", typeof(Duration), typeof(AnimationPath), new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(2)),
|
||||
OnPropertiesChanged));
|
||||
|
||||
public Duration Duration
|
||||
{
|
||||
get => (Duration) GetValue(DurationProperty);
|
||||
set => SetValue(DurationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(
|
||||
"IsPlaying", typeof(bool), typeof(AnimationPath), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, (o, args) =>
|
||||
{
|
||||
var ctl = (AnimationPath) o;
|
||||
var v = (bool) args.NewValue;
|
||||
if (v)
|
||||
{
|
||||
ctl.UpdatePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl._storyboard?.Pause();
|
||||
}
|
||||
}));
|
||||
|
||||
public bool IsPlaying
|
||||
{
|
||||
get => (bool) GetValue(IsPlayingProperty);
|
||||
set => SetValue(IsPlayingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RepeatBehaviorProperty =
|
||||
Timeline.RepeatBehaviorProperty.AddOwner(typeof(AnimationPath),
|
||||
new PropertyMetadata(RepeatBehavior.Forever));
|
||||
|
||||
public RepeatBehavior RepeatBehavior
|
||||
{
|
||||
get => (RepeatBehavior) GetValue(RepeatBehaviorProperty);
|
||||
set => SetValue(RepeatBehaviorProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FillBehaviorProperty =
|
||||
Timeline.FillBehaviorProperty.AddOwner(typeof(AnimationPath), new PropertyMetadata(FillBehavior.Stop));
|
||||
|
||||
public FillBehavior FillBehavior
|
||||
{
|
||||
get { return (FillBehavior) GetValue(FillBehaviorProperty); }
|
||||
set { SetValue(FillBehaviorProperty, value); }
|
||||
}
|
||||
|
||||
static AnimationPath()
|
||||
{
|
||||
StretchProperty.AddOwner(typeof(AnimationPath), new FrameworkPropertyMetadata(Stretch.Uniform,
|
||||
OnPropertiesChanged));
|
||||
|
||||
StrokeThicknessProperty.AddOwner(typeof(AnimationPath), new FrameworkPropertyMetadata(ValueBoxes.Double1Box,
|
||||
OnPropertiesChanged));
|
||||
}
|
||||
|
||||
public AnimationPath() => Loaded += (s, e) => UpdatePath();
|
||||
|
||||
public static readonly RoutedEvent CompletedEvent =
|
||||
EventManager.RegisterRoutedEvent("Completed", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler), typeof(AnimationPath));
|
||||
|
||||
public event EventHandler Completed
|
||||
{
|
||||
add => AddHandler(CompletedEvent, value);
|
||||
remove => RemoveHandler(CompletedEvent, value);
|
||||
}
|
||||
|
||||
private void UpdatePath()
|
||||
{
|
||||
if (!Duration.HasTimeSpan || !IsPlaying) return;
|
||||
|
||||
_pathLength = PathLength > 0 ? PathLength : Data.GetTotalLength(new Size(ActualWidth, ActualHeight), StrokeThickness);
|
||||
|
||||
if (MathHelper.IsVerySmall(_pathLength)) return;
|
||||
|
||||
StrokeDashOffset = _pathLength;
|
||||
StrokeDashArray = new DoubleCollection(new List<double>
|
||||
{
|
||||
_pathLength,
|
||||
_pathLength
|
||||
});
|
||||
|
||||
if (_storyboard != null)
|
||||
{
|
||||
_storyboard.Stop();
|
||||
_storyboard.Completed -= Storyboard_Completed;
|
||||
}
|
||||
_storyboard = new Storyboard
|
||||
{
|
||||
RepeatBehavior = RepeatBehavior,
|
||||
FillBehavior = FillBehavior
|
||||
};
|
||||
_storyboard.Completed += Storyboard_Completed;
|
||||
|
||||
var frames = new DoubleAnimationUsingKeyFrames();
|
||||
|
||||
var frameIn = new LinearDoubleKeyFrame
|
||||
{
|
||||
Value = _pathLength,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
|
||||
};
|
||||
frames.KeyFrames.Add(frameIn);
|
||||
|
||||
var frameOut = new LinearDoubleKeyFrame
|
||||
{
|
||||
Value = FillBehavior == FillBehavior.Stop ? -_pathLength : 0,
|
||||
KeyTime = KeyTime.FromTimeSpan(Duration.TimeSpan)
|
||||
};
|
||||
frames.KeyFrames.Add(frameOut);
|
||||
|
||||
Storyboard.SetTarget(frames, this);
|
||||
Storyboard.SetTargetProperty(frames, new PropertyPath(StrokeDashOffsetProperty));
|
||||
_storyboard.Children.Add(frames);
|
||||
|
||||
_storyboard.Begin();
|
||||
}
|
||||
|
||||
private void Storyboard_Completed(object sender, EventArgs e) => RaiseEvent(new RoutedEventArgs(CompletedEvent));
|
||||
}
|
||||
|
||||
public Geometry Data
|
||||
{
|
||||
get => (Geometry) GetValue(DataProperty);
|
||||
set => SetValue(DataProperty, value);
|
||||
}
|
||||
|
||||
protected override Geometry DefiningGeometry => Data ?? Geometry.Empty;
|
||||
|
||||
public static readonly DependencyProperty PathLengthProperty = DependencyProperty.Register(
|
||||
"PathLength", typeof(double), typeof(AnimationPath), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, OnPropertiesChanged));
|
||||
|
||||
public double PathLength
|
||||
{
|
||||
get => (double) GetValue(PathLengthProperty);
|
||||
set => SetValue(PathLengthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register(
|
||||
"Duration", typeof(Duration), typeof(AnimationPath), new FrameworkPropertyMetadata(new Duration(TimeSpan.FromSeconds(2)),
|
||||
OnPropertiesChanged));
|
||||
|
||||
public Duration Duration
|
||||
{
|
||||
get => (Duration) GetValue(DurationProperty);
|
||||
set => SetValue(DurationProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(
|
||||
"IsPlaying", typeof(bool), typeof(AnimationPath), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, (o, args) =>
|
||||
{
|
||||
var ctl = (AnimationPath) o;
|
||||
var v = (bool) args.NewValue;
|
||||
if (v)
|
||||
{
|
||||
ctl.UpdatePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctl._storyboard?.Pause();
|
||||
}
|
||||
}));
|
||||
|
||||
public bool IsPlaying
|
||||
{
|
||||
get => (bool) GetValue(IsPlayingProperty);
|
||||
set => SetValue(IsPlayingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty RepeatBehaviorProperty =
|
||||
Timeline.RepeatBehaviorProperty.AddOwner(typeof(AnimationPath),
|
||||
new PropertyMetadata(RepeatBehavior.Forever));
|
||||
|
||||
public RepeatBehavior RepeatBehavior
|
||||
{
|
||||
get => (RepeatBehavior) GetValue(RepeatBehaviorProperty);
|
||||
set => SetValue(RepeatBehaviorProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty FillBehaviorProperty =
|
||||
Timeline.FillBehaviorProperty.AddOwner(typeof(AnimationPath), new PropertyMetadata(FillBehavior.Stop));
|
||||
|
||||
public FillBehavior FillBehavior
|
||||
{
|
||||
get { return (FillBehavior) GetValue(FillBehaviorProperty); }
|
||||
set { SetValue(FillBehaviorProperty, value); }
|
||||
}
|
||||
|
||||
static AnimationPath()
|
||||
{
|
||||
StretchProperty.AddOwner(typeof(AnimationPath), new FrameworkPropertyMetadata(Stretch.Uniform,
|
||||
OnPropertiesChanged));
|
||||
|
||||
StrokeThicknessProperty.AddOwner(typeof(AnimationPath), new FrameworkPropertyMetadata(ValueBoxes.Double1Box,
|
||||
OnPropertiesChanged));
|
||||
}
|
||||
|
||||
public AnimationPath() => Loaded += (s, e) => UpdatePath();
|
||||
|
||||
public static readonly RoutedEvent CompletedEvent =
|
||||
EventManager.RegisterRoutedEvent("Completed", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler), typeof(AnimationPath));
|
||||
|
||||
public event EventHandler Completed
|
||||
{
|
||||
add => AddHandler(CompletedEvent, value);
|
||||
remove => RemoveHandler(CompletedEvent, value);
|
||||
}
|
||||
|
||||
private void UpdatePath()
|
||||
{
|
||||
if (!Duration.HasTimeSpan || !IsPlaying) return;
|
||||
|
||||
_pathLength = PathLength > 0 ? PathLength : Data.GetTotalLength(new Size(ActualWidth, ActualHeight), StrokeThickness);
|
||||
|
||||
if (MathHelper.IsVerySmall(_pathLength)) return;
|
||||
|
||||
StrokeDashOffset = _pathLength;
|
||||
StrokeDashArray = new DoubleCollection(new List<double>
|
||||
{
|
||||
_pathLength,
|
||||
_pathLength
|
||||
});
|
||||
|
||||
if (_storyboard != null)
|
||||
{
|
||||
_storyboard.Stop();
|
||||
_storyboard.Completed -= Storyboard_Completed;
|
||||
}
|
||||
_storyboard = new Storyboard
|
||||
{
|
||||
RepeatBehavior = RepeatBehavior,
|
||||
FillBehavior = FillBehavior
|
||||
};
|
||||
_storyboard.Completed += Storyboard_Completed;
|
||||
|
||||
var frames = new DoubleAnimationUsingKeyFrames();
|
||||
|
||||
var frameIn = new LinearDoubleKeyFrame
|
||||
{
|
||||
Value = _pathLength,
|
||||
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero)
|
||||
};
|
||||
frames.KeyFrames.Add(frameIn);
|
||||
|
||||
var frameOut = new LinearDoubleKeyFrame
|
||||
{
|
||||
Value = FillBehavior == FillBehavior.Stop ? -_pathLength : 0,
|
||||
KeyTime = KeyTime.FromTimeSpan(Duration.TimeSpan)
|
||||
};
|
||||
frames.KeyFrames.Add(frameOut);
|
||||
|
||||
Storyboard.SetTarget(frames, this);
|
||||
Storyboard.SetTargetProperty(frames, new PropertyPath(StrokeDashOffsetProperty));
|
||||
_storyboard.Children.Add(frames);
|
||||
|
||||
_storyboard.Begin();
|
||||
}
|
||||
|
||||
private void Storyboard_Completed(object sender, EventArgs e) => RaiseEvent(new RoutedEventArgs(CompletedEvent));
|
||||
}
|
||||
@@ -4,98 +4,97 @@ using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 标记
|
||||
/// </summary>
|
||||
public class Badge : ContentControl
|
||||
{
|
||||
/// <summary>
|
||||
/// 标记
|
||||
/// </summary>
|
||||
public class Badge : ContentControl
|
||||
public static readonly RoutedEvent ValueChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<int>>), typeof(Badge));
|
||||
|
||||
public event EventHandler<FunctionEventArgs<int>> ValueChanged
|
||||
{
|
||||
public static readonly RoutedEvent ValueChangedEvent =
|
||||
EventManager.RegisterRoutedEvent("ValueChanged", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<int>>), typeof(Badge));
|
||||
|
||||
public event EventHandler<FunctionEventArgs<int>> ValueChanged
|
||||
{
|
||||
add => AddHandler(ValueChangedEvent, value);
|
||||
remove => RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
|
||||
"Text", typeof(string), typeof(Badge), new PropertyMetadata("0"));
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string) GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
|
||||
"Value", typeof(int), typeof(Badge), new PropertyMetadata(ValueBoxes.Int0Box, OnValueChanged));
|
||||
|
||||
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Badge) d;
|
||||
var v = (int) e.NewValue;
|
||||
ctl.SetCurrentValue(TextProperty, v <= ctl.Maximum ? v.ToString() : $"{ctl.Maximum}+");
|
||||
if (ctl.IsInitialized)
|
||||
{
|
||||
ctl.RaiseEvent(new FunctionEventArgs<int>(ValueChangedEvent, ctl)
|
||||
{
|
||||
Info = v
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public int Value
|
||||
{
|
||||
get => (int) GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StatusProperty = DependencyProperty.Register(
|
||||
"Status", typeof(BadgeStatus), typeof(Badge), new PropertyMetadata(default(BadgeStatus)));
|
||||
|
||||
public BadgeStatus Status
|
||||
{
|
||||
get => (BadgeStatus) GetValue(StatusProperty);
|
||||
set => SetValue(StatusProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
|
||||
"Maximum", typeof(int), typeof(Badge), new PropertyMetadata(ValueBoxes.Int99Box, OnMaximumChanged));
|
||||
|
||||
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Badge) d;
|
||||
var v = ctl.Value;
|
||||
ctl.SetCurrentValue(TextProperty, v <= ctl.Maximum ? v.ToString() : $"{ctl.Maximum}+");
|
||||
}
|
||||
|
||||
public int Maximum
|
||||
{
|
||||
get => (int) GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BadgeMarginProperty = DependencyProperty.Register(
|
||||
"BadgeMargin", typeof(Thickness), typeof(Badge), new PropertyMetadata(default(Thickness)));
|
||||
|
||||
public Thickness BadgeMargin
|
||||
{
|
||||
get => (Thickness) GetValue(BadgeMarginProperty);
|
||||
set => SetValue(BadgeMarginProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowBadgeProperty = DependencyProperty.Register(
|
||||
"ShowBadge", typeof(bool), typeof(Badge), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool ShowBadge
|
||||
{
|
||||
get => (bool) GetValue(ShowBadgeProperty);
|
||||
set => SetValue(ShowBadgeProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
protected override Geometry GetLayoutClip(Size layoutSlotSize) => null;
|
||||
add => AddHandler(ValueChangedEvent, value);
|
||||
remove => RemoveHandler(ValueChangedEvent, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
|
||||
"Text", typeof(string), typeof(Badge), new PropertyMetadata("0"));
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string) GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
|
||||
"Value", typeof(int), typeof(Badge), new PropertyMetadata(ValueBoxes.Int0Box, OnValueChanged));
|
||||
|
||||
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Badge) d;
|
||||
var v = (int) e.NewValue;
|
||||
ctl.SetCurrentValue(TextProperty, v <= ctl.Maximum ? v.ToString() : $"{ctl.Maximum}+");
|
||||
if (ctl.IsInitialized)
|
||||
{
|
||||
ctl.RaiseEvent(new FunctionEventArgs<int>(ValueChangedEvent, ctl)
|
||||
{
|
||||
Info = v
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public int Value
|
||||
{
|
||||
get => (int) GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty StatusProperty = DependencyProperty.Register(
|
||||
"Status", typeof(BadgeStatus), typeof(Badge), new PropertyMetadata(default(BadgeStatus)));
|
||||
|
||||
public BadgeStatus Status
|
||||
{
|
||||
get => (BadgeStatus) GetValue(StatusProperty);
|
||||
set => SetValue(StatusProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register(
|
||||
"Maximum", typeof(int), typeof(Badge), new PropertyMetadata(ValueBoxes.Int99Box, OnMaximumChanged));
|
||||
|
||||
private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Badge) d;
|
||||
var v = ctl.Value;
|
||||
ctl.SetCurrentValue(TextProperty, v <= ctl.Maximum ? v.ToString() : $"{ctl.Maximum}+");
|
||||
}
|
||||
|
||||
public int Maximum
|
||||
{
|
||||
get => (int) GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BadgeMarginProperty = DependencyProperty.Register(
|
||||
"BadgeMargin", typeof(Thickness), typeof(Badge), new PropertyMetadata(default(Thickness)));
|
||||
|
||||
public Thickness BadgeMargin
|
||||
{
|
||||
get => (Thickness) GetValue(BadgeMarginProperty);
|
||||
set => SetValue(BadgeMarginProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowBadgeProperty = DependencyProperty.Register(
|
||||
"ShowBadge", typeof(bool), typeof(Badge), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool ShowBadge
|
||||
{
|
||||
get => (bool) GetValue(ShowBadgeProperty);
|
||||
set => SetValue(ShowBadgeProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
protected override Geometry GetLayoutClip(Size layoutSlotSize) => null;
|
||||
}
|
||||
@@ -7,110 +7,109 @@ using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media.Effects;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[DefaultProperty("Content")]
|
||||
[ContentProperty("Content")]
|
||||
public class BlendEffectBox : Control
|
||||
{
|
||||
[DefaultProperty("Content")]
|
||||
[ContentProperty("Content")]
|
||||
public class BlendEffectBox : Control
|
||||
private readonly ContentPresenter _effectBottomPresenter;
|
||||
|
||||
private readonly ContentPresenter _effectTopPresenter;
|
||||
|
||||
private bool _isInternalAction;
|
||||
|
||||
public BlendEffectBox()
|
||||
{
|
||||
private readonly ContentPresenter _effectBottomPresenter;
|
||||
_effectTopPresenter = new ContentPresenter();
|
||||
ActualContent = _effectTopPresenter;
|
||||
|
||||
private readonly ContentPresenter _effectTopPresenter;
|
||||
|
||||
private bool _isInternalAction;
|
||||
|
||||
public BlendEffectBox()
|
||||
_effectBottomPresenter = new ContentPresenter();
|
||||
_effectBottomPresenter.SetBinding(ContentPresenter.ContentProperty, new Binding(ContentProperty.Name)
|
||||
{
|
||||
_effectTopPresenter = new ContentPresenter();
|
||||
ActualContent = _effectTopPresenter;
|
||||
Source = this
|
||||
});
|
||||
|
||||
_effectBottomPresenter = new ContentPresenter();
|
||||
_effectBottomPresenter.SetBinding(ContentPresenter.ContentProperty, new Binding(ContentProperty.Name)
|
||||
{
|
||||
Source = this
|
||||
});
|
||||
var effects = new ObservableCollection<Effect>();
|
||||
effects.CollectionChanged += OnEffectsChanged;
|
||||
Effects = effects;
|
||||
}
|
||||
|
||||
var effects = new ObservableCollection<Effect>();
|
||||
effects.CollectionChanged += OnEffectsChanged;
|
||||
Effects = effects;
|
||||
private void OnEffectsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (Effects == null || Effects.Count == 0)
|
||||
{
|
||||
ClearEffect(_effectTopPresenter);
|
||||
return;
|
||||
}
|
||||
|
||||
private void OnEffectsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
if (_isInternalAction) return;
|
||||
|
||||
_isInternalAction = true;
|
||||
AddEffect(_effectTopPresenter, Effects.Count);
|
||||
_isInternalAction = false;
|
||||
}
|
||||
|
||||
private void ClearEffect(ContentPresenter presenter)
|
||||
{
|
||||
if (presenter == null) return;
|
||||
|
||||
if (ReferenceEquals(_effectBottomPresenter, presenter))
|
||||
{
|
||||
if (Effects == null || Effects.Count == 0)
|
||||
_effectBottomPresenter.SetCurrentValue(EffectProperty, null);
|
||||
return;
|
||||
}
|
||||
|
||||
presenter.SetCurrentValue(EffectProperty, null);
|
||||
ClearEffect(presenter.Content as ContentPresenter);
|
||||
}
|
||||
|
||||
private void AddEffect(ContentPresenter presenter, int count)
|
||||
{
|
||||
var newCount = --count;
|
||||
|
||||
if (newCount >= 0)
|
||||
{
|
||||
presenter.Effect = Effects[newCount];
|
||||
|
||||
var nextCount = --count;
|
||||
if (nextCount >= 1)
|
||||
{
|
||||
ClearEffect(_effectTopPresenter);
|
||||
return;
|
||||
var content = new ContentPresenter();
|
||||
presenter.Content = content;
|
||||
AddEffect(content, newCount);
|
||||
}
|
||||
|
||||
if (_isInternalAction) return;
|
||||
|
||||
_isInternalAction = true;
|
||||
AddEffect(_effectTopPresenter, Effects.Count);
|
||||
_isInternalAction = false;
|
||||
}
|
||||
|
||||
private void ClearEffect(ContentPresenter presenter)
|
||||
{
|
||||
if (presenter == null) return;
|
||||
|
||||
if (ReferenceEquals(_effectBottomPresenter, presenter))
|
||||
else if (nextCount >= 0)
|
||||
{
|
||||
_effectBottomPresenter.SetCurrentValue(EffectProperty, null);
|
||||
return;
|
||||
_effectBottomPresenter.Effect = Effects[0];
|
||||
presenter.Content = _effectBottomPresenter;
|
||||
}
|
||||
|
||||
presenter.SetCurrentValue(EffectProperty, null);
|
||||
ClearEffect(presenter.Content as ContentPresenter);
|
||||
}
|
||||
|
||||
private void AddEffect(ContentPresenter presenter, int count)
|
||||
{
|
||||
var newCount = --count;
|
||||
|
||||
if (newCount >= 0)
|
||||
else
|
||||
{
|
||||
presenter.Effect = Effects[newCount];
|
||||
|
||||
var nextCount = --count;
|
||||
if (nextCount >= 1)
|
||||
{
|
||||
var content = new ContentPresenter();
|
||||
presenter.Content = content;
|
||||
AddEffect(content, newCount);
|
||||
}
|
||||
else if (nextCount >= 0)
|
||||
{
|
||||
_effectBottomPresenter.Effect = Effects[0];
|
||||
presenter.Content = _effectBottomPresenter;
|
||||
}
|
||||
else
|
||||
{
|
||||
presenter.Content = _effectBottomPresenter;
|
||||
}
|
||||
presenter.Content = _effectBottomPresenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
||||
[Bindable(true)]
|
||||
public Collection<Effect> Effects { get; }
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
||||
[Bindable(true)]
|
||||
public Collection<Effect> Effects { get; }
|
||||
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
"Content", typeof(FrameworkElement), typeof(BlendEffectBox), new PropertyMetadata(default(FrameworkElement)));
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
"Content", typeof(FrameworkElement), typeof(BlendEffectBox), new PropertyMetadata(default(FrameworkElement)));
|
||||
|
||||
public FrameworkElement Content
|
||||
{
|
||||
get => (FrameworkElement) GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
public FrameworkElement Content
|
||||
{
|
||||
get => (FrameworkElement) GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
internal static readonly DependencyProperty ActualContentProperty = DependencyProperty.Register(
|
||||
"ActualContent", typeof(FrameworkElement), typeof(BlendEffectBox), new PropertyMetadata(default(FrameworkElement)));
|
||||
internal static readonly DependencyProperty ActualContentProperty = DependencyProperty.Register(
|
||||
"ActualContent", typeof(FrameworkElement), typeof(BlendEffectBox), new PropertyMetadata(default(FrameworkElement)));
|
||||
|
||||
internal FrameworkElement ActualContent
|
||||
{
|
||||
get => (FrameworkElement) GetValue(ActualContentProperty);
|
||||
set => SetValue(ActualContentProperty, value);
|
||||
}
|
||||
internal FrameworkElement ActualContent
|
||||
{
|
||||
get => (FrameworkElement) GetValue(ActualContentProperty);
|
||||
set => SetValue(ActualContentProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -2,86 +2,85 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class Card : ContentControl
|
||||
{
|
||||
public class Card : ContentControl
|
||||
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
|
||||
"Header", typeof(object), typeof(Card), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Header
|
||||
{
|
||||
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
|
||||
"Header", typeof(object), typeof(Card), new PropertyMetadata(default(object)));
|
||||
get => GetValue(HeaderProperty);
|
||||
set => SetValue(HeaderProperty, value);
|
||||
}
|
||||
|
||||
public object Header
|
||||
{
|
||||
get => GetValue(HeaderProperty);
|
||||
set => SetValue(HeaderProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register(
|
||||
"HeaderTemplate", typeof(DataTemplate), typeof(Card), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register(
|
||||
"HeaderTemplate", typeof(DataTemplate), typeof(Card), new PropertyMetadata(default(DataTemplate)));
|
||||
[Bindable(true), Category("Content")]
|
||||
public DataTemplate HeaderTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(HeaderTemplateProperty);
|
||||
set => SetValue(HeaderTemplateProperty, value);
|
||||
}
|
||||
|
||||
[Bindable(true), Category("Content")]
|
||||
public DataTemplate HeaderTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(HeaderTemplateProperty);
|
||||
set => SetValue(HeaderTemplateProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty HeaderTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"HeaderTemplateSelector", typeof(DataTemplateSelector), typeof(Card), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
|
||||
public static readonly DependencyProperty HeaderTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"HeaderTemplateSelector", typeof(DataTemplateSelector), typeof(Card), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
[Bindable(true), Category("Content")]
|
||||
public DataTemplateSelector HeaderTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector) GetValue(HeaderTemplateSelectorProperty);
|
||||
set => SetValue(HeaderTemplateSelectorProperty, value);
|
||||
}
|
||||
|
||||
[Bindable(true), Category("Content")]
|
||||
public DataTemplateSelector HeaderTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector) GetValue(HeaderTemplateSelectorProperty);
|
||||
set => SetValue(HeaderTemplateSelectorProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty HeaderStringFormatProperty = DependencyProperty.Register(
|
||||
"HeaderStringFormat", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
|
||||
|
||||
public static readonly DependencyProperty HeaderStringFormatProperty = DependencyProperty.Register(
|
||||
"HeaderStringFormat", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
|
||||
[Bindable(true), Category("Content")]
|
||||
public string HeaderStringFormat
|
||||
{
|
||||
get => (string) GetValue(HeaderStringFormatProperty);
|
||||
set => SetValue(HeaderStringFormatProperty, value);
|
||||
}
|
||||
|
||||
[Bindable(true), Category("Content")]
|
||||
public string HeaderStringFormat
|
||||
{
|
||||
get => (string) GetValue(HeaderStringFormatProperty);
|
||||
set => SetValue(HeaderStringFormatProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty FooterProperty = DependencyProperty.Register(
|
||||
"Footer", typeof(object), typeof(Card), new PropertyMetadata(default(object)));
|
||||
|
||||
public static readonly DependencyProperty FooterProperty = DependencyProperty.Register(
|
||||
"Footer", typeof(object), typeof(Card), new PropertyMetadata(default(object)));
|
||||
public object Footer
|
||||
{
|
||||
get => GetValue(FooterProperty);
|
||||
set => SetValue(FooterProperty, value);
|
||||
}
|
||||
|
||||
public object Footer
|
||||
{
|
||||
get => GetValue(FooterProperty);
|
||||
set => SetValue(FooterProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty FooterTemplateProperty = DependencyProperty.Register(
|
||||
"FooterTemplate", typeof(DataTemplate), typeof(Card), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public static readonly DependencyProperty FooterTemplateProperty = DependencyProperty.Register(
|
||||
"FooterTemplate", typeof(DataTemplate), typeof(Card), new PropertyMetadata(default(DataTemplate)));
|
||||
[Bindable(true), Category("Content")]
|
||||
public DataTemplate FooterTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(FooterTemplateProperty);
|
||||
set => SetValue(FooterTemplateProperty, value);
|
||||
}
|
||||
|
||||
[Bindable(true), Category("Content")]
|
||||
public DataTemplate FooterTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(FooterTemplateProperty);
|
||||
set => SetValue(FooterTemplateProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty FooterTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"FooterTemplateSelector", typeof(DataTemplateSelector), typeof(Card), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
|
||||
public static readonly DependencyProperty FooterTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"FooterTemplateSelector", typeof(DataTemplateSelector), typeof(Card), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
[Bindable(true), Category("Content")]
|
||||
public DataTemplateSelector FooterTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector) GetValue(FooterTemplateSelectorProperty);
|
||||
set => SetValue(FooterTemplateSelectorProperty, value);
|
||||
}
|
||||
|
||||
[Bindable(true), Category("Content")]
|
||||
public DataTemplateSelector FooterTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector) GetValue(FooterTemplateSelectorProperty);
|
||||
set => SetValue(FooterTemplateSelectorProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty FooterStringFormatProperty = DependencyProperty.Register(
|
||||
"FooterStringFormat", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
|
||||
|
||||
public static readonly DependencyProperty FooterStringFormatProperty = DependencyProperty.Register(
|
||||
"FooterStringFormat", typeof(string), typeof(Card), new PropertyMetadata(default(string)));
|
||||
|
||||
[Bindable(true), Category("Content")]
|
||||
public string FooterStringFormat
|
||||
{
|
||||
get => (string) GetValue(FooterStringFormatProperty);
|
||||
set => SetValue(FooterStringFormatProperty, value);
|
||||
}
|
||||
[Bindable(true), Category("Content")]
|
||||
public string FooterStringFormat
|
||||
{
|
||||
get => (string) GetValue(FooterStringFormatProperty);
|
||||
set => SetValue(FooterStringFormatProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -2,45 +2,44 @@
|
||||
using System.Windows;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ChatBubble : SelectableItem
|
||||
{
|
||||
public class ChatBubble : SelectableItem
|
||||
public static readonly DependencyProperty RoleProperty = DependencyProperty.Register(
|
||||
"Role", typeof(ChatRoleType), typeof(ChatBubble), new PropertyMetadata(default(ChatRoleType)));
|
||||
|
||||
public ChatRoleType Role
|
||||
{
|
||||
public static readonly DependencyProperty RoleProperty = DependencyProperty.Register(
|
||||
"Role", typeof(ChatRoleType), typeof(ChatBubble), new PropertyMetadata(default(ChatRoleType)));
|
||||
get => (ChatRoleType) GetValue(RoleProperty);
|
||||
set => SetValue(RoleProperty, value);
|
||||
}
|
||||
|
||||
public ChatRoleType Role
|
||||
{
|
||||
get => (ChatRoleType) GetValue(RoleProperty);
|
||||
set => SetValue(RoleProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty TypeProperty = DependencyProperty.Register(
|
||||
"Type", typeof(ChatMessageType), typeof(ChatBubble), new PropertyMetadata(default(ChatMessageType)));
|
||||
|
||||
public static readonly DependencyProperty TypeProperty = DependencyProperty.Register(
|
||||
"Type", typeof(ChatMessageType), typeof(ChatBubble), new PropertyMetadata(default(ChatMessageType)));
|
||||
public ChatMessageType Type
|
||||
{
|
||||
get => (ChatMessageType) GetValue(TypeProperty);
|
||||
set => SetValue(TypeProperty, value);
|
||||
}
|
||||
|
||||
public ChatMessageType Type
|
||||
{
|
||||
get => (ChatMessageType) GetValue(TypeProperty);
|
||||
set => SetValue(TypeProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty IsReadProperty = DependencyProperty.Register(
|
||||
"IsRead", typeof(bool), typeof(ChatBubble), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static readonly DependencyProperty IsReadProperty = DependencyProperty.Register(
|
||||
"IsRead", typeof(bool), typeof(ChatBubble), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
public bool IsRead
|
||||
{
|
||||
get => (bool) GetValue(IsReadProperty);
|
||||
set => SetValue(IsReadProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public bool IsRead
|
||||
{
|
||||
get => (bool) GetValue(IsReadProperty);
|
||||
set => SetValue(IsReadProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
public Action<object> ReadAction { get; set; }
|
||||
|
||||
public Action<object> ReadAction { get; set; }
|
||||
protected override void OnSelected(RoutedEventArgs e)
|
||||
{
|
||||
base.OnSelected(e);
|
||||
|
||||
protected override void OnSelected(RoutedEventArgs e)
|
||||
{
|
||||
base.OnSelected(e);
|
||||
|
||||
IsRead = true;
|
||||
ReadAction?.Invoke(Content);
|
||||
}
|
||||
IsRead = true;
|
||||
ReadAction?.Invoke(Content);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -3,80 +3,79 @@ using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class Divider : Control
|
||||
{
|
||||
public class Divider : Control
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
"Content", typeof(object), typeof(Divider), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Content
|
||||
{
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
"Content", typeof(object), typeof(Divider), new PropertyMetadata(default(object)));
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
public object Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(Divider), new PropertyMetadata(default(Orientation)));
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(Divider), new PropertyMetadata(default(Orientation)));
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register(
|
||||
"ContentTemplate", typeof(DataTemplate), typeof(Divider), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register(
|
||||
"ContentTemplate", typeof(DataTemplate), typeof(Divider), new PropertyMetadata(default(DataTemplate)));
|
||||
public DataTemplate ContentTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(ContentTemplateProperty);
|
||||
set => SetValue(ContentTemplateProperty, value);
|
||||
}
|
||||
|
||||
public DataTemplate ContentTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(ContentTemplateProperty);
|
||||
set => SetValue(ContentTemplateProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ContentStringFormatProperty = DependencyProperty.Register(
|
||||
"ContentStringFormat", typeof(string), typeof(Divider), new PropertyMetadata(default(string)));
|
||||
|
||||
public static readonly DependencyProperty ContentStringFormatProperty = DependencyProperty.Register(
|
||||
"ContentStringFormat", typeof(string), typeof(Divider), new PropertyMetadata(default(string)));
|
||||
public string ContentStringFormat
|
||||
{
|
||||
get => (string) GetValue(ContentStringFormatProperty);
|
||||
set => SetValue(ContentStringFormatProperty, value);
|
||||
}
|
||||
|
||||
public string ContentStringFormat
|
||||
{
|
||||
get => (string) GetValue(ContentStringFormatProperty);
|
||||
set => SetValue(ContentStringFormatProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ContentTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"ContentTemplateSelector", typeof(DataTemplateSelector), typeof(Divider), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
|
||||
public static readonly DependencyProperty ContentTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"ContentTemplateSelector", typeof(DataTemplateSelector), typeof(Divider), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
public DataTemplateSelector ContentTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector) GetValue(ContentTemplateSelectorProperty);
|
||||
set => SetValue(ContentTemplateSelectorProperty, value);
|
||||
}
|
||||
|
||||
public DataTemplateSelector ContentTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector) GetValue(ContentTemplateSelectorProperty);
|
||||
set => SetValue(ContentTemplateSelectorProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty LineStrokeProperty = DependencyProperty.Register(
|
||||
"LineStroke", typeof(Brush), typeof(Divider), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public static readonly DependencyProperty LineStrokeProperty = DependencyProperty.Register(
|
||||
"LineStroke", typeof(Brush), typeof(Divider), new PropertyMetadata(default(Brush)));
|
||||
public Brush LineStroke
|
||||
{
|
||||
get => (Brush) GetValue(LineStrokeProperty);
|
||||
set => SetValue(LineStrokeProperty, value);
|
||||
}
|
||||
|
||||
public Brush LineStroke
|
||||
{
|
||||
get => (Brush) GetValue(LineStrokeProperty);
|
||||
set => SetValue(LineStrokeProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty LineStrokeThicknessProperty = DependencyProperty.Register(
|
||||
"LineStrokeThickness", typeof(double), typeof(Divider), new PropertyMetadata(ValueBoxes.Double1Box));
|
||||
|
||||
public static readonly DependencyProperty LineStrokeThicknessProperty = DependencyProperty.Register(
|
||||
"LineStrokeThickness", typeof(double), typeof(Divider), new PropertyMetadata(ValueBoxes.Double1Box));
|
||||
public double LineStrokeThickness
|
||||
{
|
||||
get => (double) GetValue(LineStrokeThicknessProperty);
|
||||
set => SetValue(LineStrokeThicknessProperty, value);
|
||||
}
|
||||
|
||||
public double LineStrokeThickness
|
||||
{
|
||||
get => (double) GetValue(LineStrokeThicknessProperty);
|
||||
set => SetValue(LineStrokeThicknessProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty LineStrokeDashArrayProperty = DependencyProperty.Register(
|
||||
"LineStrokeDashArray", typeof(DoubleCollection), typeof(Divider), new PropertyMetadata(new DoubleCollection()));
|
||||
|
||||
public static readonly DependencyProperty LineStrokeDashArrayProperty = DependencyProperty.Register(
|
||||
"LineStrokeDashArray", typeof(DoubleCollection), typeof(Divider), new PropertyMetadata(new DoubleCollection()));
|
||||
|
||||
public DoubleCollection LineStrokeDashArray
|
||||
{
|
||||
get => (DoubleCollection) GetValue(LineStrokeDashArrayProperty);
|
||||
set => SetValue(LineStrokeDashArrayProperty, value);
|
||||
}
|
||||
public DoubleCollection LineStrokeDashArray
|
||||
{
|
||||
get => (DoubleCollection) GetValue(LineStrokeDashArrayProperty);
|
||||
set => SetValue(LineStrokeDashArrayProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -2,35 +2,34 @@
|
||||
using System.Windows.Controls;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class Empty : ContentControl
|
||||
{
|
||||
public class Empty : ContentControl
|
||||
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
|
||||
"Description", typeof(object), typeof(Empty), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Description
|
||||
{
|
||||
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
|
||||
"Description", typeof(object), typeof(Empty), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Description
|
||||
{
|
||||
get => GetValue(DescriptionProperty);
|
||||
set => SetValue(DescriptionProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LogoProperty = DependencyProperty.Register(
|
||||
"Logo", typeof(object), typeof(Empty), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Logo
|
||||
{
|
||||
get => GetValue(LogoProperty);
|
||||
set => SetValue(LogoProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowEmptyProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowEmpty", typeof(bool), typeof(Empty), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetShowEmpty(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowEmptyProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetShowEmpty(DependencyObject element)
|
||||
=> (bool) element.GetValue(ShowEmptyProperty);
|
||||
get => GetValue(DescriptionProperty);
|
||||
set => SetValue(DescriptionProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LogoProperty = DependencyProperty.Register(
|
||||
"Logo", typeof(object), typeof(Empty), new PropertyMetadata(default(object)));
|
||||
|
||||
public object Logo
|
||||
{
|
||||
get => GetValue(LogoProperty);
|
||||
set => SetValue(LogoProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ShowEmptyProperty = DependencyProperty.RegisterAttached(
|
||||
"ShowEmpty", typeof(bool), typeof(Empty), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));
|
||||
|
||||
public static void SetShowEmpty(DependencyObject element, bool value)
|
||||
=> element.SetValue(ShowEmptyProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetShowEmpty(DependencyObject element)
|
||||
=> (bool) element.GetValue(ShowEmptyProperty);
|
||||
}
|
||||
@@ -5,96 +5,95 @@ using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class GotoTop : Button
|
||||
{
|
||||
public class GotoTop : Button
|
||||
private Action _gotoTopAction;
|
||||
|
||||
private System.Windows.Controls.ScrollViewer _scrollViewer;
|
||||
|
||||
public static readonly DependencyProperty TargetProperty = DependencyProperty.Register(
|
||||
"Target", typeof(DependencyObject), typeof(GotoTop), new PropertyMetadata(default(DependencyObject)));
|
||||
|
||||
public DependencyObject Target
|
||||
{
|
||||
private Action _gotoTopAction;
|
||||
get => (DependencyObject) GetValue(TargetProperty);
|
||||
set => SetValue(TargetProperty, value);
|
||||
}
|
||||
|
||||
private System.Windows.Controls.ScrollViewer _scrollViewer;
|
||||
public GotoTop() => Loaded += (s, e) => CreateGotoAction(Target);
|
||||
|
||||
public static readonly DependencyProperty TargetProperty = DependencyProperty.Register(
|
||||
"Target", typeof(DependencyObject), typeof(GotoTop), new PropertyMetadata(default(DependencyObject)));
|
||||
|
||||
public DependencyObject Target
|
||||
public virtual void CreateGotoAction(DependencyObject obj)
|
||||
{
|
||||
if (_scrollViewer != null)
|
||||
{
|
||||
get => (DependencyObject) GetValue(TargetProperty);
|
||||
set => SetValue(TargetProperty, value);
|
||||
_scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged;
|
||||
}
|
||||
|
||||
public GotoTop() => Loaded += (s, e) => CreateGotoAction(Target);
|
||||
|
||||
public virtual void CreateGotoAction(DependencyObject obj)
|
||||
_scrollViewer = VisualHelper.GetChild<System.Windows.Controls.ScrollViewer>(obj);
|
||||
if (_scrollViewer != null)
|
||||
{
|
||||
if (_scrollViewer != null)
|
||||
_scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
|
||||
|
||||
if (_scrollViewer is ScrollViewer scrollViewerHandy && Animated && scrollViewerHandy.IsInertiaEnabled)
|
||||
{
|
||||
_scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged;
|
||||
_gotoTopAction = () => scrollViewerHandy.ScrollToTopInternal(AnimationTime);
|
||||
}
|
||||
_scrollViewer = VisualHelper.GetChild<System.Windows.Controls.ScrollViewer>(obj);
|
||||
if (_scrollViewer != null)
|
||||
else
|
||||
{
|
||||
_scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
|
||||
|
||||
if (_scrollViewer is ScrollViewer scrollViewerHandy && Animated && scrollViewerHandy.IsInertiaEnabled)
|
||||
{
|
||||
_gotoTopAction = () => scrollViewerHandy.ScrollToTopInternal(AnimationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gotoTopAction = () => _scrollViewer.ScrollToTop();
|
||||
}
|
||||
_gotoTopAction = () => _scrollViewer.ScrollToTop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
|
||||
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
|
||||
{
|
||||
if (AutoHiding)
|
||||
{
|
||||
if (AutoHiding)
|
||||
{
|
||||
this.Show(e.VerticalOffset >= HidingHeight);
|
||||
}
|
||||
this.Show(e.VerticalOffset >= HidingHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AnimatedProperty = DependencyProperty.Register(
|
||||
"Animated", typeof(bool), typeof(GotoTop), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
public static readonly DependencyProperty AnimatedProperty = DependencyProperty.Register(
|
||||
"Animated", typeof(bool), typeof(GotoTop), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool Animated
|
||||
{
|
||||
get => (bool) GetValue(AnimatedProperty);
|
||||
set => SetValue(AnimatedProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
public bool Animated
|
||||
{
|
||||
get => (bool) GetValue(AnimatedProperty);
|
||||
set => SetValue(AnimatedProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AnimationTimeProperty = DependencyProperty.Register(
|
||||
"AnimationTime", typeof(double), typeof(GotoTop), new PropertyMetadata(ValueBoxes.Double200Box));
|
||||
public static readonly DependencyProperty AnimationTimeProperty = DependencyProperty.Register(
|
||||
"AnimationTime", typeof(double), typeof(GotoTop), new PropertyMetadata(ValueBoxes.Double200Box));
|
||||
|
||||
public double AnimationTime
|
||||
{
|
||||
get => (double) GetValue(AnimationTimeProperty);
|
||||
set => SetValue(AnimationTimeProperty, value);
|
||||
}
|
||||
public double AnimationTime
|
||||
{
|
||||
get => (double) GetValue(AnimationTimeProperty);
|
||||
set => SetValue(AnimationTimeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HidingHeightProperty = DependencyProperty.Register(
|
||||
"HidingHeight", typeof(double), typeof(GotoTop), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
public static readonly DependencyProperty HidingHeightProperty = DependencyProperty.Register(
|
||||
"HidingHeight", typeof(double), typeof(GotoTop), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double HidingHeight
|
||||
{
|
||||
get => (double) GetValue(HidingHeightProperty);
|
||||
set => SetValue(HidingHeightProperty, value);
|
||||
}
|
||||
public double HidingHeight
|
||||
{
|
||||
get => (double) GetValue(HidingHeightProperty);
|
||||
set => SetValue(HidingHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AutoHidingProperty = DependencyProperty.Register(
|
||||
"AutoHiding", typeof(bool), typeof(GotoTop), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
public static readonly DependencyProperty AutoHidingProperty = DependencyProperty.Register(
|
||||
"AutoHiding", typeof(bool), typeof(GotoTop), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public bool AutoHiding
|
||||
{
|
||||
get => (bool) GetValue(AutoHidingProperty);
|
||||
set => SetValue(AutoHidingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
public bool AutoHiding
|
||||
{
|
||||
get => (bool) GetValue(AutoHidingProperty);
|
||||
set => SetValue(AutoHidingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
base.OnClick();
|
||||
protected override void OnClick()
|
||||
{
|
||||
base.OnClick();
|
||||
|
||||
_gotoTopAction?.Invoke();
|
||||
}
|
||||
_gotoTopAction?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -4,55 +4,54 @@ using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class Gravatar : ContentControl
|
||||
{
|
||||
public class Gravatar : ContentControl
|
||||
public static readonly DependencyProperty GeneratorProperty = DependencyProperty.Register(
|
||||
"Generator", typeof(IGravatarGenerator), typeof(Gravatar), new PropertyMetadata(new GithubGravatarGenerator()));
|
||||
|
||||
public IGravatarGenerator Generator
|
||||
{
|
||||
public static readonly DependencyProperty GeneratorProperty = DependencyProperty.Register(
|
||||
"Generator", typeof(IGravatarGenerator), typeof(Gravatar), new PropertyMetadata(new GithubGravatarGenerator()));
|
||||
get => (IGravatarGenerator) GetValue(GeneratorProperty);
|
||||
set => SetValue(GeneratorProperty, value);
|
||||
}
|
||||
|
||||
public IGravatarGenerator Generator
|
||||
{
|
||||
get => (IGravatarGenerator) GetValue(GeneratorProperty);
|
||||
set => SetValue(GeneratorProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty IdProperty = DependencyProperty.Register(
|
||||
"Id", typeof(string), typeof(Gravatar), new PropertyMetadata(default(string), OnIdChanged));
|
||||
|
||||
public static readonly DependencyProperty IdProperty = DependencyProperty.Register(
|
||||
"Id", typeof(string), typeof(Gravatar), new PropertyMetadata(default(string), OnIdChanged));
|
||||
private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Gravatar) d;
|
||||
if (ctl.Source != null) return;
|
||||
ctl.Content = ctl.Generator.GetGravatar((string) e.NewValue);
|
||||
}
|
||||
|
||||
private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Gravatar) d;
|
||||
if (ctl.Source != null) return;
|
||||
ctl.Content = ctl.Generator.GetGravatar((string) e.NewValue);
|
||||
}
|
||||
public string Id
|
||||
{
|
||||
get => (string) GetValue(IdProperty);
|
||||
set => SetValue(IdProperty, value);
|
||||
}
|
||||
|
||||
public string Id
|
||||
{
|
||||
get => (string) GetValue(IdProperty);
|
||||
set => SetValue(IdProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
|
||||
"Source", typeof(ImageSource), typeof(Gravatar), new PropertyMetadata(default(ImageSource), OnSourceChanged));
|
||||
|
||||
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
|
||||
"Source", typeof(ImageSource), typeof(Gravatar), new PropertyMetadata(default(ImageSource), OnSourceChanged));
|
||||
private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Gravatar) d;
|
||||
var v = (ImageSource) e.NewValue;
|
||||
|
||||
private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (Gravatar) d;
|
||||
var v = (ImageSource) e.NewValue;
|
||||
ctl.Background = v != null
|
||||
? new ImageBrush(v)
|
||||
{
|
||||
Stretch = Stretch.UniformToFill
|
||||
}
|
||||
: ResourceHelper.GetResourceInternal<Brush>(ResourceToken.SecondaryRegionBrush);
|
||||
}
|
||||
|
||||
ctl.Background = v != null
|
||||
? new ImageBrush(v)
|
||||
{
|
||||
Stretch = Stretch.UniformToFill
|
||||
}
|
||||
: ResourceHelper.GetResourceInternal<Brush>(ResourceToken.SecondaryRegionBrush);
|
||||
}
|
||||
|
||||
public ImageSource Source
|
||||
{
|
||||
get => (ImageSource) GetValue(SourceProperty);
|
||||
set => SetValue(SourceProperty, value);
|
||||
}
|
||||
public ImageSource Source
|
||||
{
|
||||
get => (ImageSource) GetValue(SourceProperty);
|
||||
set => SetValue(SourceProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -7,154 +7,153 @@ using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementVisualBrush, Type = typeof(VisualBrush))]
|
||||
public class Magnifier : AdornerElement
|
||||
{
|
||||
[TemplatePart(Name = ElementVisualBrush, Type = typeof(VisualBrush))]
|
||||
public class Magnifier : AdornerElement
|
||||
private AdornerContainer _adornerContainer;
|
||||
|
||||
private Size _viewboxSize;
|
||||
|
||||
private const string ElementVisualBrush = "PART_VisualBrush";
|
||||
|
||||
private VisualBrush _visualBrush = new();
|
||||
|
||||
private readonly TranslateTransform _translateTransform;
|
||||
|
||||
public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register(
|
||||
"HorizontalOffset", typeof(double), typeof(Magnifier), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double HorizontalOffset
|
||||
{
|
||||
private AdornerContainer _adornerContainer;
|
||||
get => (double) GetValue(HorizontalOffsetProperty);
|
||||
set => SetValue(HorizontalOffsetProperty, value);
|
||||
}
|
||||
|
||||
private Size _viewboxSize;
|
||||
public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.Register(
|
||||
"VerticalOffset", typeof(double), typeof(Magnifier), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
private const string ElementVisualBrush = "PART_VisualBrush";
|
||||
public double VerticalOffset
|
||||
{
|
||||
get => (double) GetValue(VerticalOffsetProperty);
|
||||
set => SetValue(VerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
private VisualBrush _visualBrush = new();
|
||||
public static Magnifier Default => new();
|
||||
|
||||
private readonly TranslateTransform _translateTransform;
|
||||
public static readonly DependencyProperty ScaleProperty = DependencyProperty.Register(
|
||||
"Scale", typeof(double), typeof(Magnifier), new PropertyMetadata(5.0, OnScaleChanged), ValidateHelper.IsInRangeOfPosDouble);
|
||||
|
||||
public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register(
|
||||
"HorizontalOffset", typeof(double), typeof(Magnifier), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
private static void OnScaleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((Magnifier) d).UpdateViewboxSize();
|
||||
|
||||
public double HorizontalOffset
|
||||
public double Scale
|
||||
{
|
||||
get => (double) GetValue(ScaleProperty);
|
||||
set => SetValue(ScaleProperty, value);
|
||||
}
|
||||
|
||||
public Magnifier()
|
||||
{
|
||||
_translateTransform = new TranslateTransform();
|
||||
RenderTransform = _translateTransform;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var visualBrush = GetTemplateChild(ElementVisualBrush) as VisualBrush ?? new VisualBrush();
|
||||
visualBrush.Viewbox = _visualBrush.Viewbox;
|
||||
_visualBrush = visualBrush;
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
UpdateViewboxSize();
|
||||
}
|
||||
|
||||
private void UpdateViewboxSize() => _viewboxSize = new Size(ActualWidth / Scale, ActualHeight / Scale);
|
||||
|
||||
protected sealed override void OnTargetChanged(FrameworkElement element, bool isNew)
|
||||
{
|
||||
base.OnTargetChanged(element, isNew);
|
||||
|
||||
if (element == null) return;
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
get => (double) GetValue(HorizontalOffsetProperty);
|
||||
set => SetValue(HorizontalOffsetProperty, value);
|
||||
element.MouseEnter -= Element_MouseEnter;
|
||||
element.MouseLeave -= Element_MouseLeave;
|
||||
element.MouseMove -= Element_MouseMove;
|
||||
ElementTarget = null;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.Register(
|
||||
"VerticalOffset", typeof(double), typeof(Magnifier), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public double VerticalOffset
|
||||
else
|
||||
{
|
||||
get => (double) GetValue(VerticalOffsetProperty);
|
||||
set => SetValue(VerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
public static Magnifier Default => new();
|
||||
|
||||
public static readonly DependencyProperty ScaleProperty = DependencyProperty.Register(
|
||||
"Scale", typeof(double), typeof(Magnifier), new PropertyMetadata(5.0, OnScaleChanged), ValidateHelper.IsInRangeOfPosDouble);
|
||||
|
||||
private static void OnScaleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => ((Magnifier) d).UpdateViewboxSize();
|
||||
|
||||
public double Scale
|
||||
{
|
||||
get => (double) GetValue(ScaleProperty);
|
||||
set => SetValue(ScaleProperty, value);
|
||||
}
|
||||
|
||||
public Magnifier()
|
||||
{
|
||||
_translateTransform = new TranslateTransform();
|
||||
RenderTransform = _translateTransform;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var visualBrush = GetTemplateChild(ElementVisualBrush) as VisualBrush ?? new VisualBrush();
|
||||
visualBrush.Viewbox = _visualBrush.Viewbox;
|
||||
_visualBrush = visualBrush;
|
||||
}
|
||||
|
||||
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
|
||||
{
|
||||
base.OnRenderSizeChanged(sizeInfo);
|
||||
UpdateViewboxSize();
|
||||
}
|
||||
|
||||
private void UpdateViewboxSize() => _viewboxSize = new Size(ActualWidth / Scale, ActualHeight / Scale);
|
||||
|
||||
protected sealed override void OnTargetChanged(FrameworkElement element, bool isNew)
|
||||
{
|
||||
base.OnTargetChanged(element, isNew);
|
||||
|
||||
if (element == null) return;
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
element.MouseEnter -= Element_MouseEnter;
|
||||
element.MouseLeave -= Element_MouseLeave;
|
||||
element.MouseMove -= Element_MouseMove;
|
||||
ElementTarget = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
element.MouseEnter += Element_MouseEnter;
|
||||
element.MouseLeave += Element_MouseLeave;
|
||||
element.MouseMove += Element_MouseMove;
|
||||
ElementTarget = element;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose() => HideAdornerElement();
|
||||
|
||||
private void UpdateLocation()
|
||||
{
|
||||
var targetPoint = Mouse.GetPosition(Target);
|
||||
var subX = targetPoint.X - _visualBrush.Viewbox.Width / 2;
|
||||
var subY = targetPoint.Y - _visualBrush.Viewbox.Height / 2;
|
||||
|
||||
var targetVector = VisualTreeHelper.GetOffset(Target);
|
||||
_visualBrush.Viewbox = new Rect(new Point(subX + targetVector.X, subY + targetVector.Y), _viewboxSize);
|
||||
|
||||
var adornerPoint = Mouse.GetPosition(_adornerContainer);
|
||||
_translateTransform.X = adornerPoint.X + HorizontalOffset;
|
||||
_translateTransform.Y = adornerPoint.Y + VerticalOffset;
|
||||
}
|
||||
|
||||
private void Element_MouseMove(object sender, MouseEventArgs e) => UpdateLocation();
|
||||
|
||||
private void Element_MouseLeave(object sender, MouseEventArgs e) => HideAdornerElement();
|
||||
|
||||
private void Element_MouseEnter(object sender, MouseEventArgs e) => ShowAdornerElement();
|
||||
|
||||
private void HideAdornerElement()
|
||||
{
|
||||
if (_adornerContainer == null) return;
|
||||
var layer = AdornerLayer.GetAdornerLayer(Target);
|
||||
|
||||
if (layer != null)
|
||||
{
|
||||
layer.Remove(_adornerContainer);
|
||||
}
|
||||
else if (_adornerContainer is { Parent: AdornerLayer parent })
|
||||
{
|
||||
parent.Remove(_adornerContainer);
|
||||
}
|
||||
|
||||
if (_adornerContainer != null)
|
||||
{
|
||||
_adornerContainer.Child = null;
|
||||
_adornerContainer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowAdornerElement()
|
||||
{
|
||||
if (_adornerContainer == null)
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(Target);
|
||||
if (layer == null) return;
|
||||
|
||||
_adornerContainer = new AdornerContainer(layer)
|
||||
{
|
||||
Child = this
|
||||
};
|
||||
layer.Add(_adornerContainer);
|
||||
}
|
||||
this.Show();
|
||||
element.MouseEnter += Element_MouseEnter;
|
||||
element.MouseLeave += Element_MouseLeave;
|
||||
element.MouseMove += Element_MouseMove;
|
||||
ElementTarget = element;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose() => HideAdornerElement();
|
||||
|
||||
private void UpdateLocation()
|
||||
{
|
||||
var targetPoint = Mouse.GetPosition(Target);
|
||||
var subX = targetPoint.X - _visualBrush.Viewbox.Width / 2;
|
||||
var subY = targetPoint.Y - _visualBrush.Viewbox.Height / 2;
|
||||
|
||||
var targetVector = VisualTreeHelper.GetOffset(Target);
|
||||
_visualBrush.Viewbox = new Rect(new Point(subX + targetVector.X, subY + targetVector.Y), _viewboxSize);
|
||||
|
||||
var adornerPoint = Mouse.GetPosition(_adornerContainer);
|
||||
_translateTransform.X = adornerPoint.X + HorizontalOffset;
|
||||
_translateTransform.Y = adornerPoint.Y + VerticalOffset;
|
||||
}
|
||||
|
||||
private void Element_MouseMove(object sender, MouseEventArgs e) => UpdateLocation();
|
||||
|
||||
private void Element_MouseLeave(object sender, MouseEventArgs e) => HideAdornerElement();
|
||||
|
||||
private void Element_MouseEnter(object sender, MouseEventArgs e) => ShowAdornerElement();
|
||||
|
||||
private void HideAdornerElement()
|
||||
{
|
||||
if (_adornerContainer == null) return;
|
||||
var layer = AdornerLayer.GetAdornerLayer(Target);
|
||||
|
||||
if (layer != null)
|
||||
{
|
||||
layer.Remove(_adornerContainer);
|
||||
}
|
||||
else if (_adornerContainer is { Parent: AdornerLayer parent })
|
||||
{
|
||||
parent.Remove(_adornerContainer);
|
||||
}
|
||||
|
||||
if (_adornerContainer != null)
|
||||
{
|
||||
_adornerContainer.Child = null;
|
||||
_adornerContainer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowAdornerElement()
|
||||
{
|
||||
if (_adornerContainer == null)
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(Target);
|
||||
if (layer == null) return;
|
||||
|
||||
_adornerContainer = new AdornerContainer(layer)
|
||||
{
|
||||
Child = this
|
||||
};
|
||||
layer.Add(_adornerContainer);
|
||||
}
|
||||
this.Show();
|
||||
}
|
||||
}
|
||||
@@ -5,150 +5,149 @@ using System.Windows.Threading;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public sealed class Notification : System.Windows.Window
|
||||
{
|
||||
public sealed class Notification : System.Windows.Window
|
||||
private const int WaitTime = 6;
|
||||
|
||||
/// <summary>
|
||||
/// 计数
|
||||
/// </summary>
|
||||
private int _tickCount;
|
||||
|
||||
/// <summary>
|
||||
/// 关闭计时器
|
||||
/// </summary>
|
||||
private DispatcherTimer _timerClose;
|
||||
|
||||
private ShowAnimation ShowAnimation { get; set; }
|
||||
|
||||
private bool _shouldBeClosed;
|
||||
|
||||
public Notification()
|
||||
{
|
||||
private const int WaitTime = 6;
|
||||
WindowStyle = WindowStyle.None;
|
||||
AllowsTransparency = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计数
|
||||
/// </summary>
|
||||
private int _tickCount;
|
||||
|
||||
/// <summary>
|
||||
/// 关闭计时器
|
||||
/// </summary>
|
||||
private DispatcherTimer _timerClose;
|
||||
|
||||
private ShowAnimation ShowAnimation { get; set; }
|
||||
|
||||
private bool _shouldBeClosed;
|
||||
|
||||
public Notification()
|
||||
public static Notification Show(object content, ShowAnimation showAnimation = ShowAnimation.None, bool staysOpen = false)
|
||||
{
|
||||
var notification = new Notification
|
||||
{
|
||||
WindowStyle = WindowStyle.None;
|
||||
AllowsTransparency = true;
|
||||
Content = content,
|
||||
Opacity = 0,
|
||||
ShowAnimation = showAnimation
|
||||
};
|
||||
|
||||
notification.Show();
|
||||
|
||||
var desktopWorkingArea = SystemParameters.WorkArea;
|
||||
var leftMax = desktopWorkingArea.Width - notification.ActualWidth;
|
||||
var topMax = desktopWorkingArea.Height - notification.ActualHeight;
|
||||
|
||||
switch (showAnimation)
|
||||
{
|
||||
case ShowAnimation.None:
|
||||
notification.Opacity = 1;
|
||||
notification.Left = leftMax;
|
||||
notification.Top = topMax;
|
||||
break;
|
||||
case ShowAnimation.HorizontalMove:
|
||||
notification.Opacity = 1;
|
||||
notification.Left = desktopWorkingArea.Width;
|
||||
notification.Top = topMax;
|
||||
notification.BeginAnimation(LeftProperty, AnimationHelper.CreateAnimation(leftMax));
|
||||
break;
|
||||
case ShowAnimation.VerticalMove:
|
||||
notification.Opacity = 1;
|
||||
notification.Left = leftMax;
|
||||
notification.Top = desktopWorkingArea.Height;
|
||||
notification.BeginAnimation(TopProperty, AnimationHelper.CreateAnimation(topMax));
|
||||
break;
|
||||
case ShowAnimation.Fade:
|
||||
notification.Left = leftMax;
|
||||
notification.Top = topMax;
|
||||
notification.BeginAnimation(OpacityProperty, AnimationHelper.CreateAnimation(1));
|
||||
break;
|
||||
default:
|
||||
notification.Opacity = 1;
|
||||
notification.Left = leftMax;
|
||||
notification.Top = topMax;
|
||||
break;
|
||||
}
|
||||
|
||||
public static Notification Show(object content, ShowAnimation showAnimation = ShowAnimation.None, bool staysOpen = false)
|
||||
if (!staysOpen) notification.StartTimer();
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
base.OnClosing(e);
|
||||
|
||||
if (_shouldBeClosed)
|
||||
{
|
||||
var notification = new Notification
|
||||
{
|
||||
Content = content,
|
||||
Opacity = 0,
|
||||
ShowAnimation = showAnimation
|
||||
};
|
||||
|
||||
notification.Show();
|
||||
|
||||
var desktopWorkingArea = SystemParameters.WorkArea;
|
||||
var leftMax = desktopWorkingArea.Width - notification.ActualWidth;
|
||||
var topMax = desktopWorkingArea.Height - notification.ActualHeight;
|
||||
|
||||
switch (showAnimation)
|
||||
{
|
||||
case ShowAnimation.None:
|
||||
notification.Opacity = 1;
|
||||
notification.Left = leftMax;
|
||||
notification.Top = topMax;
|
||||
break;
|
||||
case ShowAnimation.HorizontalMove:
|
||||
notification.Opacity = 1;
|
||||
notification.Left = desktopWorkingArea.Width;
|
||||
notification.Top = topMax;
|
||||
notification.BeginAnimation(LeftProperty, AnimationHelper.CreateAnimation(leftMax));
|
||||
break;
|
||||
case ShowAnimation.VerticalMove:
|
||||
notification.Opacity = 1;
|
||||
notification.Left = leftMax;
|
||||
notification.Top = desktopWorkingArea.Height;
|
||||
notification.BeginAnimation(TopProperty, AnimationHelper.CreateAnimation(topMax));
|
||||
break;
|
||||
case ShowAnimation.Fade:
|
||||
notification.Left = leftMax;
|
||||
notification.Top = topMax;
|
||||
notification.BeginAnimation(OpacityProperty, AnimationHelper.CreateAnimation(1));
|
||||
break;
|
||||
default:
|
||||
notification.Opacity = 1;
|
||||
notification.Left = leftMax;
|
||||
notification.Top = topMax;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!staysOpen) notification.StartTimer();
|
||||
|
||||
return notification;
|
||||
return;
|
||||
}
|
||||
var desktopWorkingArea = SystemParameters.WorkArea;
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
switch (ShowAnimation)
|
||||
{
|
||||
base.OnClosing(e);
|
||||
|
||||
if (_shouldBeClosed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var desktopWorkingArea = SystemParameters.WorkArea;
|
||||
|
||||
switch (ShowAnimation)
|
||||
{
|
||||
case ShowAnimation.None:
|
||||
break;
|
||||
case ShowAnimation.HorizontalMove:
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(desktopWorkingArea.Width);
|
||||
animation.Completed += Animation_Completed;
|
||||
BeginAnimation(LeftProperty, animation);
|
||||
e.Cancel = true;
|
||||
_shouldBeClosed = true;
|
||||
}
|
||||
break;
|
||||
case ShowAnimation.VerticalMove:
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(desktopWorkingArea.Height);
|
||||
animation.Completed += Animation_Completed;
|
||||
BeginAnimation(TopProperty, animation);
|
||||
e.Cancel = true;
|
||||
_shouldBeClosed = true;
|
||||
}
|
||||
break;
|
||||
case ShowAnimation.Fade:
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(0);
|
||||
animation.Completed += Animation_Completed;
|
||||
BeginAnimation(OpacityProperty, animation);
|
||||
e.Cancel = true;
|
||||
_shouldBeClosed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Animation_Completed(object sender, EventArgs e) => Close();
|
||||
|
||||
/// <summary>
|
||||
/// 开始计时器
|
||||
/// </summary>
|
||||
private void StartTimer()
|
||||
{
|
||||
_timerClose = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(1)
|
||||
};
|
||||
_timerClose.Tick += delegate
|
||||
{
|
||||
if (IsMouseOver)
|
||||
case ShowAnimation.None:
|
||||
break;
|
||||
case ShowAnimation.HorizontalMove:
|
||||
{
|
||||
_tickCount = 0;
|
||||
return;
|
||||
var animation = AnimationHelper.CreateAnimation(desktopWorkingArea.Width);
|
||||
animation.Completed += Animation_Completed;
|
||||
BeginAnimation(LeftProperty, animation);
|
||||
e.Cancel = true;
|
||||
_shouldBeClosed = true;
|
||||
}
|
||||
|
||||
_tickCount++;
|
||||
if (_tickCount >= WaitTime) Close();
|
||||
};
|
||||
_timerClose.Start();
|
||||
break;
|
||||
case ShowAnimation.VerticalMove:
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(desktopWorkingArea.Height);
|
||||
animation.Completed += Animation_Completed;
|
||||
BeginAnimation(TopProperty, animation);
|
||||
e.Cancel = true;
|
||||
_shouldBeClosed = true;
|
||||
}
|
||||
break;
|
||||
case ShowAnimation.Fade:
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(0);
|
||||
animation.Completed += Animation_Completed;
|
||||
BeginAnimation(OpacityProperty, animation);
|
||||
e.Cancel = true;
|
||||
_shouldBeClosed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Animation_Completed(object sender, EventArgs e) => Close();
|
||||
|
||||
/// <summary>
|
||||
/// 开始计时器
|
||||
/// </summary>
|
||||
private void StartTimer()
|
||||
{
|
||||
_timerClose = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(1)
|
||||
};
|
||||
_timerClose.Tick += delegate
|
||||
{
|
||||
if (IsMouseOver)
|
||||
{
|
||||
_tickCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_tickCount++;
|
||||
if (_tickCount >= WaitTime) Close();
|
||||
};
|
||||
_timerClose.Start();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -7,396 +7,395 @@ using HandyControl.Interactivity;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Extension;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ElementButtonLeft, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ElementButtonRight, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ElementButtonFirst, Type = typeof(RadioButton))]
|
||||
[TemplatePart(Name = ElementMoreLeft, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = ElementPanelMain, Type = typeof(Panel))]
|
||||
[TemplatePart(Name = ElementMoreRight, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = ElementButtonLast, Type = typeof(RadioButton))]
|
||||
[TemplatePart(Name = ElementButtonLast, Type = typeof(NumericUpDown))]
|
||||
public class Pagination : Control
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string ElementButtonLeft = "PART_ButtonLeft";
|
||||
private const string ElementButtonRight = "PART_ButtonRight";
|
||||
private const string ElementButtonFirst = "PART_ButtonFirst";
|
||||
private const string ElementMoreLeft = "PART_MoreLeft";
|
||||
private const string ElementPanelMain = "PART_PanelMain";
|
||||
private const string ElementMoreRight = "PART_MoreRight";
|
||||
private const string ElementButtonLast = "PART_ButtonLast";
|
||||
private const string ElementJump = "PART_Jump";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Data
|
||||
|
||||
private Button _buttonLeft;
|
||||
private Button _buttonRight;
|
||||
private RadioButton _buttonFirst;
|
||||
private FrameworkElement _moreLeft;
|
||||
private Panel _panelMain;
|
||||
private FrameworkElement _moreRight;
|
||||
private RadioButton _buttonLast;
|
||||
private NumericUpDown _jumpNumericUpDown;
|
||||
|
||||
private bool _appliedTemplate;
|
||||
|
||||
#endregion Data
|
||||
|
||||
#region Public Events
|
||||
|
||||
/// <summary>
|
||||
/// 页码
|
||||
/// 页面更新事件
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ElementButtonLeft, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ElementButtonRight, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ElementButtonFirst, Type = typeof(RadioButton))]
|
||||
[TemplatePart(Name = ElementMoreLeft, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = ElementPanelMain, Type = typeof(Panel))]
|
||||
[TemplatePart(Name = ElementMoreRight, Type = typeof(FrameworkElement))]
|
||||
[TemplatePart(Name = ElementButtonLast, Type = typeof(RadioButton))]
|
||||
[TemplatePart(Name = ElementButtonLast, Type = typeof(NumericUpDown))]
|
||||
public class Pagination : Control
|
||||
public static readonly RoutedEvent PageUpdatedEvent =
|
||||
EventManager.RegisterRoutedEvent("PageUpdated", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<int>>), typeof(Pagination));
|
||||
|
||||
/// <summary>
|
||||
/// 页面更新事件
|
||||
/// </summary>
|
||||
public event EventHandler<FunctionEventArgs<int>> PageUpdated
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string ElementButtonLeft = "PART_ButtonLeft";
|
||||
private const string ElementButtonRight = "PART_ButtonRight";
|
||||
private const string ElementButtonFirst = "PART_ButtonFirst";
|
||||
private const string ElementMoreLeft = "PART_MoreLeft";
|
||||
private const string ElementPanelMain = "PART_PanelMain";
|
||||
private const string ElementMoreRight = "PART_MoreRight";
|
||||
private const string ElementButtonLast = "PART_ButtonLast";
|
||||
private const string ElementJump = "PART_Jump";
|
||||
|
||||
#endregion Constants
|
||||
|
||||
#region Data
|
||||
|
||||
private Button _buttonLeft;
|
||||
private Button _buttonRight;
|
||||
private RadioButton _buttonFirst;
|
||||
private FrameworkElement _moreLeft;
|
||||
private Panel _panelMain;
|
||||
private FrameworkElement _moreRight;
|
||||
private RadioButton _buttonLast;
|
||||
private NumericUpDown _jumpNumericUpDown;
|
||||
|
||||
private bool _appliedTemplate;
|
||||
|
||||
#endregion Data
|
||||
|
||||
#region Public Events
|
||||
|
||||
/// <summary>
|
||||
/// 页面更新事件
|
||||
/// </summary>
|
||||
public static readonly RoutedEvent PageUpdatedEvent =
|
||||
EventManager.RegisterRoutedEvent("PageUpdated", RoutingStrategy.Bubble,
|
||||
typeof(EventHandler<FunctionEventArgs<int>>), typeof(Pagination));
|
||||
|
||||
/// <summary>
|
||||
/// 页面更新事件
|
||||
/// </summary>
|
||||
public event EventHandler<FunctionEventArgs<int>> PageUpdated
|
||||
{
|
||||
add => AddHandler(PageUpdatedEvent, value);
|
||||
remove => RemoveHandler(PageUpdatedEvent, value);
|
||||
}
|
||||
|
||||
#endregion Public Events
|
||||
|
||||
public Pagination()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Prev, ButtonPrev_OnClick));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Next, ButtonNext_OnClick));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Selected, ToggleButton_OnChecked));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Jump, (s, e) => PageIndex = (int) _jumpNumericUpDown.Value));
|
||||
|
||||
OnAutoHidingChanged(AutoHiding);
|
||||
Update();
|
||||
}
|
||||
|
||||
#region Public Properties
|
||||
|
||||
#region MaxPageCount
|
||||
|
||||
/// <summary>
|
||||
/// 最大页数
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxPageCountProperty = DependencyProperty.Register(
|
||||
"MaxPageCount", typeof(int), typeof(Pagination), new PropertyMetadata(ValueBoxes.Int1Box, OnMaxPageCountChanged, CoerceMaxPageCount), ValidateHelper.IsInRangeOfPosIntIncludeZero);
|
||||
|
||||
private static object CoerceMaxPageCount(DependencyObject d, object basevalue)
|
||||
{
|
||||
var intValue = (int) basevalue;
|
||||
return intValue < 1 ? 1 : intValue;
|
||||
}
|
||||
|
||||
private static void OnMaxPageCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination)
|
||||
{
|
||||
if (pagination.PageIndex > pagination.MaxPageCount)
|
||||
{
|
||||
pagination.PageIndex = pagination.MaxPageCount;
|
||||
}
|
||||
|
||||
pagination.CoerceValue(PageIndexProperty);
|
||||
pagination.OnAutoHidingChanged(pagination.AutoHiding);
|
||||
pagination.Update();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大页数
|
||||
/// </summary>
|
||||
public int MaxPageCount
|
||||
{
|
||||
get => (int) GetValue(MaxPageCountProperty);
|
||||
set => SetValue(MaxPageCountProperty, value);
|
||||
}
|
||||
|
||||
#endregion MaxPageCount
|
||||
|
||||
#region DataCountPerPage
|
||||
|
||||
/// <summary>
|
||||
/// 每页的数据量
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DataCountPerPageProperty = DependencyProperty.Register(
|
||||
"DataCountPerPage", typeof(int), typeof(Pagination), new PropertyMetadata(20, OnDataCountPerPageChanged),
|
||||
ValidateHelper.IsInRangeOfPosInt);
|
||||
|
||||
private static void OnDataCountPerPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination)
|
||||
{
|
||||
pagination.Update();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每页的数据量
|
||||
/// </summary>
|
||||
public int DataCountPerPage
|
||||
{
|
||||
get => (int) GetValue(DataCountPerPageProperty);
|
||||
set => SetValue(DataCountPerPageProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PageIndex
|
||||
|
||||
/// <summary>
|
||||
/// 当前页
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PageIndexProperty = DependencyProperty.Register(
|
||||
"PageIndex", typeof(int), typeof(Pagination), new PropertyMetadata(ValueBoxes.Int1Box, OnPageIndexChanged, CoercePageIndex), ValidateHelper.IsInRangeOfPosIntIncludeZero);
|
||||
|
||||
private static object CoercePageIndex(DependencyObject d, object basevalue)
|
||||
{
|
||||
if (d is not Pagination pagination) return 1;
|
||||
|
||||
var intValue = (int) basevalue;
|
||||
return intValue < 1
|
||||
? 1
|
||||
: intValue > pagination.MaxPageCount
|
||||
? pagination.MaxPageCount
|
||||
: intValue;
|
||||
}
|
||||
|
||||
private static void OnPageIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination && e.NewValue is int value)
|
||||
{
|
||||
pagination.Update();
|
||||
pagination.RaiseEvent(new FunctionEventArgs<int>(PageUpdatedEvent, pagination)
|
||||
{
|
||||
Info = value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前页
|
||||
/// </summary>
|
||||
public int PageIndex
|
||||
{
|
||||
get => (int) GetValue(PageIndexProperty);
|
||||
set => SetValue(PageIndexProperty, value);
|
||||
}
|
||||
|
||||
#endregion PageIndex
|
||||
|
||||
#region MaxPageInterval
|
||||
|
||||
/// <summary>
|
||||
/// 表示当前选中的按钮距离左右两个方向按钮的最大间隔(4表示间隔4个按钮,如果超过则用省略号表示)
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxPageIntervalProperty = DependencyProperty.Register(
|
||||
"MaxPageInterval", typeof(int), typeof(Pagination), new PropertyMetadata(3, OnMaxPageIntervalChanged), ValidateHelper.IsInRangeOfPosIntIncludeZero);
|
||||
|
||||
private static void OnMaxPageIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination)
|
||||
{
|
||||
pagination.Update();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示当前选中的按钮距离左右两个方向按钮的最大间隔(4表示间隔4个按钮,如果超过则用省略号表示)
|
||||
/// </summary>
|
||||
public int MaxPageInterval
|
||||
{
|
||||
get => (int) GetValue(MaxPageIntervalProperty);
|
||||
set => SetValue(MaxPageIntervalProperty, value);
|
||||
}
|
||||
|
||||
#endregion MaxPageInterval
|
||||
|
||||
#region IsJumpEnabled
|
||||
|
||||
public static readonly DependencyProperty IsJumpEnabledProperty = DependencyProperty.Register(
|
||||
"IsJumpEnabled", typeof(bool), typeof(Pagination), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsJumpEnabled
|
||||
{
|
||||
get => (bool) GetValue(IsJumpEnabledProperty);
|
||||
set => SetValue(IsJumpEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region AutoHiding
|
||||
|
||||
public static readonly DependencyProperty AutoHidingProperty = DependencyProperty.Register(
|
||||
"AutoHiding", typeof(bool), typeof(Pagination), new PropertyMetadata(ValueBoxes.TrueBox, OnAutoHidingChanged));
|
||||
|
||||
private static void OnAutoHidingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination)
|
||||
{
|
||||
pagination.OnAutoHidingChanged((bool) e.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAutoHidingChanged(bool newValue) => this.Show(!newValue || MaxPageCount > 1);
|
||||
|
||||
public bool AutoHiding
|
||||
{
|
||||
get => (bool) GetValue(AutoHidingProperty);
|
||||
set => SetValue(AutoHidingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
_appliedTemplate = false;
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_buttonLeft = GetTemplateChild(ElementButtonLeft) as Button;
|
||||
_buttonRight = GetTemplateChild(ElementButtonRight) as Button;
|
||||
_buttonFirst = GetTemplateChild(ElementButtonFirst) as RadioButton;
|
||||
_moreLeft = GetTemplateChild(ElementMoreLeft) as FrameworkElement;
|
||||
_panelMain = GetTemplateChild(ElementPanelMain) as Panel;
|
||||
_moreRight = GetTemplateChild(ElementMoreRight) as FrameworkElement;
|
||||
_buttonLast = GetTemplateChild(ElementButtonLast) as RadioButton;
|
||||
_jumpNumericUpDown = GetTemplateChild(ElementJump) as NumericUpDown;
|
||||
|
||||
CheckNull();
|
||||
|
||||
_appliedTemplate = true;
|
||||
Update();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void CheckNull()
|
||||
{
|
||||
if (_buttonLeft == null || _buttonRight == null || _buttonFirst == null ||
|
||||
_moreLeft == null || _panelMain == null || _moreRight == null ||
|
||||
_buttonLast == null) throw new Exception();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (!_appliedTemplate) return;
|
||||
_buttonLeft.IsEnabled = PageIndex > 1;
|
||||
_buttonRight.IsEnabled = PageIndex < MaxPageCount;
|
||||
if (MaxPageInterval == 0)
|
||||
{
|
||||
_buttonFirst.Collapse();
|
||||
_buttonLast.Collapse();
|
||||
_moreLeft.Collapse();
|
||||
_moreRight.Collapse();
|
||||
_panelMain.Children.Clear();
|
||||
var selectButton = CreateButton(PageIndex);
|
||||
_panelMain.Children.Add(selectButton);
|
||||
selectButton.IsChecked = true;
|
||||
return;
|
||||
}
|
||||
_buttonFirst.Show();
|
||||
_buttonLast.Show();
|
||||
_moreLeft.Show();
|
||||
_moreRight.Show();
|
||||
|
||||
//更新最后一页
|
||||
if (MaxPageCount == 1)
|
||||
{
|
||||
_buttonLast.Collapse();
|
||||
}
|
||||
else
|
||||
{
|
||||
_buttonLast.Show();
|
||||
_buttonLast.Content = MaxPageCount.ToString();
|
||||
}
|
||||
|
||||
//更新省略号
|
||||
var right = MaxPageCount - PageIndex;
|
||||
var left = PageIndex - 1;
|
||||
_moreRight.Show(right > MaxPageInterval);
|
||||
_moreLeft.Show(left > MaxPageInterval);
|
||||
|
||||
//更新中间部分
|
||||
_panelMain.Children.Clear();
|
||||
if (PageIndex > 1 && PageIndex < MaxPageCount)
|
||||
{
|
||||
var selectButton = CreateButton(PageIndex);
|
||||
_panelMain.Children.Add(selectButton);
|
||||
selectButton.IsChecked = true;
|
||||
}
|
||||
else if (PageIndex == 1)
|
||||
{
|
||||
_buttonFirst.IsChecked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_buttonLast.IsChecked = true;
|
||||
}
|
||||
|
||||
var sub = PageIndex;
|
||||
for (var i = 0; i < MaxPageInterval - 1; i++)
|
||||
{
|
||||
if (--sub > 1)
|
||||
{
|
||||
_panelMain.Children.Insert(0, CreateButton(sub));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
var add = PageIndex;
|
||||
for (var i = 0; i < MaxPageInterval - 1; i++)
|
||||
{
|
||||
if (++add < MaxPageCount)
|
||||
{
|
||||
_panelMain.Children.Add(CreateButton(add));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ButtonPrev_OnClick(object sender, RoutedEventArgs e) => PageIndex--;
|
||||
|
||||
private void ButtonNext_OnClick(object sender, RoutedEventArgs e) => PageIndex++;
|
||||
|
||||
private RadioButton CreateButton(int page)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Style = ResourceHelper.GetResourceInternal<Style>(ResourceToken.PaginationButtonStyle),
|
||||
Content = page.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
private void ToggleButton_OnChecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is not RadioButton button) return;
|
||||
if (button.IsChecked == false) return;
|
||||
PageIndex = int.Parse(button.Content.ToString());
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
add => AddHandler(PageUpdatedEvent, value);
|
||||
remove => RemoveHandler(PageUpdatedEvent, value);
|
||||
}
|
||||
|
||||
#endregion Public Events
|
||||
|
||||
public Pagination()
|
||||
{
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Prev, ButtonPrev_OnClick));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Next, ButtonNext_OnClick));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Selected, ToggleButton_OnChecked));
|
||||
CommandBindings.Add(new CommandBinding(ControlCommands.Jump, (s, e) => PageIndex = (int) _jumpNumericUpDown.Value));
|
||||
|
||||
OnAutoHidingChanged(AutoHiding);
|
||||
Update();
|
||||
}
|
||||
|
||||
#region Public Properties
|
||||
|
||||
#region MaxPageCount
|
||||
|
||||
/// <summary>
|
||||
/// 最大页数
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxPageCountProperty = DependencyProperty.Register(
|
||||
"MaxPageCount", typeof(int), typeof(Pagination), new PropertyMetadata(ValueBoxes.Int1Box, OnMaxPageCountChanged, CoerceMaxPageCount), ValidateHelper.IsInRangeOfPosIntIncludeZero);
|
||||
|
||||
private static object CoerceMaxPageCount(DependencyObject d, object basevalue)
|
||||
{
|
||||
var intValue = (int) basevalue;
|
||||
return intValue < 1 ? 1 : intValue;
|
||||
}
|
||||
|
||||
private static void OnMaxPageCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination)
|
||||
{
|
||||
if (pagination.PageIndex > pagination.MaxPageCount)
|
||||
{
|
||||
pagination.PageIndex = pagination.MaxPageCount;
|
||||
}
|
||||
|
||||
pagination.CoerceValue(PageIndexProperty);
|
||||
pagination.OnAutoHidingChanged(pagination.AutoHiding);
|
||||
pagination.Update();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 最大页数
|
||||
/// </summary>
|
||||
public int MaxPageCount
|
||||
{
|
||||
get => (int) GetValue(MaxPageCountProperty);
|
||||
set => SetValue(MaxPageCountProperty, value);
|
||||
}
|
||||
|
||||
#endregion MaxPageCount
|
||||
|
||||
#region DataCountPerPage
|
||||
|
||||
/// <summary>
|
||||
/// 每页的数据量
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DataCountPerPageProperty = DependencyProperty.Register(
|
||||
"DataCountPerPage", typeof(int), typeof(Pagination), new PropertyMetadata(20, OnDataCountPerPageChanged),
|
||||
ValidateHelper.IsInRangeOfPosInt);
|
||||
|
||||
private static void OnDataCountPerPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination)
|
||||
{
|
||||
pagination.Update();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每页的数据量
|
||||
/// </summary>
|
||||
public int DataCountPerPage
|
||||
{
|
||||
get => (int) GetValue(DataCountPerPageProperty);
|
||||
set => SetValue(DataCountPerPageProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PageIndex
|
||||
|
||||
/// <summary>
|
||||
/// 当前页
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PageIndexProperty = DependencyProperty.Register(
|
||||
"PageIndex", typeof(int), typeof(Pagination), new PropertyMetadata(ValueBoxes.Int1Box, OnPageIndexChanged, CoercePageIndex), ValidateHelper.IsInRangeOfPosIntIncludeZero);
|
||||
|
||||
private static object CoercePageIndex(DependencyObject d, object basevalue)
|
||||
{
|
||||
if (d is not Pagination pagination) return 1;
|
||||
|
||||
var intValue = (int) basevalue;
|
||||
return intValue < 1
|
||||
? 1
|
||||
: intValue > pagination.MaxPageCount
|
||||
? pagination.MaxPageCount
|
||||
: intValue;
|
||||
}
|
||||
|
||||
private static void OnPageIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination && e.NewValue is int value)
|
||||
{
|
||||
pagination.Update();
|
||||
pagination.RaiseEvent(new FunctionEventArgs<int>(PageUpdatedEvent, pagination)
|
||||
{
|
||||
Info = value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前页
|
||||
/// </summary>
|
||||
public int PageIndex
|
||||
{
|
||||
get => (int) GetValue(PageIndexProperty);
|
||||
set => SetValue(PageIndexProperty, value);
|
||||
}
|
||||
|
||||
#endregion PageIndex
|
||||
|
||||
#region MaxPageInterval
|
||||
|
||||
/// <summary>
|
||||
/// 表示当前选中的按钮距离左右两个方向按钮的最大间隔(4表示间隔4个按钮,如果超过则用省略号表示)
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxPageIntervalProperty = DependencyProperty.Register(
|
||||
"MaxPageInterval", typeof(int), typeof(Pagination), new PropertyMetadata(3, OnMaxPageIntervalChanged), ValidateHelper.IsInRangeOfPosIntIncludeZero);
|
||||
|
||||
private static void OnMaxPageIntervalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination)
|
||||
{
|
||||
pagination.Update();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表示当前选中的按钮距离左右两个方向按钮的最大间隔(4表示间隔4个按钮,如果超过则用省略号表示)
|
||||
/// </summary>
|
||||
public int MaxPageInterval
|
||||
{
|
||||
get => (int) GetValue(MaxPageIntervalProperty);
|
||||
set => SetValue(MaxPageIntervalProperty, value);
|
||||
}
|
||||
|
||||
#endregion MaxPageInterval
|
||||
|
||||
#region IsJumpEnabled
|
||||
|
||||
public static readonly DependencyProperty IsJumpEnabledProperty = DependencyProperty.Register(
|
||||
"IsJumpEnabled", typeof(bool), typeof(Pagination), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public bool IsJumpEnabled
|
||||
{
|
||||
get => (bool) GetValue(IsJumpEnabledProperty);
|
||||
set => SetValue(IsJumpEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region AutoHiding
|
||||
|
||||
public static readonly DependencyProperty AutoHidingProperty = DependencyProperty.Register(
|
||||
"AutoHiding", typeof(bool), typeof(Pagination), new PropertyMetadata(ValueBoxes.TrueBox, OnAutoHidingChanged));
|
||||
|
||||
private static void OnAutoHidingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Pagination pagination)
|
||||
{
|
||||
pagination.OnAutoHidingChanged((bool) e.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAutoHidingChanged(bool newValue) => this.Show(!newValue || MaxPageCount > 1);
|
||||
|
||||
public bool AutoHiding
|
||||
{
|
||||
get => (bool) GetValue(AutoHidingProperty);
|
||||
set => SetValue(AutoHidingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
_appliedTemplate = false;
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_buttonLeft = GetTemplateChild(ElementButtonLeft) as Button;
|
||||
_buttonRight = GetTemplateChild(ElementButtonRight) as Button;
|
||||
_buttonFirst = GetTemplateChild(ElementButtonFirst) as RadioButton;
|
||||
_moreLeft = GetTemplateChild(ElementMoreLeft) as FrameworkElement;
|
||||
_panelMain = GetTemplateChild(ElementPanelMain) as Panel;
|
||||
_moreRight = GetTemplateChild(ElementMoreRight) as FrameworkElement;
|
||||
_buttonLast = GetTemplateChild(ElementButtonLast) as RadioButton;
|
||||
_jumpNumericUpDown = GetTemplateChild(ElementJump) as NumericUpDown;
|
||||
|
||||
CheckNull();
|
||||
|
||||
_appliedTemplate = true;
|
||||
Update();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void CheckNull()
|
||||
{
|
||||
if (_buttonLeft == null || _buttonRight == null || _buttonFirst == null ||
|
||||
_moreLeft == null || _panelMain == null || _moreRight == null ||
|
||||
_buttonLast == null) throw new Exception();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
if (!_appliedTemplate) return;
|
||||
_buttonLeft.IsEnabled = PageIndex > 1;
|
||||
_buttonRight.IsEnabled = PageIndex < MaxPageCount;
|
||||
if (MaxPageInterval == 0)
|
||||
{
|
||||
_buttonFirst.Collapse();
|
||||
_buttonLast.Collapse();
|
||||
_moreLeft.Collapse();
|
||||
_moreRight.Collapse();
|
||||
_panelMain.Children.Clear();
|
||||
var selectButton = CreateButton(PageIndex);
|
||||
_panelMain.Children.Add(selectButton);
|
||||
selectButton.IsChecked = true;
|
||||
return;
|
||||
}
|
||||
_buttonFirst.Show();
|
||||
_buttonLast.Show();
|
||||
_moreLeft.Show();
|
||||
_moreRight.Show();
|
||||
|
||||
//更新最后一页
|
||||
if (MaxPageCount == 1)
|
||||
{
|
||||
_buttonLast.Collapse();
|
||||
}
|
||||
else
|
||||
{
|
||||
_buttonLast.Show();
|
||||
_buttonLast.Content = MaxPageCount.ToString();
|
||||
}
|
||||
|
||||
//更新省略号
|
||||
var right = MaxPageCount - PageIndex;
|
||||
var left = PageIndex - 1;
|
||||
_moreRight.Show(right > MaxPageInterval);
|
||||
_moreLeft.Show(left > MaxPageInterval);
|
||||
|
||||
//更新中间部分
|
||||
_panelMain.Children.Clear();
|
||||
if (PageIndex > 1 && PageIndex < MaxPageCount)
|
||||
{
|
||||
var selectButton = CreateButton(PageIndex);
|
||||
_panelMain.Children.Add(selectButton);
|
||||
selectButton.IsChecked = true;
|
||||
}
|
||||
else if (PageIndex == 1)
|
||||
{
|
||||
_buttonFirst.IsChecked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_buttonLast.IsChecked = true;
|
||||
}
|
||||
|
||||
var sub = PageIndex;
|
||||
for (var i = 0; i < MaxPageInterval - 1; i++)
|
||||
{
|
||||
if (--sub > 1)
|
||||
{
|
||||
_panelMain.Children.Insert(0, CreateButton(sub));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
var add = PageIndex;
|
||||
for (var i = 0; i < MaxPageInterval - 1; i++)
|
||||
{
|
||||
if (++add < MaxPageCount)
|
||||
{
|
||||
_panelMain.Children.Add(CreateButton(add));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ButtonPrev_OnClick(object sender, RoutedEventArgs e) => PageIndex--;
|
||||
|
||||
private void ButtonNext_OnClick(object sender, RoutedEventArgs e) => PageIndex++;
|
||||
|
||||
private RadioButton CreateButton(int page)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
Style = ResourceHelper.GetResourceInternal<Style>(ResourceToken.PaginationButtonStyle),
|
||||
Content = page.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
private void ToggleButton_OnChecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (e.OriginalSource is not RadioButton button) return;
|
||||
if (button.IsChecked == false) return;
|
||||
PageIndex = int.Parse(button.Content.ToString());
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
@@ -7,313 +7,322 @@ using System.Windows.Input;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Data.Enum;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class Poptip : AdornerElement
|
||||
{
|
||||
public class Poptip : AdornerElement
|
||||
private readonly Popup _popup;
|
||||
|
||||
public Poptip()
|
||||
{
|
||||
private readonly Popup _popup;
|
||||
|
||||
public Poptip()
|
||||
_popup = new Popup
|
||||
{
|
||||
_popup = new Popup
|
||||
{
|
||||
AllowsTransparency = true,
|
||||
Child = this
|
||||
};
|
||||
AllowsTransparency = true,
|
||||
Child = this,
|
||||
Placement = PlacementMode.Relative
|
||||
};
|
||||
|
||||
_popup.SetBinding(DataContextProperty, new Binding(DataContextProperty.Name) { Source = this });
|
||||
}
|
||||
_popup.SetBinding(DataContextProperty, new Binding(DataContextProperty.Name) { Source = this });
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HitModeProperty = DependencyProperty.RegisterAttached(
|
||||
"HitMode", typeof(HitMode), typeof(Poptip), new PropertyMetadata(HitMode.Hover));
|
||||
public static readonly DependencyProperty HitModeProperty = DependencyProperty.RegisterAttached(
|
||||
"HitMode", typeof(HitMode), typeof(Poptip), new PropertyMetadata(HitMode.Hover));
|
||||
|
||||
public static void SetHitMode(DependencyObject element, HitMode value)
|
||||
=> element.SetValue(HitModeProperty, value);
|
||||
public static void SetHitMode(DependencyObject element, HitMode value)
|
||||
=> element.SetValue(HitModeProperty, value);
|
||||
|
||||
public static HitMode GetHitMode(DependencyObject element)
|
||||
=> (HitMode) element.GetValue(HitModeProperty);
|
||||
public static HitMode GetHitMode(DependencyObject element)
|
||||
=> (HitMode) element.GetValue(HitModeProperty);
|
||||
|
||||
public HitMode HitMode
|
||||
public HitMode HitMode
|
||||
{
|
||||
get => (HitMode) GetValue(HitModeProperty);
|
||||
set => SetValue(HitModeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.RegisterAttached(
|
||||
"Content", typeof(object), typeof(Poptip), new PropertyMetadata(default, OnContentChanged));
|
||||
|
||||
private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Poptip) return;
|
||||
if (GetInstance(d) == null)
|
||||
{
|
||||
get => (HitMode) GetValue(HitModeProperty);
|
||||
set => SetValue(HitModeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.RegisterAttached(
|
||||
"Content", typeof(object), typeof(Poptip), new PropertyMetadata(default, OnContentChanged));
|
||||
|
||||
private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Poptip) return;
|
||||
if (GetInstance(d) == null)
|
||||
{
|
||||
SetInstance(d, Default);
|
||||
SetIsInstance(d, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetContent(DependencyObject element, object value)
|
||||
=> element.SetValue(ContentProperty, value);
|
||||
|
||||
public static object GetContent(DependencyObject element)
|
||||
=> element.GetValue(ContentProperty);
|
||||
|
||||
public object Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register(
|
||||
"ContentTemplate", typeof(DataTemplate), typeof(Poptip), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public DataTemplate ContentTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(ContentTemplateProperty);
|
||||
set => SetValue(ContentTemplateProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentStringFormatProperty = DependencyProperty.Register(
|
||||
"ContentStringFormat", typeof(string), typeof(Poptip), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ContentStringFormat
|
||||
{
|
||||
get => (string) GetValue(ContentStringFormatProperty);
|
||||
set => SetValue(ContentStringFormatProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"ContentTemplateSelector", typeof(DataTemplateSelector), typeof(Poptip), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
|
||||
public DataTemplateSelector ContentTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector) GetValue(ContentTemplateSelectorProperty);
|
||||
set => SetValue(ContentTemplateSelectorProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OffsetProperty = DependencyProperty.RegisterAttached(
|
||||
"Offset", typeof(double), typeof(Poptip), new PropertyMetadata(6.0));
|
||||
|
||||
public static void SetOffset(DependencyObject element, double value)
|
||||
=> element.SetValue(OffsetProperty, value);
|
||||
|
||||
public static double GetOffset(DependencyObject element)
|
||||
=> (double) element.GetValue(OffsetProperty);
|
||||
|
||||
public double Offset
|
||||
{
|
||||
get => (double) GetValue(OffsetProperty);
|
||||
set => SetValue(OffsetProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PlacementTypeProperty = DependencyProperty.RegisterAttached(
|
||||
"PlacementType", typeof(PlacementType), typeof(Poptip), new PropertyMetadata(PlacementType.Top));
|
||||
|
||||
public static void SetPlacement(DependencyObject element, PlacementType value)
|
||||
=> element.SetValue(PlacementTypeProperty, value);
|
||||
|
||||
public static PlacementType GetPlacement(DependencyObject element)
|
||||
=> (PlacementType) element.GetValue(PlacementTypeProperty);
|
||||
|
||||
public PlacementType PlacementType
|
||||
{
|
||||
get => (PlacementType) GetValue(PlacementTypeProperty);
|
||||
set => SetValue(PlacementTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsOpenProperty = DependencyProperty.RegisterAttached(
|
||||
"IsOpen", typeof(bool), typeof(Poptip), new PropertyMetadata(ValueBoxes.FalseBox, OnIsOpenChanged));
|
||||
|
||||
private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Poptip poptip)
|
||||
{
|
||||
poptip.SwitchPoptip((bool) e.NewValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
((Poptip) GetInstance(d))?.SwitchPoptip((bool) e.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetIsOpen(DependencyObject element, bool value)
|
||||
=> element.SetValue(IsOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsOpen(DependencyObject element)
|
||||
=> (bool) element.GetValue(IsOpenProperty);
|
||||
|
||||
public bool IsOpen
|
||||
{
|
||||
get => (bool) GetValue(IsOpenProperty);
|
||||
set => SetValue(IsOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static Poptip Default => new();
|
||||
|
||||
protected sealed override void OnTargetChanged(FrameworkElement element, bool isNew)
|
||||
{
|
||||
base.OnTargetChanged(element, isNew);
|
||||
|
||||
if (element == null) return;
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
element.MouseEnter -= Element_MouseEnter;
|
||||
element.MouseLeave -= Element_MouseLeave;
|
||||
element.GotFocus -= Element_GotFocus;
|
||||
element.LostFocus -= Element_LostFocus;
|
||||
ElementTarget = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
element.MouseEnter += Element_MouseEnter;
|
||||
element.MouseLeave += Element_MouseLeave;
|
||||
element.GotFocus += Element_GotFocus;
|
||||
element.LostFocus += Element_LostFocus;
|
||||
ElementTarget = element;
|
||||
_popup.PlacementTarget = ElementTarget;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose() => SwitchPoptip(false);
|
||||
|
||||
private void UpdateLocation()
|
||||
{
|
||||
var targetWidth = Target.RenderSize.Width;
|
||||
var targetHeight = Target.RenderSize.Height;
|
||||
|
||||
Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
var size = DesiredSize;
|
||||
|
||||
var width = size.Width;
|
||||
var height = size.Height;
|
||||
|
||||
var offsetX = .0;
|
||||
var offsetY = .0;
|
||||
|
||||
var poptip = (Poptip) GetInstance(Target);
|
||||
var popupPlacement = poptip.PlacementType;
|
||||
var popupOffset = poptip.Offset;
|
||||
|
||||
PlacementMode placementMode;
|
||||
|
||||
switch (popupPlacement)
|
||||
{
|
||||
case PlacementType.LeftTop:
|
||||
offsetX = -popupOffset;
|
||||
placementMode = PlacementMode.Left;
|
||||
break;
|
||||
case PlacementType.Left:
|
||||
offsetX = -popupOffset;
|
||||
offsetY = (targetHeight - height) / 2;
|
||||
placementMode = PlacementMode.Left;
|
||||
break;
|
||||
case PlacementType.LeftBottom:
|
||||
offsetX = -popupOffset;
|
||||
offsetY = targetHeight - height;
|
||||
placementMode = PlacementMode.Left;
|
||||
break;
|
||||
case PlacementType.TopLeft:
|
||||
offsetY = -popupOffset;
|
||||
placementMode = PlacementMode.Top;
|
||||
break;
|
||||
case PlacementType.Top:
|
||||
offsetX = (targetWidth - width) / 2;
|
||||
offsetY = -popupOffset;
|
||||
placementMode = PlacementMode.Top;
|
||||
break;
|
||||
case PlacementType.TopRight:
|
||||
offsetX = targetWidth - width;
|
||||
offsetY = -popupOffset;
|
||||
placementMode = PlacementMode.Top;
|
||||
break;
|
||||
case PlacementType.RightTop:
|
||||
offsetX = popupOffset;
|
||||
placementMode = PlacementMode.Right;
|
||||
break;
|
||||
case PlacementType.Right:
|
||||
offsetX = popupOffset;
|
||||
offsetY = (targetHeight - height) / 2;
|
||||
placementMode = PlacementMode.Right;
|
||||
break;
|
||||
case PlacementType.RightBottom:
|
||||
offsetX = popupOffset;
|
||||
offsetY = targetHeight - height;
|
||||
placementMode = PlacementMode.Right;
|
||||
break;
|
||||
case PlacementType.BottomLeft:
|
||||
offsetY = popupOffset;
|
||||
placementMode = PlacementMode.Bottom;
|
||||
break;
|
||||
case PlacementType.Bottom:
|
||||
offsetX = (targetWidth - width) / 2;
|
||||
offsetY = popupOffset;
|
||||
placementMode = PlacementMode.Bottom;
|
||||
break;
|
||||
case PlacementType.BottomRight:
|
||||
offsetX = targetWidth - width;
|
||||
offsetY = popupOffset;
|
||||
placementMode = PlacementMode.Bottom;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
_popup.HorizontalOffset = offsetX;
|
||||
_popup.VerticalOffset = offsetY;
|
||||
_popup.Placement = placementMode;
|
||||
}
|
||||
|
||||
private void SwitchPoptip(bool isShow)
|
||||
{
|
||||
if (isShow)
|
||||
{
|
||||
if (!GetIsInstance(Target))
|
||||
{
|
||||
SetCurrentValue(ContentProperty, GetContent(Target));
|
||||
SetCurrentValue(PlacementTypeProperty, GetPlacement(Target));
|
||||
SetCurrentValue(HitModeProperty, GetHitMode(Target));
|
||||
SetCurrentValue(OffsetProperty, GetOffset(Target));
|
||||
SetCurrentValue(IsOpenProperty, GetIsOpen(Target));
|
||||
}
|
||||
|
||||
_popup.PlacementTarget = Target;
|
||||
UpdateLocation();
|
||||
}
|
||||
_popup.IsOpen = isShow;
|
||||
Target.SetCurrentValue(IsOpenProperty, isShow);
|
||||
}
|
||||
|
||||
private void Element_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
var hitMode = GetIsInstance(Target) ? HitMode : GetHitMode(Target);
|
||||
if (hitMode != HitMode.Hover) return;
|
||||
|
||||
SwitchPoptip(true);
|
||||
}
|
||||
|
||||
private void Element_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
var hitMode = GetIsInstance(Target) ? HitMode : GetHitMode(Target);
|
||||
if (hitMode != HitMode.Hover) return;
|
||||
|
||||
SwitchPoptip(false);
|
||||
}
|
||||
|
||||
private void Element_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var hitMode = GetIsInstance(Target) ? HitMode : GetHitMode(Target);
|
||||
if (hitMode != HitMode.Focus) return;
|
||||
|
||||
SwitchPoptip(true);
|
||||
}
|
||||
|
||||
private void Element_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var hitMode = GetIsInstance(Target) ? HitMode : GetHitMode(Target);
|
||||
if (hitMode != HitMode.Focus) return;
|
||||
|
||||
SwitchPoptip(false);
|
||||
SetInstance(d, Default);
|
||||
SetIsInstance(d, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetContent(DependencyObject element, object value)
|
||||
=> element.SetValue(ContentProperty, value);
|
||||
|
||||
public static object GetContent(DependencyObject element)
|
||||
=> element.GetValue(ContentProperty);
|
||||
|
||||
public object Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register(
|
||||
"ContentTemplate", typeof(DataTemplate), typeof(Poptip), new PropertyMetadata(default(DataTemplate)));
|
||||
|
||||
public DataTemplate ContentTemplate
|
||||
{
|
||||
get => (DataTemplate) GetValue(ContentTemplateProperty);
|
||||
set => SetValue(ContentTemplateProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentStringFormatProperty = DependencyProperty.Register(
|
||||
"ContentStringFormat", typeof(string), typeof(Poptip), new PropertyMetadata(default(string)));
|
||||
|
||||
public string ContentStringFormat
|
||||
{
|
||||
get => (string) GetValue(ContentStringFormatProperty);
|
||||
set => SetValue(ContentStringFormatProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentTemplateSelectorProperty = DependencyProperty.Register(
|
||||
"ContentTemplateSelector", typeof(DataTemplateSelector), typeof(Poptip), new PropertyMetadata(default(DataTemplateSelector)));
|
||||
|
||||
public DataTemplateSelector ContentTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector) GetValue(ContentTemplateSelectorProperty);
|
||||
set => SetValue(ContentTemplateSelectorProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.RegisterAttached(
|
||||
"VerticalOffset", typeof(double), typeof(Poptip), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public static void SetVerticalOffset(DependencyObject element, double value)
|
||||
{
|
||||
element.SetValue(VerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
public static double GetVerticalOffset(DependencyObject element)
|
||||
{
|
||||
return (double) element.GetValue(VerticalOffsetProperty);
|
||||
}
|
||||
|
||||
public double VerticalOffset
|
||||
{
|
||||
get => (double) GetValue(VerticalOffsetProperty);
|
||||
set => SetValue(VerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.RegisterAttached(
|
||||
"HorizontalOffset", typeof(double), typeof(Poptip), new PropertyMetadata(ValueBoxes.Double0Box));
|
||||
|
||||
public static void SetHorizontalOffset(DependencyObject element, double value)
|
||||
{
|
||||
element.SetValue(HorizontalOffsetProperty, value);
|
||||
}
|
||||
|
||||
public static double GetHorizontalOffset(DependencyObject element)
|
||||
{
|
||||
return (double) element.GetValue(HorizontalOffsetProperty);
|
||||
}
|
||||
|
||||
public double HorizontalOffset
|
||||
{
|
||||
get => (double) GetValue(HorizontalOffsetProperty);
|
||||
set => SetValue(HorizontalOffsetProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty PlacementTypeProperty = DependencyProperty.RegisterAttached(
|
||||
"PlacementType", typeof(PlacementType), typeof(Poptip), new PropertyMetadata(PlacementType.Top));
|
||||
|
||||
public static void SetPlacement(DependencyObject element, PlacementType value)
|
||||
=> element.SetValue(PlacementTypeProperty, value);
|
||||
|
||||
public static PlacementType GetPlacement(DependencyObject element)
|
||||
=> (PlacementType) element.GetValue(PlacementTypeProperty);
|
||||
|
||||
public PlacementType PlacementType
|
||||
{
|
||||
get => (PlacementType) GetValue(PlacementTypeProperty);
|
||||
set => SetValue(PlacementTypeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsOpenProperty = DependencyProperty.RegisterAttached(
|
||||
"IsOpen", typeof(bool), typeof(Poptip), new PropertyMetadata(ValueBoxes.FalseBox, OnIsOpenChanged));
|
||||
|
||||
private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Poptip poptip)
|
||||
{
|
||||
poptip.SwitchPoptip((bool) e.NewValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
((Poptip) GetInstance(d))?.SwitchPoptip((bool) e.NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetIsOpen(DependencyObject element, bool value)
|
||||
=> element.SetValue(IsOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsOpen(DependencyObject element)
|
||||
=> (bool) element.GetValue(IsOpenProperty);
|
||||
|
||||
public bool IsOpen
|
||||
{
|
||||
get => (bool) GetValue(IsOpenProperty);
|
||||
set => SetValue(IsOpenProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static Poptip Default => new();
|
||||
|
||||
protected sealed override void OnTargetChanged(FrameworkElement element, bool isNew)
|
||||
{
|
||||
base.OnTargetChanged(element, isNew);
|
||||
|
||||
if (element == null) return;
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
element.MouseEnter -= Element_MouseEnter;
|
||||
element.MouseLeave -= Element_MouseLeave;
|
||||
element.GotFocus -= Element_GotFocus;
|
||||
element.LostFocus -= Element_LostFocus;
|
||||
ElementTarget = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
element.MouseEnter += Element_MouseEnter;
|
||||
element.MouseLeave += Element_MouseLeave;
|
||||
element.GotFocus += Element_GotFocus;
|
||||
element.LostFocus += Element_LostFocus;
|
||||
ElementTarget = element;
|
||||
_popup.PlacementTarget = ElementTarget;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose() => SwitchPoptip(false);
|
||||
|
||||
private void UpdateLocation()
|
||||
{
|
||||
var targetWidth = Target.RenderSize.Width;
|
||||
var targetHeight = Target.RenderSize.Height;
|
||||
|
||||
Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
var size = DesiredSize;
|
||||
|
||||
var width = size.Width;
|
||||
var height = size.Height;
|
||||
|
||||
var offsetX = .0;
|
||||
var offsetY = .0;
|
||||
|
||||
var poptip = (Poptip) GetInstance(Target);
|
||||
var popupPlacement = poptip.PlacementType;
|
||||
var popupOffsetX = poptip.HorizontalOffset;
|
||||
var popupOffsetY = poptip.VerticalOffset;
|
||||
|
||||
switch (popupPlacement)
|
||||
{
|
||||
case PlacementType.LeftTop:
|
||||
break;
|
||||
case PlacementType.Left:
|
||||
offsetY = -(height - targetHeight) * 0.5;
|
||||
break;
|
||||
case PlacementType.LeftBottom:
|
||||
offsetY = -(height - targetHeight);
|
||||
break;
|
||||
case PlacementType.TopLeft:
|
||||
offsetX = width;
|
||||
offsetY = -height;
|
||||
break;
|
||||
case PlacementType.Top:
|
||||
offsetX = (width + targetWidth) * 0.5;
|
||||
offsetY = -height;
|
||||
break;
|
||||
case PlacementType.TopRight:
|
||||
offsetX = targetWidth;
|
||||
offsetY = -height;
|
||||
break;
|
||||
case PlacementType.RightTop:
|
||||
offsetX = width + targetWidth;
|
||||
break;
|
||||
case PlacementType.Right:
|
||||
offsetX = width + targetWidth;
|
||||
offsetY = -(height - targetHeight) * 0.5;
|
||||
break;
|
||||
case PlacementType.RightBottom:
|
||||
offsetX = width + targetWidth;
|
||||
offsetY = -(height - targetHeight);
|
||||
break;
|
||||
case PlacementType.BottomLeft:
|
||||
offsetX = width;
|
||||
offsetY = targetHeight;
|
||||
break;
|
||||
case PlacementType.Bottom:
|
||||
offsetX = (width + targetWidth) * 0.5;
|
||||
offsetY = targetHeight;
|
||||
break;
|
||||
case PlacementType.BottomRight:
|
||||
offsetX = targetWidth;
|
||||
offsetY = targetHeight;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
_popup.HorizontalOffset = offsetX + popupOffsetX;
|
||||
_popup.VerticalOffset = offsetY + popupOffsetY;
|
||||
}
|
||||
|
||||
private void SwitchPoptip(bool isShow)
|
||||
{
|
||||
if (isShow)
|
||||
{
|
||||
if (!GetIsInstance(Target))
|
||||
{
|
||||
SetCurrentValue(ContentProperty, GetContent(Target));
|
||||
SetCurrentValue(PlacementTypeProperty, GetPlacement(Target));
|
||||
SetCurrentValue(HitModeProperty, GetHitMode(Target));
|
||||
SetCurrentValue(HorizontalOffsetProperty, GetHorizontalOffset(Target));
|
||||
SetCurrentValue(VerticalOffsetProperty, GetVerticalOffset(Target));
|
||||
SetCurrentValue(IsOpenProperty, GetIsOpen(Target));
|
||||
}
|
||||
|
||||
_popup.PlacementTarget = Target;
|
||||
UpdateLocation();
|
||||
}
|
||||
_popup.IsOpen = isShow;
|
||||
Target.SetCurrentValue(IsOpenProperty, isShow);
|
||||
}
|
||||
|
||||
private void Element_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
var hitMode = GetIsInstance(Target) ? HitMode : GetHitMode(Target);
|
||||
if (hitMode != HitMode.Hover) return;
|
||||
|
||||
SwitchPoptip(true);
|
||||
}
|
||||
|
||||
private void Element_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
var hitMode = GetIsInstance(Target) ? HitMode : GetHitMode(Target);
|
||||
if (hitMode != HitMode.Hover) return;
|
||||
|
||||
SwitchPoptip(false);
|
||||
}
|
||||
|
||||
private void Element_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var hitMode = GetIsInstance(Target) ? HitMode : GetHitMode(Target);
|
||||
if (hitMode != HitMode.Focus) return;
|
||||
|
||||
SwitchPoptip(true);
|
||||
}
|
||||
|
||||
private void Element_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var hitMode = GetIsInstance(Target) ? HitMode : GetHitMode(Target);
|
||||
if (hitMode != HitMode.Focus) return;
|
||||
|
||||
SwitchPoptip(false);
|
||||
}
|
||||
}
|
||||
@@ -7,221 +7,205 @@ using System.Windows.Media.Animation;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ScrollViewer : System.Windows.Controls.ScrollViewer
|
||||
{
|
||||
public class ScrollViewer : System.Windows.Controls.ScrollViewer
|
||||
private double _totalVerticalOffset;
|
||||
|
||||
private double _totalHorizontalOffset;
|
||||
|
||||
private bool _isRunning;
|
||||
|
||||
/// <summary>
|
||||
/// 是否响应鼠标滚轮操作
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CanMouseWheelProperty = DependencyProperty.Register(
|
||||
"CanMouseWheel", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否响应鼠标滚轮操作
|
||||
/// </summary>
|
||||
public bool CanMouseWheel
|
||||
{
|
||||
private double _totalVerticalOffset;
|
||||
get => (bool) GetValue(CanMouseWheelProperty);
|
||||
set => SetValue(CanMouseWheelProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
private double _totalHorizontalOffset;
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
if (!CanMouseWheel) return;
|
||||
|
||||
private bool _isRunning;
|
||||
|
||||
/// <summary>
|
||||
/// 滚动方向
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(ScrollViewer), new PropertyMetadata(Orientation.Vertical));
|
||||
|
||||
/// <summary>
|
||||
/// 滚动方向
|
||||
/// </summary>
|
||||
public Orientation Orientation
|
||||
if (!IsInertiaEnabled)
|
||||
{
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否响应鼠标滚轮操作
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CanMouseWheelProperty = DependencyProperty.Register(
|
||||
"CanMouseWheel", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否响应鼠标滚轮操作
|
||||
/// </summary>
|
||||
public bool CanMouseWheel
|
||||
{
|
||||
get => (bool) GetValue(CanMouseWheelProperty);
|
||||
set => SetValue(CanMouseWheelProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
if (!CanMouseWheel) return;
|
||||
|
||||
if (!IsInertiaEnabled)
|
||||
if (ScrollViewerAttach.GetOrientation(this) == Orientation.Vertical)
|
||||
{
|
||||
if (Orientation == Orientation.Vertical)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
_totalHorizontalOffset = HorizontalOffset;
|
||||
CurrentHorizontalOffset = HorizontalOffset;
|
||||
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
|
||||
CurrentHorizontalOffset = _totalHorizontalOffset;
|
||||
}
|
||||
return;
|
||||
}
|
||||
e.Handled = true;
|
||||
|
||||
if (Orientation == Orientation.Vertical)
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalVerticalOffset = VerticalOffset;
|
||||
CurrentVerticalOffset = VerticalOffset;
|
||||
}
|
||||
_totalVerticalOffset = Math.Min(Math.Max(0, _totalVerticalOffset - e.Delta), ScrollableHeight);
|
||||
ScrollToVerticalOffsetWithAnimation(_totalVerticalOffset);
|
||||
base.OnMouseWheel(e);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalHorizontalOffset = HorizontalOffset;
|
||||
CurrentHorizontalOffset = HorizontalOffset;
|
||||
}
|
||||
_totalHorizontalOffset = HorizontalOffset;
|
||||
CurrentHorizontalOffset = HorizontalOffset;
|
||||
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
|
||||
ScrollToHorizontalOffsetWithAnimation(_totalHorizontalOffset);
|
||||
CurrentHorizontalOffset = _totalHorizontalOffset;
|
||||
}
|
||||
return;
|
||||
}
|
||||
e.Handled = true;
|
||||
|
||||
internal void ScrollToTopInternal(double milliseconds = 500)
|
||||
if (ScrollViewerAttach.GetOrientation(this) == Orientation.Vertical)
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalVerticalOffset = VerticalOffset;
|
||||
CurrentVerticalOffset = VerticalOffset;
|
||||
}
|
||||
ScrollToVerticalOffsetWithAnimation(0, milliseconds);
|
||||
_totalVerticalOffset = Math.Min(Math.Max(0, _totalVerticalOffset - e.Delta), ScrollableHeight);
|
||||
ScrollToVerticalOffsetWithAnimation(_totalVerticalOffset);
|
||||
}
|
||||
|
||||
public void ScrollToVerticalOffsetWithAnimation(double offset, double milliseconds = 500)
|
||||
else
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
if (!_isRunning)
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentVerticalOffset = offset;
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
|
||||
BeginAnimation(CurrentVerticalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
public void ScrollToHorizontalOffsetWithAnimation(double offset, double milliseconds = 500)
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentHorizontalOffset = offset;
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
|
||||
BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) =>
|
||||
IsPenetrating ? null : base.HitTestCore(hitTestParameters);
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持惯性
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsInertiaEnabledProperty = DependencyProperty.RegisterAttached(
|
||||
"IsInertiaEnabled", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static void SetIsInertiaEnabled(DependencyObject element, bool value) => element.SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsInertiaEnabled(DependencyObject element) => (bool) element.GetValue(IsInertiaEnabledProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持惯性
|
||||
/// </summary>
|
||||
public bool IsInertiaEnabled
|
||||
{
|
||||
get => (bool) GetValue(IsInertiaEnabledProperty);
|
||||
set => SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 控件是否可以穿透点击
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsPenetratingProperty = DependencyProperty.RegisterAttached(
|
||||
"IsPenetrating", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 控件是否可以穿透点击
|
||||
/// </summary>
|
||||
public bool IsPenetrating
|
||||
{
|
||||
get => (bool) GetValue(IsPenetratingProperty);
|
||||
set => SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static void SetIsPenetrating(DependencyObject element, bool value) => element.SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsPenetrating(DependencyObject element) => (bool) element.GetValue(IsPenetratingProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 当前垂直滚动偏移
|
||||
/// </summary>
|
||||
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)
|
||||
{
|
||||
if (d is ScrollViewer ctl && e.NewValue is double v)
|
||||
{
|
||||
ctl.ScrollToVerticalOffset(v);
|
||||
_totalHorizontalOffset = HorizontalOffset;
|
||||
CurrentHorizontalOffset = HorizontalOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前垂直滚动偏移
|
||||
/// </summary>
|
||||
internal double CurrentVerticalOffset
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
get => (double) GetValue(CurrentVerticalOffsetProperty);
|
||||
set => SetValue(CurrentVerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前水平滚动偏移
|
||||
/// </summary>
|
||||
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)
|
||||
{
|
||||
if (d is ScrollViewer ctl && e.NewValue is double v)
|
||||
{
|
||||
ctl.ScrollToHorizontalOffset(v);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前水平滚动偏移
|
||||
/// </summary>
|
||||
internal double CurrentHorizontalOffset
|
||||
{
|
||||
get => (double) GetValue(CurrentHorizontalOffsetProperty);
|
||||
set => SetValue(CurrentHorizontalOffsetProperty, value);
|
||||
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
|
||||
ScrollToHorizontalOffsetWithAnimation(_totalHorizontalOffset);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ScrollToTopInternal(double milliseconds = 500)
|
||||
{
|
||||
if (!_isRunning)
|
||||
{
|
||||
_totalVerticalOffset = VerticalOffset;
|
||||
CurrentVerticalOffset = VerticalOffset;
|
||||
}
|
||||
ScrollToVerticalOffsetWithAnimation(0, milliseconds);
|
||||
}
|
||||
|
||||
public void ScrollToVerticalOffsetWithAnimation(double offset, double milliseconds = 500)
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentVerticalOffset = offset;
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
|
||||
BeginAnimation(CurrentVerticalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
public void ScrollToHorizontalOffsetWithAnimation(double offset, double milliseconds = 500)
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentHorizontalOffset = offset;
|
||||
_isRunning = false;
|
||||
};
|
||||
_isRunning = true;
|
||||
|
||||
BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) =>
|
||||
IsPenetrating ? null : base.HitTestCore(hitTestParameters);
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持惯性
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsInertiaEnabledProperty = DependencyProperty.RegisterAttached(
|
||||
"IsInertiaEnabled", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
public static void SetIsInertiaEnabled(DependencyObject element, bool value) => element.SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsInertiaEnabled(DependencyObject element) => (bool) element.GetValue(IsInertiaEnabledProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持惯性
|
||||
/// </summary>
|
||||
public bool IsInertiaEnabled
|
||||
{
|
||||
get => (bool) GetValue(IsInertiaEnabledProperty);
|
||||
set => SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 控件是否可以穿透点击
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsPenetratingProperty = DependencyProperty.RegisterAttached(
|
||||
"IsPenetrating", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
/// <summary>
|
||||
/// 控件是否可以穿透点击
|
||||
/// </summary>
|
||||
public bool IsPenetrating
|
||||
{
|
||||
get => (bool) GetValue(IsPenetratingProperty);
|
||||
set => SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static void SetIsPenetrating(DependencyObject element, bool value) => element.SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static bool GetIsPenetrating(DependencyObject element) => (bool) element.GetValue(IsPenetratingProperty);
|
||||
|
||||
/// <summary>
|
||||
/// 当前垂直滚动偏移
|
||||
/// </summary>
|
||||
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)
|
||||
{
|
||||
if (d is ScrollViewer ctl && e.NewValue is double v)
|
||||
{
|
||||
ctl.ScrollToVerticalOffset(v);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前垂直滚动偏移
|
||||
/// </summary>
|
||||
internal double CurrentVerticalOffset
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Local
|
||||
get => (double) GetValue(CurrentVerticalOffsetProperty);
|
||||
set => SetValue(CurrentVerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前水平滚动偏移
|
||||
/// </summary>
|
||||
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)
|
||||
{
|
||||
if (d is ScrollViewer ctl && e.NewValue is double v)
|
||||
{
|
||||
ctl.ScrollToHorizontalOffset(v);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前水平滚动偏移
|
||||
/// </summary>
|
||||
internal double CurrentHorizontalOffset
|
||||
{
|
||||
get => (double) GetValue(CurrentHorizontalOffsetProperty);
|
||||
set => SetValue(CurrentHorizontalOffsetProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -3,36 +3,35 @@ using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[ContentProperty(nameof(Status))]
|
||||
public class Shield : ButtonBase
|
||||
{
|
||||
[ContentProperty(nameof(Status))]
|
||||
public class Shield : ButtonBase
|
||||
public static readonly DependencyProperty SubjectProperty = DependencyProperty.Register(
|
||||
"Subject", typeof(string), typeof(Shield), new PropertyMetadata(default(string)));
|
||||
|
||||
public string Subject
|
||||
{
|
||||
public static readonly DependencyProperty SubjectProperty = DependencyProperty.Register(
|
||||
"Subject", typeof(string), typeof(Shield), new PropertyMetadata(default(string)));
|
||||
get => (string) GetValue(SubjectProperty);
|
||||
set => SetValue(SubjectProperty, value);
|
||||
}
|
||||
|
||||
public string Subject
|
||||
{
|
||||
get => (string) GetValue(SubjectProperty);
|
||||
set => SetValue(SubjectProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty StatusProperty = DependencyProperty.Register(
|
||||
"Status", typeof(object), typeof(Shield), new PropertyMetadata(default(object)));
|
||||
|
||||
public static readonly DependencyProperty StatusProperty = DependencyProperty.Register(
|
||||
"Status", typeof(object), typeof(Shield), new PropertyMetadata(default(object)));
|
||||
public object Status
|
||||
{
|
||||
get => GetValue(StatusProperty);
|
||||
set => SetValue(StatusProperty, value);
|
||||
}
|
||||
|
||||
public object Status
|
||||
{
|
||||
get => GetValue(StatusProperty);
|
||||
set => SetValue(StatusProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(
|
||||
"Color", typeof(Brush), typeof(Shield), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(
|
||||
"Color", typeof(Brush), typeof(Shield), new PropertyMetadata(default(Brush)));
|
||||
|
||||
public Brush Color
|
||||
{
|
||||
get => (Brush) GetValue(ColorProperty);
|
||||
set => SetValue(ColorProperty, value);
|
||||
}
|
||||
public Brush Color
|
||||
{
|
||||
get => (Brush) GetValue(ColorProperty);
|
||||
set => SetValue(ColorProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,28 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public sealed class Sprite : System.Windows.Window
|
||||
{
|
||||
public sealed class Sprite : System.Windows.Window
|
||||
private Sprite()
|
||||
{
|
||||
private Sprite()
|
||||
WindowStyle = WindowStyle.None;
|
||||
AllowsTransparency = true;
|
||||
}
|
||||
|
||||
public static Sprite Show(object content)
|
||||
{
|
||||
var sprite = new Sprite
|
||||
{
|
||||
WindowStyle = WindowStyle.None;
|
||||
AllowsTransparency = true;
|
||||
}
|
||||
Content = content
|
||||
};
|
||||
|
||||
public static Sprite Show(object content)
|
||||
{
|
||||
var sprite = new Sprite
|
||||
{
|
||||
Content = content
|
||||
};
|
||||
sprite.Show();
|
||||
|
||||
sprite.Show();
|
||||
var desktopWorkingArea = SystemParameters.WorkArea;
|
||||
sprite.Left = desktopWorkingArea.Width - sprite.ActualWidth - 50;
|
||||
sprite.Top = 50 - sprite.Padding.Top;
|
||||
|
||||
var desktopWorkingArea = SystemParameters.WorkArea;
|
||||
sprite.Left = desktopWorkingArea.Width - sprite.ActualWidth - 50;
|
||||
sprite.Top = 50 - sprite.Padding.Top;
|
||||
|
||||
return sprite;
|
||||
}
|
||||
return sprite;
|
||||
}
|
||||
}
|
||||
@@ -5,103 +5,103 @@ using System.Windows.Media.Animation;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class TransitioningContentControl : ContentControl
|
||||
{
|
||||
public class TransitioningContentControl : ContentControl
|
||||
private FrameworkElement _contentPresenter;
|
||||
|
||||
private static Storyboard StoryboardBuildInDefault;
|
||||
|
||||
private Storyboard _storyboardBuildIn;
|
||||
|
||||
public TransitioningContentControl()
|
||||
{
|
||||
private FrameworkElement _contentPresenter;
|
||||
Loaded += TransitioningContentControl_Loaded;
|
||||
Unloaded += TransitioningContentControl_Unloaded;
|
||||
}
|
||||
|
||||
private static Storyboard StoryboardBuildInDefault;
|
||||
public static readonly DependencyProperty TransitionModeProperty = DependencyProperty.Register(
|
||||
"TransitionMode", typeof(TransitionMode), typeof(TransitioningContentControl), new PropertyMetadata(default(TransitionMode), OnTransitionModeChanged));
|
||||
|
||||
private Storyboard _storyboardBuildIn;
|
||||
private static void OnTransitionModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (TransitioningContentControl) d;
|
||||
ctl.OnTransitionModeChanged((TransitionMode) e.NewValue);
|
||||
}
|
||||
|
||||
public TransitioningContentControl()
|
||||
private void OnTransitionModeChanged(TransitionMode newValue)
|
||||
{
|
||||
_storyboardBuildIn = ResourceHelper.GetResourceInternal<Storyboard>($"{newValue}Transition");
|
||||
StartTransition();
|
||||
}
|
||||
|
||||
public TransitionMode TransitionMode
|
||||
{
|
||||
get => (TransitionMode) GetValue(TransitionModeProperty);
|
||||
set => SetValue(TransitionModeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TransitionStoryboardProperty = DependencyProperty.Register(
|
||||
"TransitionStoryboard", typeof(Storyboard), typeof(TransitioningContentControl), new PropertyMetadata(default(Storyboard)));
|
||||
|
||||
public Storyboard TransitionStoryboard
|
||||
{
|
||||
get => (Storyboard) GetValue(TransitionStoryboardProperty);
|
||||
set => SetValue(TransitionStoryboardProperty, value);
|
||||
}
|
||||
|
||||
private void TransitioningContentControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) => StartTransition();
|
||||
|
||||
private void TransitioningContentControl_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
IsVisibleChanged += TransitioningContentControl_IsVisibleChanged;
|
||||
}
|
||||
|
||||
private void TransitioningContentControl_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
IsVisibleChanged -= TransitioningContentControl_IsVisibleChanged;
|
||||
}
|
||||
|
||||
private void StartTransition()
|
||||
{
|
||||
if (_contentPresenter == null || !IsVisible) return;
|
||||
|
||||
if (TransitionStoryboard != null)
|
||||
{
|
||||
Loaded += TransitioningContentControl_Loaded;
|
||||
Unloaded += TransitioningContentControl_Unloaded;
|
||||
TransitionStoryboard.Begin(_contentPresenter);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TransitionModeProperty = DependencyProperty.Register(
|
||||
"TransitionMode", typeof(TransitionMode), typeof(TransitioningContentControl), new PropertyMetadata(default(TransitionMode), OnTransitionModeChanged));
|
||||
|
||||
private static void OnTransitionModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
else if (_storyboardBuildIn != null)
|
||||
{
|
||||
var ctl = (TransitioningContentControl) d;
|
||||
ctl.OnTransitionModeChanged((TransitionMode) e.NewValue);
|
||||
_storyboardBuildIn?.Begin(_contentPresenter);
|
||||
}
|
||||
|
||||
private void OnTransitionModeChanged(TransitionMode newValue)
|
||||
else
|
||||
{
|
||||
_storyboardBuildIn = ResourceHelper.GetResourceInternal<Storyboard>($"{newValue}Transition");
|
||||
StartTransition();
|
||||
}
|
||||
|
||||
public TransitionMode TransitionMode
|
||||
{
|
||||
get => (TransitionMode) GetValue(TransitionModeProperty);
|
||||
set => SetValue(TransitionModeProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TransitionStoryboardProperty = DependencyProperty.Register(
|
||||
"TransitionStoryboard", typeof(Storyboard), typeof(TransitioningContentControl), new PropertyMetadata(default(Storyboard)));
|
||||
|
||||
public Storyboard TransitionStoryboard
|
||||
{
|
||||
get => (Storyboard) GetValue(TransitionStoryboardProperty);
|
||||
set => SetValue(TransitionStoryboardProperty, value);
|
||||
}
|
||||
|
||||
private void TransitioningContentControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) => StartTransition();
|
||||
|
||||
private void TransitioningContentControl_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
StartTransition();
|
||||
IsVisibleChanged += TransitioningContentControl_IsVisibleChanged;
|
||||
}
|
||||
|
||||
private void TransitioningContentControl_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
IsVisibleChanged -= TransitioningContentControl_IsVisibleChanged;
|
||||
}
|
||||
|
||||
private void StartTransition()
|
||||
{
|
||||
if (!IsArrangeValid || _contentPresenter == null) return;
|
||||
|
||||
if (TransitionStoryboard != null)
|
||||
{
|
||||
TransitionStoryboard.Begin(_contentPresenter);
|
||||
}
|
||||
else if (_storyboardBuildIn != null)
|
||||
{
|
||||
_storyboardBuildIn?.Begin(_contentPresenter);
|
||||
}
|
||||
else
|
||||
{
|
||||
StoryboardBuildInDefault ??= ResourceHelper.GetResourceInternal<Storyboard>($"{default(TransitionMode)}Transition");
|
||||
StoryboardBuildInDefault?.Begin(_contentPresenter);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_contentPresenter = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;
|
||||
if (_contentPresenter != null)
|
||||
{
|
||||
_contentPresenter.RenderTransformOrigin = new Point(0.5, 0.5);
|
||||
_contentPresenter.RenderTransform = new TransformGroup
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new ScaleTransform(),
|
||||
new SkewTransform(),
|
||||
new RotateTransform(),
|
||||
new TranslateTransform()
|
||||
}
|
||||
};
|
||||
}
|
||||
StoryboardBuildInDefault ??= ResourceHelper.GetResourceInternal<Storyboard>($"{default(TransitionMode)}Transition");
|
||||
StoryboardBuildInDefault?.Begin(_contentPresenter);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_contentPresenter = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;
|
||||
if (_contentPresenter != null)
|
||||
{
|
||||
_contentPresenter.RenderTransformOrigin = new Point(0.5, 0.5);
|
||||
_contentPresenter.RenderTransform = new TransformGroup
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new ScaleTransform(),
|
||||
new SkewTransform(),
|
||||
new RotateTransform(),
|
||||
new TranslateTransform()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
StartTransition();
|
||||
}
|
||||
}
|
||||
@@ -5,161 +5,160 @@ using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
[TemplatePart(Name = ElementRoot, Type = typeof(Border))]
|
||||
[ContentProperty(nameof(Content))]
|
||||
public class Watermark : Control
|
||||
{
|
||||
[TemplatePart(Name = ElementRoot, Type = typeof(Border))]
|
||||
[ContentProperty(nameof(Content))]
|
||||
public class Watermark : Control
|
||||
private const string ElementRoot = "PART_Root";
|
||||
|
||||
private Border _borderRoot;
|
||||
|
||||
private DrawingBrush _brush;
|
||||
|
||||
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register(
|
||||
"Angle", typeof(double), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double Angle
|
||||
{
|
||||
private const string ElementRoot = "PART_Root";
|
||||
|
||||
private Border _borderRoot;
|
||||
|
||||
private DrawingBrush _brush;
|
||||
|
||||
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register(
|
||||
"Angle", typeof(double), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double Angle
|
||||
{
|
||||
get => (double) GetValue(AngleProperty);
|
||||
set => SetValue(AngleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
"Content", typeof(object), typeof(Watermark), new PropertyMetadata(default));
|
||||
|
||||
public object Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkProperty = DependencyProperty.Register(
|
||||
"Mark", typeof(object), typeof(Watermark), new FrameworkPropertyMetadata(default, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public object Mark
|
||||
{
|
||||
get => GetValue(MarkProperty);
|
||||
set => SetValue(MarkProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkWidthProperty = DependencyProperty.Register(
|
||||
"MarkWidth", typeof(double), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double MarkWidth
|
||||
{
|
||||
get => (double) GetValue(MarkWidthProperty);
|
||||
set => SetValue(MarkWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkHeightProperty = DependencyProperty.Register(
|
||||
"MarkHeight", typeof(double), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double MarkHeight
|
||||
{
|
||||
get => (double) GetValue(MarkHeightProperty);
|
||||
set => SetValue(MarkHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkBrushProperty = DependencyProperty.Register(
|
||||
"MarkBrush", typeof(Brush), typeof(Watermark), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Brush MarkBrush
|
||||
{
|
||||
get => (Brush) GetValue(MarkBrushProperty);
|
||||
set => SetValue(MarkBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AutoSizeEnabledProperty = DependencyProperty.Register(
|
||||
"AutoSizeEnabled", typeof(bool), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool AutoSizeEnabled
|
||||
{
|
||||
get => (bool) GetValue(AutoSizeEnabledProperty);
|
||||
set => SetValue(AutoSizeEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkMarginProperty = DependencyProperty.Register(
|
||||
"MarkMargin", typeof(Thickness), typeof(Watermark), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Thickness MarkMargin
|
||||
{
|
||||
get => (Thickness) GetValue(MarkMarginProperty);
|
||||
set => SetValue(MarkMarginProperty, value);
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate() => _borderRoot = GetTemplateChild(ElementRoot) as Border;
|
||||
|
||||
private void EnsureBrush()
|
||||
{
|
||||
var presenter = new ContentPresenter();
|
||||
|
||||
if (Mark is Geometry geometry)
|
||||
{
|
||||
presenter.Content = new Path
|
||||
{
|
||||
Width = MarkWidth,
|
||||
Height = MarkHeight,
|
||||
Fill = MarkBrush,
|
||||
Stretch = Stretch.Uniform,
|
||||
Data = geometry
|
||||
};
|
||||
}
|
||||
else if (Mark is string str)
|
||||
{
|
||||
presenter.Content = new TextBlock
|
||||
{
|
||||
Text = str,
|
||||
FontSize = FontSize,
|
||||
Foreground = MarkBrush
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
presenter.Content = Mark;
|
||||
}
|
||||
|
||||
Size markSize;
|
||||
if (AutoSizeEnabled)
|
||||
{
|
||||
presenter.Measure(new Size(double.MaxValue, double.MaxValue));
|
||||
markSize = presenter.DesiredSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
markSize = new Size(MarkWidth, MarkHeight);
|
||||
}
|
||||
|
||||
_brush = new DrawingBrush
|
||||
{
|
||||
ViewportUnits = BrushMappingMode.Absolute,
|
||||
Stretch = Stretch.Uniform,
|
||||
TileMode = TileMode.Tile,
|
||||
Transform = new RotateTransform(Angle),
|
||||
Drawing = new GeometryDrawing
|
||||
{
|
||||
Brush = new VisualBrush(new Border
|
||||
{
|
||||
Background = Brushes.Transparent,
|
||||
Padding = MarkMargin,
|
||||
Child = presenter
|
||||
}),
|
||||
Geometry = new RectangleGeometry(new Rect(markSize))
|
||||
},
|
||||
Viewport = new Rect(markSize)
|
||||
};
|
||||
|
||||
RenderOptions.SetCacheInvalidationThresholdMinimum(_brush, 0.5);
|
||||
RenderOptions.SetCacheInvalidationThresholdMaximum(_brush, 2);
|
||||
RenderOptions.SetCachingHint(_brush, CachingHint.Cache);
|
||||
|
||||
if (_borderRoot != null)
|
||||
{
|
||||
_borderRoot.Background = _brush;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext) => EnsureBrush();
|
||||
get => (double) GetValue(AngleProperty);
|
||||
set => SetValue(AngleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
|
||||
"Content", typeof(object), typeof(Watermark), new PropertyMetadata(default));
|
||||
|
||||
public object Content
|
||||
{
|
||||
get => GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkProperty = DependencyProperty.Register(
|
||||
"Mark", typeof(object), typeof(Watermark), new FrameworkPropertyMetadata(default, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public object Mark
|
||||
{
|
||||
get => GetValue(MarkProperty);
|
||||
set => SetValue(MarkProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkWidthProperty = DependencyProperty.Register(
|
||||
"MarkWidth", typeof(double), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double MarkWidth
|
||||
{
|
||||
get => (double) GetValue(MarkWidthProperty);
|
||||
set => SetValue(MarkWidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkHeightProperty = DependencyProperty.Register(
|
||||
"MarkHeight", typeof(double), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double MarkHeight
|
||||
{
|
||||
get => (double) GetValue(MarkHeightProperty);
|
||||
set => SetValue(MarkHeightProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkBrushProperty = DependencyProperty.Register(
|
||||
"MarkBrush", typeof(Brush), typeof(Watermark), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Brush MarkBrush
|
||||
{
|
||||
get => (Brush) GetValue(MarkBrushProperty);
|
||||
set => SetValue(MarkBrushProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty AutoSizeEnabledProperty = DependencyProperty.Register(
|
||||
"AutoSizeEnabled", typeof(bool), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool AutoSizeEnabled
|
||||
{
|
||||
get => (bool) GetValue(AutoSizeEnabledProperty);
|
||||
set => SetValue(AutoSizeEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MarkMarginProperty = DependencyProperty.Register(
|
||||
"MarkMargin", typeof(Thickness), typeof(Watermark), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Thickness MarkMargin
|
||||
{
|
||||
get => (Thickness) GetValue(MarkMarginProperty);
|
||||
set => SetValue(MarkMarginProperty, value);
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate() => _borderRoot = GetTemplateChild(ElementRoot) as Border;
|
||||
|
||||
private void EnsureBrush()
|
||||
{
|
||||
var presenter = new ContentPresenter();
|
||||
|
||||
if (Mark is Geometry geometry)
|
||||
{
|
||||
presenter.Content = new Path
|
||||
{
|
||||
Width = MarkWidth,
|
||||
Height = MarkHeight,
|
||||
Fill = MarkBrush,
|
||||
Stretch = Stretch.Uniform,
|
||||
Data = geometry
|
||||
};
|
||||
}
|
||||
else if (Mark is string str)
|
||||
{
|
||||
presenter.Content = new TextBlock
|
||||
{
|
||||
Text = str,
|
||||
FontSize = FontSize,
|
||||
Foreground = MarkBrush
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
presenter.Content = Mark;
|
||||
}
|
||||
|
||||
Size markSize;
|
||||
if (AutoSizeEnabled)
|
||||
{
|
||||
presenter.Measure(new Size(double.MaxValue, double.MaxValue));
|
||||
markSize = presenter.DesiredSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
markSize = new Size(MarkWidth, MarkHeight);
|
||||
}
|
||||
|
||||
_brush = new DrawingBrush
|
||||
{
|
||||
ViewportUnits = BrushMappingMode.Absolute,
|
||||
Stretch = Stretch.Uniform,
|
||||
TileMode = TileMode.Tile,
|
||||
Transform = new RotateTransform(Angle),
|
||||
Drawing = new GeometryDrawing
|
||||
{
|
||||
Brush = new VisualBrush(new Border
|
||||
{
|
||||
Background = Brushes.Transparent,
|
||||
Padding = MarkMargin,
|
||||
Child = presenter
|
||||
}),
|
||||
Geometry = new RectangleGeometry(new Rect(markSize))
|
||||
},
|
||||
Viewport = new Rect(markSize)
|
||||
};
|
||||
|
||||
RenderOptions.SetCacheInvalidationThresholdMinimum(_brush, 0.5);
|
||||
RenderOptions.SetCacheInvalidationThresholdMaximum(_brush, 2);
|
||||
RenderOptions.SetCachingHint(_brush, CachingHint.Cache);
|
||||
|
||||
if (_borderRoot != null)
|
||||
{
|
||||
_borderRoot.Background = _brush;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext) => EnsureBrush();
|
||||
}
|
||||
@@ -1,64 +1,63 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class AxleCanvas : Canvas
|
||||
{
|
||||
public class AxleCanvas : Canvas
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(AxleCanvas), new PropertyMetadata(default(Orientation)));
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||||
"Orientation", typeof(Orientation), typeof(AxleCanvas), new PropertyMetadata(default(Orientation)));
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
public Orientation Orientation
|
||||
protected override Size ArrangeOverride(Size arrangeSize)
|
||||
{
|
||||
foreach (UIElement internalChild in InternalChildren)
|
||||
{
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
if (internalChild == null) continue;
|
||||
|
||||
protected override Size ArrangeOverride(Size arrangeSize)
|
||||
{
|
||||
foreach (UIElement internalChild in InternalChildren)
|
||||
var x = 0.0;
|
||||
var y = 0.0;
|
||||
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
{
|
||||
if (internalChild == null) continue;
|
||||
x = (arrangeSize.Width - internalChild.DesiredSize.Width) / 2;
|
||||
|
||||
var x = 0.0;
|
||||
var y = 0.0;
|
||||
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
var top = GetTop(internalChild);
|
||||
if (!double.IsNaN(top))
|
||||
{
|
||||
x = (arrangeSize.Width - internalChild.DesiredSize.Width) / 2;
|
||||
|
||||
var top = GetTop(internalChild);
|
||||
if (!double.IsNaN(top))
|
||||
{
|
||||
y = top;
|
||||
}
|
||||
else
|
||||
{
|
||||
var bottom = GetBottom(internalChild);
|
||||
if (!double.IsNaN(bottom))
|
||||
y = arrangeSize.Height - internalChild.DesiredSize.Height - bottom;
|
||||
}
|
||||
y = top;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = (arrangeSize.Height - internalChild.DesiredSize.Height) / 2;
|
||||
|
||||
var left = GetLeft(internalChild);
|
||||
if (!double.IsNaN(left))
|
||||
{
|
||||
x = left;
|
||||
}
|
||||
else
|
||||
{
|
||||
var right = GetRight(internalChild);
|
||||
if (!double.IsNaN(right))
|
||||
x = arrangeSize.Width - internalChild.DesiredSize.Width - right;
|
||||
}
|
||||
var bottom = GetBottom(internalChild);
|
||||
if (!double.IsNaN(bottom))
|
||||
y = arrangeSize.Height - internalChild.DesiredSize.Height - bottom;
|
||||
}
|
||||
|
||||
internalChild.Arrange(new Rect(new Point(x, y), internalChild.DesiredSize));
|
||||
}
|
||||
return arrangeSize;
|
||||
else
|
||||
{
|
||||
y = (arrangeSize.Height - internalChild.DesiredSize.Height) / 2;
|
||||
|
||||
var left = GetLeft(internalChild);
|
||||
if (!double.IsNaN(left))
|
||||
{
|
||||
x = left;
|
||||
}
|
||||
else
|
||||
{
|
||||
var right = GetRight(internalChild);
|
||||
if (!double.IsNaN(right))
|
||||
x = arrangeSize.Width - internalChild.DesiredSize.Width - right;
|
||||
}
|
||||
}
|
||||
|
||||
internalChild.Arrange(new Rect(new Point(x, y), internalChild.DesiredSize));
|
||||
}
|
||||
return arrangeSize;
|
||||
}
|
||||
}
|
||||
@@ -4,87 +4,86 @@ using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class CirclePanel : Panel
|
||||
{
|
||||
public class CirclePanel : Panel
|
||||
public static readonly DependencyProperty DiameterProperty = DependencyProperty.Register(
|
||||
"Diameter", typeof(double), typeof(CirclePanel), new FrameworkPropertyMetadata(170.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
public double Diameter
|
||||
{
|
||||
public static readonly DependencyProperty DiameterProperty = DependencyProperty.Register(
|
||||
"Diameter", typeof(double), typeof(CirclePanel), new FrameworkPropertyMetadata(170.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
get => (double) GetValue(DiameterProperty);
|
||||
set => SetValue(DiameterProperty, value);
|
||||
}
|
||||
|
||||
public double Diameter
|
||||
public static readonly DependencyProperty KeepVerticalProperty = DependencyProperty.Register(
|
||||
"KeepVertical", typeof(bool), typeof(CirclePanel), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
public bool KeepVertical
|
||||
{
|
||||
get => (bool) GetValue(KeepVerticalProperty);
|
||||
set => SetValue(KeepVerticalProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty OffsetAngleProperty = DependencyProperty.Register(
|
||||
"OffsetAngle", typeof(double), typeof(CirclePanel), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
public double OffsetAngle
|
||||
{
|
||||
get => (double) GetValue(OffsetAngleProperty);
|
||||
set => SetValue(OffsetAngleProperty, value);
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var diameter = Diameter;
|
||||
|
||||
if (Children.Count == 0) return new Size(diameter, diameter);
|
||||
|
||||
var newSize = new Size(diameter, diameter);
|
||||
|
||||
foreach (UIElement element in Children)
|
||||
{
|
||||
get => (double) GetValue(DiameterProperty);
|
||||
set => SetValue(DiameterProperty, value);
|
||||
element.Measure(newSize);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty KeepVerticalProperty = DependencyProperty.Register(
|
||||
"KeepVertical", typeof(bool), typeof(CirclePanel), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
return newSize;
|
||||
}
|
||||
|
||||
public bool KeepVertical
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
var keepVertical = KeepVertical;
|
||||
var offsetAngle = OffsetAngle;
|
||||
|
||||
var i = 0;
|
||||
var perDeg = 360.0 / Children.Count;
|
||||
var radius = Diameter / 2;
|
||||
|
||||
foreach (UIElement element in Children)
|
||||
{
|
||||
get => (bool) GetValue(KeepVerticalProperty);
|
||||
set => SetValue(KeepVerticalProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
var centerX = element.DesiredSize.Width / 2.0;
|
||||
var centerY = element.DesiredSize.Height / 2.0;
|
||||
var angle = perDeg * i++ + offsetAngle;
|
||||
|
||||
public static readonly DependencyProperty OffsetAngleProperty = DependencyProperty.Register(
|
||||
"OffsetAngle", typeof(double), typeof(CirclePanel), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
public double OffsetAngle
|
||||
{
|
||||
get => (double) GetValue(OffsetAngleProperty);
|
||||
set => SetValue(OffsetAngleProperty, value);
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
var diameter = Diameter;
|
||||
|
||||
if (Children.Count == 0) return new Size(diameter, diameter);
|
||||
|
||||
var newSize = new Size(diameter, diameter);
|
||||
|
||||
foreach (UIElement element in Children)
|
||||
var transform = new RotateTransform
|
||||
{
|
||||
element.Measure(newSize);
|
||||
}
|
||||
CenterX = centerX,
|
||||
CenterY = centerY,
|
||||
Angle = keepVertical ? 0 : angle
|
||||
};
|
||||
element.RenderTransform = transform;
|
||||
|
||||
return newSize;
|
||||
var r = Math.PI * angle / 180.0;
|
||||
var x = radius * Math.Cos(r);
|
||||
var y = radius * Math.Sin(r);
|
||||
|
||||
var rectX = x + finalSize.Width / 2 - centerX;
|
||||
var rectY = y + finalSize.Height / 2 - centerY;
|
||||
|
||||
element.Arrange(new Rect(rectX, rectY, element.DesiredSize.Width, element.DesiredSize.Height));
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
var keepVertical = KeepVertical;
|
||||
var offsetAngle = OffsetAngle;
|
||||
|
||||
var i = 0;
|
||||
var perDeg = 360.0 / Children.Count;
|
||||
var radius = Diameter / 2;
|
||||
|
||||
foreach (UIElement element in Children)
|
||||
{
|
||||
var centerX = element.DesiredSize.Width / 2.0;
|
||||
var centerY = element.DesiredSize.Height / 2.0;
|
||||
var angle = perDeg * i++ + offsetAngle;
|
||||
|
||||
var transform = new RotateTransform
|
||||
{
|
||||
CenterX = centerX,
|
||||
CenterY = centerY,
|
||||
Angle = keepVertical ? 0 : angle
|
||||
};
|
||||
element.RenderTransform = transform;
|
||||
|
||||
var r = Math.PI * angle / 180.0;
|
||||
var x = radius * Math.Cos(r);
|
||||
var y = radius * Math.Sin(r);
|
||||
|
||||
var rectX = x + finalSize.Width / 2 - centerX;
|
||||
var rectY = y + finalSize.Height / 2 - centerY;
|
||||
|
||||
element.Arrange(new Rect(rectX, rectY, element.DesiredSize.Width, element.DesiredSize.Height));
|
||||
}
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
return finalSize;
|
||||
}
|
||||
}
|
||||
@@ -1,120 +1,152 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
namespace HandyControl.Controls;
|
||||
|
||||
public class ElementGroup : ItemsControl
|
||||
{
|
||||
public class ElementGroup : SimpleStackPanel
|
||||
private static readonly Dictionary<Orientation, Dictionary<ChildLocation, CornerRadius>> CornerRadiusDict;
|
||||
|
||||
public static readonly DependencyProperty OrientationProperty =
|
||||
StackPanel.OrientationProperty.AddOwner(typeof(ElementGroup),
|
||||
new FrameworkPropertyMetadata(ValueBoxes.HorizontalBox, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
private static readonly Dictionary<Orientation, Dictionary<ChildLocation, CornerRadius>> CornerRadiusDict;
|
||||
get => (Orientation) GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, ValueBoxes.OrientationBox(value));
|
||||
}
|
||||
|
||||
static ElementGroup()
|
||||
public static readonly DependencyProperty LayoutProperty = DependencyProperty.Register(
|
||||
"Layout", typeof(LinearLayout), typeof(ElementGroup),
|
||||
new FrameworkPropertyMetadata(LinearLayout.Uniform, FrameworkPropertyMetadataOptions.AffectsMeasure));
|
||||
|
||||
public LinearLayout Layout
|
||||
{
|
||||
get => (LinearLayout) GetValue(LayoutProperty);
|
||||
set => SetValue(LayoutProperty, value);
|
||||
}
|
||||
|
||||
static ElementGroup()
|
||||
{
|
||||
var defaultCornerRadius = ResourceHelper.GetResourceInternal<CornerRadius>("DefaultCornerRadius");
|
||||
|
||||
CornerRadiusDict = new Dictionary<Orientation, Dictionary<ChildLocation, CornerRadius>>
|
||||
{
|
||||
var defaultCornerRadius = ResourceHelper.GetResourceInternal<CornerRadius>("DefaultCornerRadius");
|
||||
|
||||
CornerRadiusDict = new Dictionary<Orientation, Dictionary<ChildLocation, CornerRadius>>
|
||||
[Orientation.Horizontal] = new()
|
||||
{
|
||||
[Orientation.Horizontal] = new()
|
||||
{
|
||||
[ChildLocation.Single] = defaultCornerRadius,
|
||||
[ChildLocation.First] = new CornerRadius(defaultCornerRadius.TopLeft, 0, 0, defaultCornerRadius.BottomLeft),
|
||||
[ChildLocation.Middle] = new CornerRadius(),
|
||||
[ChildLocation.Last] = new CornerRadius(0, defaultCornerRadius.TopRight, defaultCornerRadius.BottomRight, 0)
|
||||
},
|
||||
[Orientation.Vertical] = new()
|
||||
{
|
||||
[ChildLocation.Single] = defaultCornerRadius,
|
||||
[ChildLocation.First] = new CornerRadius(defaultCornerRadius.TopLeft, defaultCornerRadius.TopRight, 0, 0),
|
||||
[ChildLocation.Middle] = new CornerRadius(),
|
||||
[ChildLocation.Last] = new CornerRadius(0, 0, defaultCornerRadius.BottomRight, defaultCornerRadius.BottomLeft)
|
||||
}
|
||||
};
|
||||
[ChildLocation.Single] = defaultCornerRadius,
|
||||
[ChildLocation.First] = new CornerRadius(defaultCornerRadius.TopLeft, 0, 0, defaultCornerRadius.BottomLeft),
|
||||
[ChildLocation.Middle] = new CornerRadius(),
|
||||
[ChildLocation.Last] = new CornerRadius(0, defaultCornerRadius.TopRight, defaultCornerRadius.BottomRight, 0)
|
||||
},
|
||||
[Orientation.Vertical] = new()
|
||||
{
|
||||
[ChildLocation.Single] = defaultCornerRadius,
|
||||
[ChildLocation.First] = new CornerRadius(defaultCornerRadius.TopLeft, defaultCornerRadius.TopRight, 0, 0),
|
||||
[ChildLocation.Middle] = new CornerRadius(),
|
||||
[ChildLocation.Last] = new CornerRadius(0, 0, defaultCornerRadius.BottomRight, defaultCornerRadius.BottomLeft)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
|
||||
{
|
||||
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
|
||||
|
||||
if (visualAdded is UIElement elementAdded)
|
||||
{
|
||||
elementAdded.GotFocus += ElementAdded_GotFocus;
|
||||
elementAdded.LostFocus += ElementAdded_LostFocus;
|
||||
elementAdded.IsVisibleChanged += ElementAdded_IsVisibleChanged;
|
||||
}
|
||||
|
||||
protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
|
||||
if (visualRemoved is UIElement elementRemoved)
|
||||
{
|
||||
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
|
||||
|
||||
if (visualAdded is UIElement elementAdded)
|
||||
{
|
||||
elementAdded.GotFocus += ElementAdded_GotFocus;
|
||||
elementAdded.LostFocus += ElementAdded_LostFocus;
|
||||
}
|
||||
|
||||
if (visualRemoved is UIElement elementRemoved)
|
||||
{
|
||||
elementRemoved.GotFocus -= ElementAdded_GotFocus;
|
||||
elementRemoved.LostFocus -= ElementAdded_LostFocus;
|
||||
}
|
||||
|
||||
var childrenCount = InternalChildren.Count;
|
||||
if (childrenCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var orientation = Orientation;
|
||||
|
||||
if (childrenCount == 1)
|
||||
{
|
||||
UpdateChildCornerRadius(InternalChildren[0], CornerRadiusDict[orientation][ChildLocation.Single]);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateChildCornerRadius(InternalChildren[0], CornerRadiusDict[orientation][ChildLocation.First]);
|
||||
|
||||
var childMargin = orientation == Orientation.Horizontal
|
||||
? new Thickness(-1, 0, 0, 0)
|
||||
: new Thickness(0, -1, 0, 0);
|
||||
|
||||
for (var childIndex = 1; childIndex < childrenCount; childIndex++)
|
||||
{
|
||||
var child = InternalChildren[childIndex];
|
||||
child.SetCurrentValue(MarginProperty, childMargin);
|
||||
UpdateChildCornerRadius(child, CornerRadiusDict[orientation][ChildLocation.Middle]);
|
||||
}
|
||||
|
||||
var lastChild = InternalChildren[childrenCount - 1];
|
||||
lastChild.SetCurrentValue(MarginProperty, childMargin);
|
||||
UpdateChildCornerRadius(lastChild, CornerRadiusDict[orientation][ChildLocation.Last]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateChildCornerRadius(DependencyObject child, CornerRadius cornerRadius)
|
||||
{
|
||||
if (child is Border border)
|
||||
{
|
||||
border.SetCurrentValue(Border.CornerRadiusProperty, cornerRadius);
|
||||
}
|
||||
else
|
||||
{
|
||||
BorderElement.SetCornerRadius(child, cornerRadius);
|
||||
}
|
||||
}
|
||||
|
||||
private void ElementAdded_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is UIElement element)
|
||||
{
|
||||
SetZIndex(element, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void ElementAdded_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is UIElement element)
|
||||
{
|
||||
SetZIndex(element, int.MaxValue);
|
||||
}
|
||||
}
|
||||
|
||||
private enum ChildLocation
|
||||
{
|
||||
Single,
|
||||
First,
|
||||
Middle,
|
||||
Last
|
||||
elementRemoved.GotFocus -= ElementAdded_GotFocus;
|
||||
elementRemoved.LostFocus -= ElementAdded_LostFocus;
|
||||
elementRemoved.IsVisibleChanged -= ElementAdded_IsVisibleChanged;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) => UpdateChildrenCornerRadius();
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext) => UpdateChildrenCornerRadius();
|
||||
|
||||
private void UpdateChildrenCornerRadius()
|
||||
{
|
||||
var visibleChildren = GetVisibleChildrenCount();
|
||||
var count = visibleChildren.Count;
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var orientation = Orientation;
|
||||
|
||||
if (count == 1)
|
||||
{
|
||||
UpdateChildCornerRadius(visibleChildren[0], CornerRadiusDict[orientation][ChildLocation.Single]);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateChildCornerRadius(visibleChildren[0], CornerRadiusDict[orientation][ChildLocation.First]);
|
||||
|
||||
var childMargin = orientation == Orientation.Horizontal
|
||||
? new Thickness(-1, 0, 0, 0)
|
||||
: new Thickness(0, -1, 0, 0);
|
||||
|
||||
for (var childIndex = 1; childIndex < count; childIndex++)
|
||||
{
|
||||
var child = visibleChildren[childIndex];
|
||||
child.SetCurrentValue(MarginProperty, childMargin);
|
||||
UpdateChildCornerRadius(child, CornerRadiusDict[orientation][ChildLocation.Middle]);
|
||||
}
|
||||
|
||||
var lastChild = visibleChildren[count - 1];
|
||||
lastChild.SetCurrentValue(MarginProperty, childMargin);
|
||||
UpdateChildCornerRadius(lastChild, CornerRadiusDict[orientation][ChildLocation.Last]);
|
||||
}
|
||||
}
|
||||
|
||||
private List<UIElement> GetVisibleChildrenCount()
|
||||
{
|
||||
return Items.OfType<UIElement>().Where(element => element.Visibility == Visibility.Visible).ToList();
|
||||
}
|
||||
|
||||
private static void UpdateChildCornerRadius(DependencyObject child, CornerRadius cornerRadius)
|
||||
{
|
||||
if (child is Border border)
|
||||
{
|
||||
border.SetCurrentValue(Border.CornerRadiusProperty, cornerRadius);
|
||||
}
|
||||
else
|
||||
{
|
||||
BorderElement.SetCornerRadius(child, cornerRadius);
|
||||
}
|
||||
}
|
||||
|
||||
private void ElementAdded_LostFocus(object sender, RoutedEventArgs e) => ResetElementZIndex(e.OriginalSource);
|
||||
|
||||
private void ElementAdded_GotFocus(object sender, RoutedEventArgs e) => MaximizeElementZIndex(e.OriginalSource);
|
||||
|
||||
private static void ResetElementZIndex(object element) => Panel.SetZIndex((UIElement) element, 0);
|
||||
|
||||
private static void MaximizeElementZIndex(object element) => Panel.SetZIndex((UIElement) element, int.MaxValue);
|
||||
|
||||
private void ElementAdded_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) => UpdateChildrenCornerRadius();
|
||||
|
||||
private enum ChildLocation
|
||||
{
|
||||
Single,
|
||||
First,
|
||||
Middle,
|
||||
Last
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Loaded 100 of 986 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user