Merge branch 'HandyOrg:master' into japanese-translation
This commit is contained in:
942 files changed
+62191
-61784
No files matched your search
@@ -4,81 +4,80 @@ using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace HandyControl.Collections
|
||||
namespace HandyControl.Collections;
|
||||
|
||||
[Serializable]
|
||||
public class ManualObservableCollection<T> : ObservableCollection<T>
|
||||
{
|
||||
[Serializable]
|
||||
public class ManualObservableCollection<T> : ObservableCollection<T>
|
||||
private const string CountString = "Count";
|
||||
|
||||
private const string IndexerName = "Item[]";
|
||||
|
||||
private int _oldCount;
|
||||
|
||||
private bool _canNotify = true;
|
||||
|
||||
public bool CanNotify
|
||||
{
|
||||
private const string CountString = "Count";
|
||||
|
||||
private const string IndexerName = "Item[]";
|
||||
|
||||
private int _oldCount;
|
||||
|
||||
private bool _canNotify = true;
|
||||
|
||||
public bool CanNotify
|
||||
get => _canNotify;
|
||||
set
|
||||
{
|
||||
get => _canNotify;
|
||||
set
|
||||
_canNotify = value;
|
||||
|
||||
if (value)
|
||||
{
|
||||
_canNotify = value;
|
||||
|
||||
if (value)
|
||||
if (_oldCount != Count)
|
||||
{
|
||||
if (_oldCount != Count)
|
||||
{
|
||||
OnPropertyChanged(new PropertyChangedEventArgs(CountString));
|
||||
}
|
||||
|
||||
OnPropertyChanged(new PropertyChangedEventArgs(IndexerName));
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_oldCount = Count;
|
||||
OnPropertyChanged(new PropertyChangedEventArgs(CountString));
|
||||
}
|
||||
|
||||
OnPropertyChanged(new PropertyChangedEventArgs(IndexerName));
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_oldCount = Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ManualObservableCollection()
|
||||
public ManualObservableCollection()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ManualObservableCollection(List<T> list) : base(list != null ? new List<T>(list.Count) : list) => CopyFrom(list);
|
||||
|
||||
public ManualObservableCollection(IEnumerable<T> collection)
|
||||
{
|
||||
if (collection == null) throw new ArgumentNullException(nameof(collection));
|
||||
CopyFrom(collection);
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
|
||||
{
|
||||
if (!CanNotify) return;
|
||||
|
||||
base.OnPropertyChanged(e);
|
||||
}
|
||||
|
||||
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (!CanNotify) return;
|
||||
|
||||
base.OnCollectionChanged(e);
|
||||
}
|
||||
|
||||
private void CopyFrom(IEnumerable<T> collection)
|
||||
{
|
||||
var items = Items;
|
||||
if (collection != null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ManualObservableCollection(List<T> list) : base(list != null ? new List<T>(list.Count) : list) => CopyFrom(list);
|
||||
|
||||
public ManualObservableCollection(IEnumerable<T> collection)
|
||||
{
|
||||
if (collection == null) throw new ArgumentNullException(nameof(collection));
|
||||
CopyFrom(collection);
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
|
||||
{
|
||||
if (!CanNotify) return;
|
||||
|
||||
base.OnPropertyChanged(e);
|
||||
}
|
||||
|
||||
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (!CanNotify) return;
|
||||
|
||||
base.OnCollectionChanged(e);
|
||||
}
|
||||
|
||||
private void CopyFrom(IEnumerable<T> collection)
|
||||
{
|
||||
var items = Items;
|
||||
if (collection != null)
|
||||
using var enumerator = collection.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
using var enumerator = collection.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
items.Add(enumerator.Current);
|
||||
}
|
||||
items.Add(enumerator.Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
namespace HandyControl.Collections
|
||||
{
|
||||
public interface IPool<T>
|
||||
{
|
||||
T Acquire();
|
||||
namespace HandyControl.Collections;
|
||||
|
||||
bool Release(T instance);
|
||||
}
|
||||
public interface IPool<T>
|
||||
{
|
||||
T Acquire();
|
||||
|
||||
bool Release(T instance);
|
||||
}
|
||||
@@ -2,63 +2,62 @@
|
||||
|
||||
using System;
|
||||
|
||||
namespace HandyControl.Collections
|
||||
namespace HandyControl.Collections;
|
||||
|
||||
public class SimplePool<T> : IPool<T>
|
||||
{
|
||||
public class SimplePool<T> : IPool<T>
|
||||
private readonly object[] _pool;
|
||||
|
||||
private int _poolSize;
|
||||
|
||||
public SimplePool(int maxPoolSize)
|
||||
{
|
||||
private readonly object[] _pool;
|
||||
|
||||
private int _poolSize;
|
||||
|
||||
public SimplePool(int maxPoolSize)
|
||||
if (maxPoolSize <= 0)
|
||||
{
|
||||
if (maxPoolSize <= 0)
|
||||
{
|
||||
throw new ArgumentException("The max pool size must be > 0");
|
||||
}
|
||||
_pool = new object[maxPoolSize];
|
||||
throw new ArgumentException("The max pool size must be > 0");
|
||||
}
|
||||
_pool = new object[maxPoolSize];
|
||||
}
|
||||
|
||||
public virtual T Acquire()
|
||||
{
|
||||
if (_poolSize > 0)
|
||||
{
|
||||
var lastPooledIndex = _poolSize - 1;
|
||||
var instance = (T) _pool[lastPooledIndex];
|
||||
_pool[lastPooledIndex] = null;
|
||||
_poolSize--;
|
||||
return instance;
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
public virtual bool Release(T instance)
|
||||
{
|
||||
if (IsInPool(instance))
|
||||
{
|
||||
throw new Exception("Already in the pool!");
|
||||
}
|
||||
|
||||
public virtual T Acquire()
|
||||
if (_poolSize < _pool.Length)
|
||||
{
|
||||
if (_poolSize > 0)
|
||||
{
|
||||
var lastPooledIndex = _poolSize - 1;
|
||||
var instance = (T) _pool[lastPooledIndex];
|
||||
_pool[lastPooledIndex] = null;
|
||||
_poolSize--;
|
||||
return instance;
|
||||
}
|
||||
return default;
|
||||
_pool[_poolSize] = instance;
|
||||
_poolSize++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool Release(T instance)
|
||||
{
|
||||
if (IsInPool(instance))
|
||||
{
|
||||
throw new Exception("Already in the pool!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_poolSize < _pool.Length)
|
||||
private bool IsInPool(T instance)
|
||||
{
|
||||
for (var i = 0; i < _poolSize; i++)
|
||||
{
|
||||
if (Equals(_pool[i], instance))
|
||||
{
|
||||
_pool[_poolSize] = instance;
|
||||
_poolSize++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsInPool(T instance)
|
||||
{
|
||||
for (var i = 0; i < _poolSize; i++)
|
||||
{
|
||||
if (Equals(_pool[i], instance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
namespace HandyControl.Collections
|
||||
namespace HandyControl.Collections;
|
||||
|
||||
public class SynchronizedPool<T> : SimplePool<T>
|
||||
{
|
||||
public class SynchronizedPool<T> : SimplePool<T>
|
||||
private readonly object _lockObj = new();
|
||||
|
||||
public SynchronizedPool(int maxPoolSize) : base(maxPoolSize)
|
||||
{
|
||||
private readonly object _lockObj = new();
|
||||
|
||||
public SynchronizedPool(int maxPoolSize) : base(maxPoolSize)
|
||||
}
|
||||
|
||||
public override T Acquire()
|
||||
{
|
||||
lock (_lockObj)
|
||||
{
|
||||
|
||||
return base.Acquire();
|
||||
}
|
||||
}
|
||||
|
||||
public override T Acquire()
|
||||
public override bool Release(T element)
|
||||
{
|
||||
lock (_lockObj)
|
||||
{
|
||||
lock (_lockObj)
|
||||
{
|
||||
return base.Acquire();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Release(T element)
|
||||
{
|
||||
lock (_lockObj)
|
||||
{
|
||||
return base.Release(element);
|
||||
}
|
||||
return base.Release(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,332 +5,331 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace HandyControl.Collections
|
||||
namespace HandyControl.Collections;
|
||||
|
||||
[Serializable]
|
||||
public class Deque<T> : IEnumerable<T>, ICollection
|
||||
{
|
||||
[Serializable]
|
||||
public class Deque<T> : IEnumerable<T>, ICollection
|
||||
[NonSerialized]
|
||||
private object _syncRoot;
|
||||
|
||||
private List<T> _front;
|
||||
|
||||
private List<T> _back;
|
||||
|
||||
private int _frontDeleted;
|
||||
|
||||
private int _backDeleted;
|
||||
|
||||
public int Capacity => _front.Capacity + _back.Capacity;
|
||||
|
||||
public int Count => _front.Count + _back.Count - _frontDeleted - _backDeleted;
|
||||
|
||||
public bool IsEmpty => Count == 0;
|
||||
|
||||
public IEnumerable<T> Reversed
|
||||
{
|
||||
[NonSerialized]
|
||||
private object _syncRoot;
|
||||
|
||||
private List<T> _front;
|
||||
|
||||
private List<T> _back;
|
||||
|
||||
private int _frontDeleted;
|
||||
|
||||
private int _backDeleted;
|
||||
|
||||
public int Capacity => _front.Capacity + _back.Capacity;
|
||||
|
||||
public int Count => _front.Count + _back.Count - _frontDeleted - _backDeleted;
|
||||
|
||||
public bool IsEmpty => Count == 0;
|
||||
|
||||
public IEnumerable<T> Reversed
|
||||
get
|
||||
{
|
||||
get
|
||||
if (_back.Count - _backDeleted > 0)
|
||||
{
|
||||
if (_back.Count - _backDeleted > 0)
|
||||
{
|
||||
for (var i = _back.Count - 1; i >= _backDeleted; i--) yield return _back[i];
|
||||
}
|
||||
|
||||
if (_front.Count - _frontDeleted > 0)
|
||||
{
|
||||
for (var i = _frontDeleted; i < _front.Count; i++) yield return _front[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Deque()
|
||||
{
|
||||
_front = new List<T>();
|
||||
_back = new List<T>();
|
||||
}
|
||||
|
||||
public Deque(int capacity)
|
||||
{
|
||||
if (capacity < 0) throw new ArgumentException("Capacity cannot be negative");
|
||||
var temp = capacity / 2;
|
||||
var temp2 = capacity - temp;
|
||||
_front = new List<T>(temp);
|
||||
_back = new List<T>(temp2);
|
||||
}
|
||||
|
||||
public Deque(IEnumerable<T> backCollection) : this(backCollection, null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Deque(IEnumerable<T> backCollection, IEnumerable<T> frontCollection)
|
||||
{
|
||||
if (backCollection == null && frontCollection == null) throw new ArgumentException("Collections cannot both be null");
|
||||
|
||||
_front = frontCollection != null ? new List<T>(frontCollection) : new List<T>();
|
||||
_back = backCollection != null ? new List<T>(backCollection) : new List<T>();
|
||||
}
|
||||
|
||||
public void AddFirst(T item)
|
||||
{
|
||||
if (_frontDeleted > 0 && _front.Count == _front.Capacity)
|
||||
{
|
||||
_front.RemoveRange(0, _frontDeleted);
|
||||
_frontDeleted = 0;
|
||||
for (var i = _back.Count - 1; i >= _backDeleted; i--) yield return _back[i];
|
||||
}
|
||||
|
||||
_front.Add(item);
|
||||
}
|
||||
|
||||
public void AddLast(T item)
|
||||
{
|
||||
if (_backDeleted > 0 && _back.Count == _back.Capacity)
|
||||
if (_front.Count - _frontDeleted > 0)
|
||||
{
|
||||
_back.RemoveRange(0, _backDeleted);
|
||||
_backDeleted = 0;
|
||||
for (var i = _frontDeleted; i < _front.Count; i++) yield return _front[i];
|
||||
}
|
||||
|
||||
_back.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddRangeFirst(IEnumerable<T> range)
|
||||
public Deque()
|
||||
{
|
||||
_front = new List<T>();
|
||||
_back = new List<T>();
|
||||
}
|
||||
|
||||
public Deque(int capacity)
|
||||
{
|
||||
if (capacity < 0) throw new ArgumentException("Capacity cannot be negative");
|
||||
var temp = capacity / 2;
|
||||
var temp2 = capacity - temp;
|
||||
_front = new List<T>(temp);
|
||||
_back = new List<T>(temp2);
|
||||
}
|
||||
|
||||
public Deque(IEnumerable<T> backCollection) : this(backCollection, null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Deque(IEnumerable<T> backCollection, IEnumerable<T> frontCollection)
|
||||
{
|
||||
if (backCollection == null && frontCollection == null) throw new ArgumentException("Collections cannot both be null");
|
||||
|
||||
_front = frontCollection != null ? new List<T>(frontCollection) : new List<T>();
|
||||
_back = backCollection != null ? new List<T>(backCollection) : new List<T>();
|
||||
}
|
||||
|
||||
public void AddFirst(T item)
|
||||
{
|
||||
if (_frontDeleted > 0 && _front.Count == _front.Capacity)
|
||||
{
|
||||
if (range == null) return;
|
||||
|
||||
foreach (var item in range) AddFirst(item);
|
||||
}
|
||||
|
||||
public void AddRangeLast(IEnumerable<T> range)
|
||||
{
|
||||
if (range == null) return;
|
||||
|
||||
foreach (var item in range) AddLast(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_front.Clear();
|
||||
_back.Clear();
|
||||
_front.RemoveRange(0, _frontDeleted);
|
||||
_frontDeleted = 0;
|
||||
}
|
||||
|
||||
_front.Add(item);
|
||||
}
|
||||
|
||||
public void AddLast(T item)
|
||||
{
|
||||
if (_backDeleted > 0 && _back.Count == _back.Capacity)
|
||||
{
|
||||
_back.RemoveRange(0, _backDeleted);
|
||||
_backDeleted = 0;
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
for (var i = _frontDeleted; i < _front.Count; i++)
|
||||
{
|
||||
if (Equals(_front[i], item)) return true;
|
||||
}
|
||||
|
||||
for (var i = _backDeleted; i < _back.Count; i++)
|
||||
{
|
||||
if (Equals(_back[i], item)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int index)
|
||||
{
|
||||
if (array == null) throw new ArgumentNullException("Array cannot be null");
|
||||
if (index < 0) throw new ArgumentOutOfRangeException("Index cannot be negative");
|
||||
if (array.Length < index + Count) throw new ArgumentException("Index is invalid");
|
||||
var i = index;
|
||||
|
||||
foreach (var item in this)
|
||||
{
|
||||
array[i++] = item;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
if (_front.Count - _frontDeleted > 0)
|
||||
{
|
||||
for (var i = _front.Count - 1; i >= _frontDeleted; i--) yield return _front[i];
|
||||
}
|
||||
|
||||
if (_back.Count - _backDeleted > 0)
|
||||
{
|
||||
for (var i = _backDeleted; i < _back.Count; i++) yield return _back[i];
|
||||
}
|
||||
}
|
||||
|
||||
public T PeekFirst()
|
||||
{
|
||||
if (_front.Count > _frontDeleted)
|
||||
{
|
||||
return _front[_front.Count - 1];
|
||||
}
|
||||
|
||||
if (_back.Count > _backDeleted)
|
||||
{
|
||||
return _back[_backDeleted];
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Can't peek at empty Deque");
|
||||
}
|
||||
|
||||
public T PeekLast()
|
||||
{
|
||||
if (_back.Count > _backDeleted)
|
||||
{
|
||||
return _back[_back.Count - 1];
|
||||
}
|
||||
|
||||
if (_front.Count > _frontDeleted)
|
||||
{
|
||||
return _front[_frontDeleted];
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Can't peek at empty Deque");
|
||||
}
|
||||
|
||||
public T PopFirst()
|
||||
{
|
||||
T result;
|
||||
|
||||
if (_front.Count > _frontDeleted)
|
||||
{
|
||||
result = _front[_front.Count - 1];
|
||||
_front.RemoveAt(_front.Count - 1);
|
||||
}
|
||||
else if (_back.Count > _backDeleted)
|
||||
{
|
||||
result = _back[_backDeleted];
|
||||
_backDeleted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Can't pop empty Deque");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public T PopLast()
|
||||
{
|
||||
T result;
|
||||
|
||||
if (_back.Count > _backDeleted)
|
||||
{
|
||||
result = _back[_back.Count - 1];
|
||||
_back.RemoveAt(_back.Count - 1);
|
||||
}
|
||||
else if (_front.Count > _frontDeleted)
|
||||
{
|
||||
result = _front[_frontDeleted];
|
||||
_frontDeleted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Can't pop empty Deque");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Reverse()
|
||||
{
|
||||
var temp = _front;
|
||||
_front = _back;
|
||||
_back = temp;
|
||||
var temp2 = _frontDeleted;
|
||||
_frontDeleted = _backDeleted;
|
||||
_backDeleted = temp2;
|
||||
}
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
if (Count == 0) return new T[0];
|
||||
var result = new T[Count];
|
||||
CopyTo(result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void TrimExcess()
|
||||
{
|
||||
if (_frontDeleted > 0)
|
||||
{
|
||||
_front.RemoveRange(0, _frontDeleted);
|
||||
_frontDeleted = 0;
|
||||
}
|
||||
|
||||
if (_backDeleted > 0)
|
||||
{
|
||||
_back.RemoveRange(0, _backDeleted);
|
||||
_backDeleted = 0;
|
||||
}
|
||||
|
||||
_front.TrimExcess();
|
||||
_back.TrimExcess();
|
||||
}
|
||||
|
||||
public bool TryPeekFirst(out T item)
|
||||
{
|
||||
if (!IsEmpty)
|
||||
{
|
||||
item = PeekFirst();
|
||||
return true;
|
||||
}
|
||||
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryPeekLast(out T item)
|
||||
{
|
||||
if (!IsEmpty)
|
||||
{
|
||||
item = PeekLast();
|
||||
return true;
|
||||
}
|
||||
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryPopFirst(out T item)
|
||||
{
|
||||
if (!IsEmpty)
|
||||
{
|
||||
item = PopFirst();
|
||||
return true;
|
||||
}
|
||||
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryPopLast(out T item)
|
||||
{
|
||||
if (!IsEmpty)
|
||||
{
|
||||
item = PopLast();
|
||||
return true;
|
||||
}
|
||||
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ICollection.IsSynchronized => false;
|
||||
|
||||
object ICollection.SyncRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_syncRoot == null)
|
||||
{
|
||||
Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null);
|
||||
}
|
||||
return _syncRoot;
|
||||
}
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array array, int index) => CopyTo((T[]) array, index);
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
_back.Add(item);
|
||||
}
|
||||
|
||||
public void AddRangeFirst(IEnumerable<T> range)
|
||||
{
|
||||
if (range == null) return;
|
||||
|
||||
foreach (var item in range) AddFirst(item);
|
||||
}
|
||||
|
||||
public void AddRangeLast(IEnumerable<T> range)
|
||||
{
|
||||
if (range == null) return;
|
||||
|
||||
foreach (var item in range) AddLast(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_front.Clear();
|
||||
_back.Clear();
|
||||
_frontDeleted = 0;
|
||||
_backDeleted = 0;
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
for (var i = _frontDeleted; i < _front.Count; i++)
|
||||
{
|
||||
if (Equals(_front[i], item)) return true;
|
||||
}
|
||||
|
||||
for (var i = _backDeleted; i < _back.Count; i++)
|
||||
{
|
||||
if (Equals(_back[i], item)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int index)
|
||||
{
|
||||
if (array == null) throw new ArgumentNullException("Array cannot be null");
|
||||
if (index < 0) throw new ArgumentOutOfRangeException("Index cannot be negative");
|
||||
if (array.Length < index + Count) throw new ArgumentException("Index is invalid");
|
||||
var i = index;
|
||||
|
||||
foreach (var item in this)
|
||||
{
|
||||
array[i++] = item;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
if (_front.Count - _frontDeleted > 0)
|
||||
{
|
||||
for (var i = _front.Count - 1; i >= _frontDeleted; i--) yield return _front[i];
|
||||
}
|
||||
|
||||
if (_back.Count - _backDeleted > 0)
|
||||
{
|
||||
for (var i = _backDeleted; i < _back.Count; i++) yield return _back[i];
|
||||
}
|
||||
}
|
||||
|
||||
public T PeekFirst()
|
||||
{
|
||||
if (_front.Count > _frontDeleted)
|
||||
{
|
||||
return _front[_front.Count - 1];
|
||||
}
|
||||
|
||||
if (_back.Count > _backDeleted)
|
||||
{
|
||||
return _back[_backDeleted];
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Can't peek at empty Deque");
|
||||
}
|
||||
|
||||
public T PeekLast()
|
||||
{
|
||||
if (_back.Count > _backDeleted)
|
||||
{
|
||||
return _back[_back.Count - 1];
|
||||
}
|
||||
|
||||
if (_front.Count > _frontDeleted)
|
||||
{
|
||||
return _front[_frontDeleted];
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Can't peek at empty Deque");
|
||||
}
|
||||
|
||||
public T PopFirst()
|
||||
{
|
||||
T result;
|
||||
|
||||
if (_front.Count > _frontDeleted)
|
||||
{
|
||||
result = _front[_front.Count - 1];
|
||||
_front.RemoveAt(_front.Count - 1);
|
||||
}
|
||||
else if (_back.Count > _backDeleted)
|
||||
{
|
||||
result = _back[_backDeleted];
|
||||
_backDeleted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Can't pop empty Deque");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public T PopLast()
|
||||
{
|
||||
T result;
|
||||
|
||||
if (_back.Count > _backDeleted)
|
||||
{
|
||||
result = _back[_back.Count - 1];
|
||||
_back.RemoveAt(_back.Count - 1);
|
||||
}
|
||||
else if (_front.Count > _frontDeleted)
|
||||
{
|
||||
result = _front[_frontDeleted];
|
||||
_frontDeleted++;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Can't pop empty Deque");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Reverse()
|
||||
{
|
||||
var temp = _front;
|
||||
_front = _back;
|
||||
_back = temp;
|
||||
var temp2 = _frontDeleted;
|
||||
_frontDeleted = _backDeleted;
|
||||
_backDeleted = temp2;
|
||||
}
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
if (Count == 0) return new T[0];
|
||||
var result = new T[Count];
|
||||
CopyTo(result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void TrimExcess()
|
||||
{
|
||||
if (_frontDeleted > 0)
|
||||
{
|
||||
_front.RemoveRange(0, _frontDeleted);
|
||||
_frontDeleted = 0;
|
||||
}
|
||||
|
||||
if (_backDeleted > 0)
|
||||
{
|
||||
_back.RemoveRange(0, _backDeleted);
|
||||
_backDeleted = 0;
|
||||
}
|
||||
|
||||
_front.TrimExcess();
|
||||
_back.TrimExcess();
|
||||
}
|
||||
|
||||
public bool TryPeekFirst(out T item)
|
||||
{
|
||||
if (!IsEmpty)
|
||||
{
|
||||
item = PeekFirst();
|
||||
return true;
|
||||
}
|
||||
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryPeekLast(out T item)
|
||||
{
|
||||
if (!IsEmpty)
|
||||
{
|
||||
item = PeekLast();
|
||||
return true;
|
||||
}
|
||||
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryPopFirst(out T item)
|
||||
{
|
||||
if (!IsEmpty)
|
||||
{
|
||||
item = PopFirst();
|
||||
return true;
|
||||
}
|
||||
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryPopLast(out T item)
|
||||
{
|
||||
if (!IsEmpty)
|
||||
{
|
||||
item = PopLast();
|
||||
return true;
|
||||
}
|
||||
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ICollection.IsSynchronized => false;
|
||||
|
||||
object ICollection.SyncRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_syncRoot == null)
|
||||
{
|
||||
Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null);
|
||||
}
|
||||
return _syncRoot;
|
||||
}
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array array, int index) => CopyTo((T[]) array, index);
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -3,54 +3,53 @@ 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));
|
||||
|
||||
public static void SetAutoHide(DependencyObject element, bool value)
|
||||
=> element.SetValue(AutoHideProperty, 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)
|
||||
if (d is ScrollViewer)
|
||||
{
|
||||
if (d is ScrollViewer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (d is System.Windows.Controls.ScrollViewer scrollViewer)
|
||||
{
|
||||
if ((Orientation) e.NewValue == Orientation.Horizontal)
|
||||
{
|
||||
scrollViewer.PreviewMouseWheel += ScrollViewer_PreviewMouseWheel;
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollViewer.PreviewMouseWheel -= ScrollViewer_PreviewMouseWheel;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private static void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
|
||||
if (d is System.Windows.Controls.ScrollViewer scrollViewer)
|
||||
{
|
||||
var scrollViewer = (System.Windows.Controls.ScrollViewer) sender;
|
||||
scrollViewer.ScrollToHorizontalOffset(Math.Min(Math.Max(0, scrollViewer.HorizontalOffset - e.Delta), scrollViewer.ScrollableWidth));
|
||||
|
||||
e.Handled = true;
|
||||
if ((Orientation) e.NewValue == Orientation.Horizontal)
|
||||
{
|
||||
scrollViewer.PreviewMouseWheel += ScrollViewer_PreviewMouseWheel;
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollViewer.PreviewMouseWheel -= ScrollViewer_PreviewMouseWheel;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetOrientation(DependencyObject element, Orientation value)
|
||||
=> element.SetValue(OrientationProperty, ValueBoxes.OrientationBox(value));
|
||||
|
||||
public static Orientation GetOrientation(DependencyObject element)
|
||||
=> (Orientation) element.GetValue(OrientationProperty);
|
||||
}
|
||||
|
||||
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,206 +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 CanMouseWheelProperty = DependencyProperty.Register(
|
||||
"CanMouseWheel", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
/// <summary>
|
||||
/// 是否响应鼠标滚轮操作
|
||||
/// </summary>
|
||||
public bool CanMouseWheel
|
||||
if (!IsInertiaEnabled)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 (ScrollViewerAttach.GetOrientation(this) == 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();
|
||||
}
|
||||
}
|
||||
Loaded 100 of 942 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user