更新
This commit is contained in:
813
WPFDark/Controls/BiaComboBox.xaml.cs
Normal file
813
WPFDark/Controls/BiaComboBox.xaml.cs
Normal file
@@ -0,0 +1,813 @@
|
||||
using WPFDark.Internals;
|
||||
|
||||
using Jewelry.Memory;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Effects;
|
||||
using System.Windows.Threading;
|
||||
|
||||
|
||||
namespace WPFDark.Controls
|
||||
{
|
||||
public class BiaComboBox : FrameworkElement
|
||||
{
|
||||
#region Background
|
||||
|
||||
public Brush? Background
|
||||
{
|
||||
get => _Background;
|
||||
set
|
||||
{
|
||||
if (value != _Background)
|
||||
SetValue(BackgroundProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private Brush? _Background;
|
||||
|
||||
public static readonly DependencyProperty BackgroundProperty =
|
||||
DependencyProperty.Register(nameof(Background), typeof(Brush), typeof(BiaComboBox),
|
||||
new FrameworkPropertyMetadata(
|
||||
default(Brush),
|
||||
FrameworkPropertyMetadataOptions.AffectsRender |
|
||||
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._Background = (Brush)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Foreground
|
||||
|
||||
public Brush? Foreground
|
||||
{
|
||||
get => _Foreground;
|
||||
set
|
||||
{
|
||||
if (value != _Foreground)
|
||||
SetValue(ForegroundProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private Brush? _Foreground;
|
||||
|
||||
public static readonly DependencyProperty ForegroundProperty =
|
||||
DependencyProperty.Register(nameof(Foreground), typeof(Brush), typeof(BiaComboBox),
|
||||
new FrameworkPropertyMetadata(
|
||||
default(Brush),
|
||||
FrameworkPropertyMetadataOptions.AffectsRender |
|
||||
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._Foreground = (Brush)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region BorderColor
|
||||
|
||||
public ByteColor BorderColor
|
||||
{
|
||||
get => _BorderColor;
|
||||
set
|
||||
{
|
||||
if (value != _BorderColor)
|
||||
SetValue(BorderColorProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private ByteColor _BorderColor = ByteColor.Red;
|
||||
|
||||
public static readonly DependencyProperty BorderColorProperty =
|
||||
DependencyProperty.Register(nameof(BorderColor), typeof(ByteColor), typeof(BiaComboBox),
|
||||
new FrameworkPropertyMetadata(
|
||||
Boxes.ByteColorRed,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender |
|
||||
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._BorderColor = (ByteColor)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region CornerRadius
|
||||
|
||||
public double CornerRadius
|
||||
{
|
||||
get => _CornerRadius;
|
||||
set
|
||||
{
|
||||
if (NumberHelper.AreClose(value, _CornerRadius) == false)
|
||||
SetValue(CornerRadiusProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private double _CornerRadius;
|
||||
|
||||
public static readonly DependencyProperty CornerRadiusProperty =
|
||||
DependencyProperty.Register(nameof(CornerRadius), typeof(double), typeof(BiaComboBox),
|
||||
new FrameworkPropertyMetadata(
|
||||
0.0,
|
||||
FrameworkPropertyMetadataOptions.AffectsRender |
|
||||
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._CornerRadius = (double)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region ItemsSource
|
||||
|
||||
public IEnumerable? ItemsSource
|
||||
{
|
||||
get => _ItemsSource;
|
||||
set
|
||||
{
|
||||
// ReSharper disable once PossibleUnintendedReferenceComparison
|
||||
if (value != _ItemsSource)
|
||||
SetValue(ItemsSourceProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable? _ItemsSource;
|
||||
|
||||
public static readonly DependencyProperty ItemsSourceProperty =
|
||||
DependencyProperty.Register(nameof(ItemsSource), typeof(IEnumerable), typeof(BiaComboBox),
|
||||
new FrameworkPropertyMetadata(
|
||||
default(IEnumerable),
|
||||
FrameworkPropertyMetadataOptions.AffectsRender |
|
||||
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._ItemsSource = (IEnumerable)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region SelectedItem
|
||||
|
||||
public object? SelectedItem
|
||||
{
|
||||
get => _SelectedItem;
|
||||
set
|
||||
{
|
||||
if (value != _SelectedItem)
|
||||
SetValue(SelectedItemProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private object? _SelectedItem;
|
||||
|
||||
public static readonly DependencyProperty SelectedItemProperty =
|
||||
DependencyProperty.Register(nameof(SelectedItem), typeof(object), typeof(BiaComboBox),
|
||||
new FrameworkPropertyMetadata(
|
||||
default,
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault |
|
||||
FrameworkPropertyMetadataOptions.AffectsRender |
|
||||
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._SelectedItem = e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region MarkBrush
|
||||
|
||||
public Brush? MarkBrush
|
||||
{
|
||||
get => _MarkBrush;
|
||||
set
|
||||
{
|
||||
if (value != _MarkBrush)
|
||||
SetValue(MarkBrushProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private Brush? _MarkBrush;
|
||||
|
||||
public static readonly DependencyProperty MarkBrushProperty =
|
||||
DependencyProperty.Register(nameof(MarkBrush), typeof(Brush), typeof(BiaComboBox),
|
||||
new FrameworkPropertyMetadata(
|
||||
default(Brush),
|
||||
FrameworkPropertyMetadataOptions.AffectsRender |
|
||||
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._MarkBrush = (Brush)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsOpen
|
||||
|
||||
public bool IsOpen
|
||||
{
|
||||
get => _IsOpen;
|
||||
set
|
||||
{
|
||||
if (value != _IsOpen)
|
||||
SetValue(IsOpenProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsOpen;
|
||||
|
||||
public static readonly DependencyProperty IsOpenProperty =
|
||||
DependencyProperty.Register(nameof(IsOpen), typeof(bool), typeof(BiaComboBox),
|
||||
new PropertyMetadata(
|
||||
false,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._IsOpen = (bool)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region ItemToStringConverter
|
||||
|
||||
public IValueConverter? ItemToStringConverter
|
||||
{
|
||||
get => _ItemToStringConverter;
|
||||
set
|
||||
{
|
||||
if (value != _ItemToStringConverter)
|
||||
SetValue(ItemToStringConverterProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private IValueConverter? _ItemToStringConverter;
|
||||
|
||||
public static readonly DependencyProperty ItemToStringConverterProperty =
|
||||
DependencyProperty.Register(nameof(ItemToStringConverter), typeof(IValueConverter), typeof(BiaComboBox),
|
||||
new PropertyMetadata(
|
||||
default(IValueConverter),
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._ItemToStringConverter = (IValueConverter)e.NewValue;
|
||||
self._isReqUpdateListBoxItemTemplate = true;
|
||||
}));
|
||||
|
||||
private bool _isReqUpdateListBoxItemTemplate = true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ItemToStringConverterParameter
|
||||
|
||||
public object? ItemToStringConverterParameter
|
||||
{
|
||||
get => _ItemToStringConverterParameter;
|
||||
set
|
||||
{
|
||||
if (value != _ItemToStringConverterParameter)
|
||||
SetValue(ItemToStringConverterParameterProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private object? _ItemToStringConverterParameter;
|
||||
|
||||
public static readonly DependencyProperty ItemToStringConverterParameterProperty =
|
||||
DependencyProperty.Register(nameof(ItemToStringConverterParameter), typeof(object), typeof(BiaComboBox),
|
||||
new PropertyMetadata(
|
||||
default,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._ItemToStringConverterParameter = e.NewValue;
|
||||
self._isReqUpdateListBoxItemTemplate = true;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region StartedContinuousEditingCommand
|
||||
|
||||
public ICommand? StartedContinuousEditingCommand
|
||||
{
|
||||
get => _StartedContinuousEditingCommand;
|
||||
set
|
||||
{
|
||||
if (value != _StartedContinuousEditingCommand)
|
||||
SetValue(StartedContinuousEditingCommandProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand? _StartedContinuousEditingCommand;
|
||||
|
||||
public static readonly DependencyProperty StartedContinuousEditingCommandProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(StartedContinuousEditingCommand),
|
||||
typeof(ICommand),
|
||||
typeof(BiaComboBox),
|
||||
new PropertyMetadata(
|
||||
default(ICommand),
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._StartedContinuousEditingCommand = (ICommand)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region EndContinuousEditingCommand
|
||||
|
||||
public ICommand? EndContinuousEditingCommand
|
||||
{
|
||||
get => _EndContinuousEditingCommand;
|
||||
set
|
||||
{
|
||||
if (value != _EndContinuousEditingCommand)
|
||||
SetValue(EndContinuousEditingCommandProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand? _EndContinuousEditingCommand;
|
||||
|
||||
public static readonly DependencyProperty EndContinuousEditingCommandProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(EndContinuousEditingCommand),
|
||||
typeof(ICommand),
|
||||
typeof(BiaComboBox),
|
||||
new PropertyMetadata(
|
||||
default(ICommand),
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._EndContinuousEditingCommand = (ICommand)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
#region TextTrimming
|
||||
|
||||
public BiaTextTrimmingMode TextTrimming
|
||||
{
|
||||
get => _TextTrimming;
|
||||
set
|
||||
{
|
||||
if (value != _TextTrimming)
|
||||
SetValue(TextTrimmingProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private BiaTextTrimmingMode _TextTrimming = BiaTextTrimmingMode.Standard;
|
||||
|
||||
public static readonly DependencyProperty TextTrimmingProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(TextTrimming),
|
||||
typeof(BiaTextTrimmingMode),
|
||||
typeof(BiaComboBox),
|
||||
new FrameworkPropertyMetadata(
|
||||
BiaTextTrimmingMode.Standard,
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault |
|
||||
FrameworkPropertyMetadataOptions.AffectsRender |
|
||||
FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender,
|
||||
(s, e) =>
|
||||
{
|
||||
var self = (BiaComboBox)s;
|
||||
self._TextTrimming = (BiaTextTrimmingMode)e.NewValue;
|
||||
}));
|
||||
|
||||
#endregion
|
||||
|
||||
static BiaComboBox()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(BiaComboBox),
|
||||
new FrameworkPropertyMetadata(typeof(BiaComboBox)));
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
{
|
||||
if (ActualWidth <= 1 ||
|
||||
ActualHeight <= 1)
|
||||
return;
|
||||
|
||||
var rounder = new LayoutRounder(this);
|
||||
|
||||
DrawBackground(rounder, dc);
|
||||
|
||||
var isCornerRadiusZero = NumberHelper.AreCloseZero(CornerRadius);
|
||||
|
||||
if (isCornerRadiusZero == false)
|
||||
dc.PushClip(
|
||||
Caches.GetClipGeom(rounder, ActualWidth, ActualHeight, CornerRadius, true));
|
||||
{
|
||||
var displayItem = ItemToStringConverter?.Convert(SelectedItem, typeof(string),
|
||||
ItemToStringConverterParameter, CultureInfo.CurrentUICulture)
|
||||
?? SelectedItem;
|
||||
|
||||
if (displayItem != null)
|
||||
if (Foreground != null)
|
||||
DefaultTextRenderer.Instance.Draw(
|
||||
this,
|
||||
displayItem.ToString(),
|
||||
5d, 4d,
|
||||
Foreground,
|
||||
dc,
|
||||
(1d, ActualWidth - 24d).Max(), // ▼分の幅を引く
|
||||
TextAlignment.Left,
|
||||
TextTrimming,
|
||||
true);
|
||||
}
|
||||
if (isCornerRadiusZero == false)
|
||||
dc.Pop();
|
||||
|
||||
// マーク
|
||||
{
|
||||
var offset = new TranslateTransform(ActualWidth - 15d, 10.5d);
|
||||
|
||||
dc.PushTransform(offset);
|
||||
dc.DrawGeometry(MarkBrush, null, MarkGeom);
|
||||
dc.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBackground(in LayoutRounder rounder, DrawingContext dc)
|
||||
{
|
||||
if (NumberHelper.AreCloseZero(CornerRadius))
|
||||
dc.DrawRectangle(
|
||||
Background,
|
||||
rounder.GetBorderPen(BorderColor),
|
||||
rounder.RoundRenderRectangle(true));
|
||||
else
|
||||
dc.DrawRoundedRectangle(
|
||||
Background,
|
||||
rounder.GetBorderPen(BorderColor),
|
||||
rounder.RoundRenderRectangle(true),
|
||||
CornerRadius,
|
||||
CornerRadius);
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonDown(e);
|
||||
|
||||
if (IsEnabled == false)
|
||||
return;
|
||||
|
||||
if (IsOpen)
|
||||
{
|
||||
Discard();
|
||||
Dispatcher?.BeginInvoke(DispatcherPriority.Input, FocusThis);
|
||||
}
|
||||
else
|
||||
{
|
||||
Focus();
|
||||
|
||||
_ContinuousEditingStartValue = SelectedItem;
|
||||
ShowPopup();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyDown(e);
|
||||
|
||||
if (IsEnabled == false)
|
||||
return;
|
||||
|
||||
if (e.Key == Key.Up)
|
||||
MoveSelectedItem(-1);
|
||||
|
||||
else if (e.Key == Key.Down)
|
||||
MoveSelectedItem(+1);
|
||||
|
||||
Dispatcher?.BeginInvoke(DispatcherPriority.Input, FocusThis);
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private bool _isDoesFindParent;
|
||||
private bool _hasScrollViewerParent;
|
||||
|
||||
protected override void OnMouseWheel(MouseWheelEventArgs e)
|
||||
{
|
||||
base.OnMouseWheel(e);
|
||||
|
||||
if (IsEnabled == false)
|
||||
return;
|
||||
|
||||
if (_isDoesFindParent == false)
|
||||
{
|
||||
_hasScrollViewerParent = this.GetParent<ScrollViewer>() != null;
|
||||
_isDoesFindParent = true;
|
||||
}
|
||||
|
||||
// スクロール操作と混同するため、
|
||||
// 親にスクロールビューワーが存在すればホイール操作を無効にする
|
||||
if (_hasScrollViewerParent)
|
||||
return;
|
||||
|
||||
if (e.Delta > 0)
|
||||
MoveSelectedItem(-1);
|
||||
|
||||
else if (e.Delta < 0)
|
||||
MoveSelectedItem(+1);
|
||||
|
||||
Dispatcher?.BeginInvoke(DispatcherPriority.Input, FocusThis);
|
||||
}
|
||||
|
||||
private ListBox? _items;
|
||||
private Popup? _popup;
|
||||
private ScaleTransform? _scale;
|
||||
|
||||
private void ShowPopup()
|
||||
{
|
||||
if (_popup is null)
|
||||
{
|
||||
_items = new ListBox
|
||||
{
|
||||
IsTabStop = false,
|
||||
FocusVisualStyle = null,
|
||||
Margin = new Thickness(0, 0, 3, 3),
|
||||
Effect = new DropShadowEffect
|
||||
{
|
||||
ShadowDepth = 2,
|
||||
Color = Colors.Black
|
||||
}
|
||||
};
|
||||
|
||||
_scale = new ScaleTransform();
|
||||
|
||||
_popup = new Popup
|
||||
{
|
||||
Child = _items,
|
||||
AllowsTransparency = true,
|
||||
VerticalOffset = 1,
|
||||
StaysOpen = false,
|
||||
Focusable = false,
|
||||
RenderTransform = _scale,
|
||||
HorizontalOffset = -2,
|
||||
PlacementTarget = this
|
||||
};
|
||||
|
||||
_items.SetBinding(ItemsControl.ItemsSourceProperty,
|
||||
new Binding(nameof(ItemsSource))
|
||||
{
|
||||
Source = this,
|
||||
Mode = BindingMode.TwoWay
|
||||
});
|
||||
_items.SetBinding(Selector.SelectedItemProperty,
|
||||
new Binding(nameof(SelectedItem))
|
||||
{
|
||||
Source = this,
|
||||
Mode = BindingMode.TwoWay
|
||||
});
|
||||
_items.PreviewKeyDown += ListBoxOnPreviewKeyDown;
|
||||
_items.PreviewMouseLeftButtonDown += ListBoxOnPreviewMouseLeftButtonDown;
|
||||
|
||||
_popup.Closed += PopupOnClosed;
|
||||
}
|
||||
|
||||
Debug.Assert(_items != null);
|
||||
Debug.Assert(_scale != null);
|
||||
|
||||
if (_isReqUpdateListBoxItemTemplate)
|
||||
{
|
||||
_isReqUpdateListBoxItemTemplate = false;
|
||||
SetupListBoxItemTemplate();
|
||||
}
|
||||
|
||||
_items.Width = ActualWidth;
|
||||
|
||||
Mouse.Capture(this, CaptureMode.SubTree);
|
||||
|
||||
var s = this.CalcCompositeRenderScale();
|
||||
_scale.ScaleX = s;
|
||||
_scale.ScaleY = s;
|
||||
|
||||
_popup.IsOpen = true;
|
||||
IsOpen = true;
|
||||
|
||||
if (_items.SelectedItem is null)
|
||||
{
|
||||
_items.Focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
var item = _items.ItemContainerGenerator.ContainerFromItem(_items.SelectedItem) as ListBoxItem;
|
||||
item?.Focus();
|
||||
|
||||
// 選択アイテム位置にスクロール
|
||||
{
|
||||
var sv = _items.Descendants().OfType<ScrollViewer>().FirstOrDefault();
|
||||
|
||||
if (sv != null)
|
||||
{
|
||||
var offset = (double)_items.Items.IndexOf(_items.SelectedItem);
|
||||
|
||||
if (offset > sv.ScrollableHeight)
|
||||
offset = sv.ScrollableHeight;
|
||||
|
||||
sv.ScrollToVerticalOffset(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var listBoxBorder = _items.Descendants().OfType<Border>().First();
|
||||
listBoxBorder.BorderBrush = (Brush)ThemeManager.Current.TryFindResource("Item.SelectedActive.Border");
|
||||
|
||||
StartedContinuousEditingCommand?.ExecuteIfCan(null);
|
||||
}
|
||||
|
||||
private void SetupListBoxItemTemplate()
|
||||
{
|
||||
Debug.Assert(_items != null);
|
||||
|
||||
var itemTemplate = new DataTemplate();
|
||||
{
|
||||
var textBlock = new FrameworkElementFactory(typeof(BiaTextBlock));
|
||||
|
||||
textBlock.SetBinding(
|
||||
BiaTextBlock.TextProperty,
|
||||
new Binding
|
||||
{
|
||||
Converter = ItemToStringConverter,
|
||||
ConverterParameter = ItemToStringConverterParameter,
|
||||
ConverterCulture = CultureInfo.CurrentUICulture,
|
||||
});
|
||||
|
||||
itemTemplate.VisualTree = textBlock;
|
||||
}
|
||||
|
||||
_items.ItemTemplate = itemTemplate;
|
||||
}
|
||||
|
||||
private void ListBoxOnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var lb = (ListBox)sender;
|
||||
|
||||
var pos = Mouse.GetPosition(lb);
|
||||
var hit = VisualTreeHelper.HitTest(lb, pos);
|
||||
|
||||
var parent = (hit?.VisualHit as FrameworkElement)?.TemplatedParent;
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
if (parent.GetType() == typeof(ScrollBar))
|
||||
return;
|
||||
|
||||
parent = (parent as FrameworkElement)?.TemplatedParent;
|
||||
}
|
||||
|
||||
SetValue();
|
||||
|
||||
Dispatcher?.BeginInvoke(DispatcherPriority.Input, FocusThis);
|
||||
}
|
||||
|
||||
// ReSharper disable once ConvertToNullCoalescingCompoundAssignment
|
||||
private Action FocusThis => _FocusThis ?? (_FocusThis = () => Focus());
|
||||
|
||||
private Action? _FocusThis;
|
||||
|
||||
private void ListBoxOnPreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (IsEnabled == false)
|
||||
return;
|
||||
|
||||
if (IsOpen == false)
|
||||
return;
|
||||
|
||||
if (e.Key == Key.Escape)
|
||||
{
|
||||
Discard();
|
||||
Focus();
|
||||
}
|
||||
|
||||
if (e.Key == Key.Return)
|
||||
{
|
||||
SetValue();
|
||||
Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private void PopupOnClosed(object? sender, EventArgs e)
|
||||
{
|
||||
IsOpen = false;
|
||||
}
|
||||
|
||||
private object? _ContinuousEditingStartValue;
|
||||
|
||||
private void SetValue()
|
||||
{
|
||||
Debug.Assert(_popup != null);
|
||||
|
||||
if (EndContinuousEditingCommand != null)
|
||||
{
|
||||
if (EndContinuousEditingCommand.CanExecute(null))
|
||||
{
|
||||
var changedValue = SelectedItem;
|
||||
SelectedItem = _ContinuousEditingStartValue;
|
||||
|
||||
EndContinuousEditingCommand.Execute(null);
|
||||
|
||||
SelectedItem = changedValue;
|
||||
}
|
||||
}
|
||||
|
||||
Mouse.Capture(null);
|
||||
_popup.IsOpen = false;
|
||||
}
|
||||
|
||||
private void Discard()
|
||||
{
|
||||
Debug.Assert(_popup != null);
|
||||
|
||||
var done = false;
|
||||
|
||||
if (EndContinuousEditingCommand != null)
|
||||
{
|
||||
if (EndContinuousEditingCommand.CanExecute(null))
|
||||
{
|
||||
SelectedItem = _ContinuousEditingStartValue;
|
||||
|
||||
EndContinuousEditingCommand.Execute(null);
|
||||
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (done == false)
|
||||
SelectedItem = _ContinuousEditingStartValue;
|
||||
|
||||
Mouse.Capture(null);
|
||||
_popup.IsOpen = false;
|
||||
}
|
||||
|
||||
//[SuppressMessage("ReSharper", "PossiblyImpureMethodCallOnReadonlyVariable")]
|
||||
private void MoveSelectedItem(int dir)
|
||||
{
|
||||
if (ItemsSource is null)
|
||||
return;
|
||||
|
||||
using var tempItems = new TempBuffer<object>(128);
|
||||
|
||||
IList? items = null;
|
||||
|
||||
int itemsCount;
|
||||
int selectedIndex;
|
||||
{
|
||||
if (ItemsSource is IList list)
|
||||
{
|
||||
items = list;
|
||||
itemsCount = list.Count;
|
||||
selectedIndex = list.IndexOf(SelectedItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempItems.AddFrom(ItemsSource);
|
||||
itemsCount = tempItems.Length;
|
||||
selectedIndex = tempItems.IndexOf(SelectedItem!);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedIndex == -1)
|
||||
{
|
||||
if (itemsCount > 0)
|
||||
{
|
||||
var item = _items?.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
|
||||
item?.Focus();
|
||||
|
||||
SelectedItem = items != null
|
||||
? items[0]
|
||||
: tempItems[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedIndex += dir;
|
||||
selectedIndex = (selectedIndex, 0, itemsCount - 1).Clamp();
|
||||
|
||||
SelectedItem = items != null
|
||||
? items[selectedIndex]
|
||||
: tempItems[selectedIndex];
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Geometry MarkGeom = Geometry.Parse("M 0.0,0.0 L 3.5,4.0 7.0,0.0 z");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user