committed by
GitHub
146 changed files with 1084 additions and 434 deletions
@ -0,0 +1,66 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using System.Windows.Input; |
||||
|
|
||||
|
namespace MiniMvvm |
||||
|
{ |
||||
|
public sealed class MiniCommand<T> : MiniCommand, ICommand |
||||
|
{ |
||||
|
private readonly Action<T> _cb; |
||||
|
private bool _busy; |
||||
|
private Func<T, Task> _acb; |
||||
|
|
||||
|
public MiniCommand(Action<T> cb) |
||||
|
{ |
||||
|
_cb = cb; |
||||
|
} |
||||
|
|
||||
|
public MiniCommand(Func<T, Task> cb) |
||||
|
{ |
||||
|
_acb = cb; |
||||
|
} |
||||
|
|
||||
|
private bool Busy |
||||
|
{ |
||||
|
get => _busy; |
||||
|
set |
||||
|
{ |
||||
|
_busy = value; |
||||
|
CanExecuteChanged?.Invoke(this, EventArgs.Empty); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public override event EventHandler CanExecuteChanged; |
||||
|
public override bool CanExecute(object parameter) => !_busy; |
||||
|
|
||||
|
public override async void Execute(object parameter) |
||||
|
{ |
||||
|
if(Busy) |
||||
|
return; |
||||
|
try |
||||
|
{ |
||||
|
Busy = true; |
||||
|
if (_cb != null) |
||||
|
_cb((T)parameter); |
||||
|
else |
||||
|
await _acb((T)parameter); |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
Busy = false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public abstract class MiniCommand : ICommand |
||||
|
{ |
||||
|
public static MiniCommand Create(Action cb) => new MiniCommand<object>(_ => cb()); |
||||
|
public static MiniCommand Create<TArg>(Action<TArg> cb) => new MiniCommand<TArg>(cb); |
||||
|
public static MiniCommand CreateFromTask(Func<Task> cb) => new MiniCommand<object>(_ => cb()); |
||||
|
|
||||
|
public abstract bool CanExecute(object parameter); |
||||
|
public abstract void Execute(object parameter); |
||||
|
public abstract event EventHandler CanExecuteChanged; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
</PropertyGroup> |
||||
|
<Import Project="..\..\build\Rx.props" /> |
||||
|
</Project> |
||||
@ -0,0 +1,108 @@ |
|||||
|
using System; |
||||
|
using System.ComponentModel; |
||||
|
using System.Linq.Expressions; |
||||
|
using System.Reactive.Linq; |
||||
|
using System.Reflection; |
||||
|
|
||||
|
namespace MiniMvvm |
||||
|
{ |
||||
|
public static class PropertyChangedExtensions |
||||
|
{ |
||||
|
class PropertyObservable<T> : IObservable<T> |
||||
|
{ |
||||
|
private readonly INotifyPropertyChanged _target; |
||||
|
private readonly PropertyInfo _info; |
||||
|
|
||||
|
public PropertyObservable(INotifyPropertyChanged target, PropertyInfo info) |
||||
|
{ |
||||
|
_target = target; |
||||
|
_info = info; |
||||
|
} |
||||
|
|
||||
|
class Subscription : IDisposable |
||||
|
{ |
||||
|
private readonly INotifyPropertyChanged _target; |
||||
|
private readonly PropertyInfo _info; |
||||
|
private readonly IObserver<T> _observer; |
||||
|
|
||||
|
public Subscription(INotifyPropertyChanged target, PropertyInfo info, IObserver<T> observer) |
||||
|
{ |
||||
|
_target = target; |
||||
|
_info = info; |
||||
|
_observer = observer; |
||||
|
_target.PropertyChanged += OnPropertyChanged; |
||||
|
_observer.OnNext((T)_info.GetValue(_target)); |
||||
|
} |
||||
|
|
||||
|
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.PropertyName == _info.Name) |
||||
|
_observer.OnNext((T)_info.GetValue(_target)); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
_target.PropertyChanged -= OnPropertyChanged; |
||||
|
_observer.OnCompleted(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public IDisposable Subscribe(IObserver<T> observer) |
||||
|
{ |
||||
|
return new Subscription(_target, _info, observer); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static IObservable<TRes> WhenAnyValue<TModel, TRes>(this TModel model, |
||||
|
Expression<Func<TModel, TRes>> expr) where TModel : INotifyPropertyChanged |
||||
|
{ |
||||
|
var l = (LambdaExpression)expr; |
||||
|
var ma = (MemberExpression)l.Body; |
||||
|
var prop = (PropertyInfo)ma.Member; |
||||
|
return new PropertyObservable<TRes>(model, prop); |
||||
|
} |
||||
|
|
||||
|
public static IObservable<TRes> WhenAnyValue<TModel, T1, TRes>(this TModel model, |
||||
|
Expression<Func<TModel, T1>> v1, |
||||
|
Func<T1, TRes> cb |
||||
|
) where TModel : INotifyPropertyChanged |
||||
|
{ |
||||
|
return model.WhenAnyValue(v1).Select(cb); |
||||
|
} |
||||
|
|
||||
|
public static IObservable<TRes> WhenAnyValue<TModel, T1, T2, TRes>(this TModel model, |
||||
|
Expression<Func<TModel, T1>> v1, |
||||
|
Expression<Func<TModel, T2>> v2, |
||||
|
Func<T1, T2, TRes> cb |
||||
|
) where TModel : INotifyPropertyChanged => |
||||
|
Observable.CombineLatest( |
||||
|
model.WhenAnyValue(v1), |
||||
|
model.WhenAnyValue(v2), |
||||
|
cb); |
||||
|
|
||||
|
public static IObservable<ValueTuple<T1, T2>> WhenAnyValue<TModel, T1, T2>(this TModel model, |
||||
|
Expression<Func<TModel, T1>> v1, |
||||
|
Expression<Func<TModel, T2>> v2 |
||||
|
) where TModel : INotifyPropertyChanged => |
||||
|
model.WhenAnyValue(v1, v2, (a1, a2) => (a1, a2)); |
||||
|
|
||||
|
public static IObservable<TRes> WhenAnyValue<TModel, T1, T2, T3, TRes>(this TModel model, |
||||
|
Expression<Func<TModel, T1>> v1, |
||||
|
Expression<Func<TModel, T2>> v2, |
||||
|
Expression<Func<TModel, T3>> v3, |
||||
|
Func<T1, T2, T3, TRes> cb |
||||
|
) where TModel : INotifyPropertyChanged => |
||||
|
Observable.CombineLatest( |
||||
|
model.WhenAnyValue(v1), |
||||
|
model.WhenAnyValue(v2), |
||||
|
model.WhenAnyValue(v3), |
||||
|
cb); |
||||
|
|
||||
|
public static IObservable<ValueTuple<T1, T2, T3>> WhenAnyValue<TModel, T1, T2, T3>(this TModel model, |
||||
|
Expression<Func<TModel, T1>> v1, |
||||
|
Expression<Func<TModel, T2>> v2, |
||||
|
Expression<Func<TModel, T3>> v3 |
||||
|
) where TModel : INotifyPropertyChanged => |
||||
|
model.WhenAnyValue(v1, v2, v3, (a1, a2, a3) => (a1, a2, a3)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Reactive.Joins; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
|
||||
|
namespace MiniMvvm |
||||
|
{ |
||||
|
public class ViewModelBase : INotifyPropertyChanged |
||||
|
{ |
||||
|
public event PropertyChangedEventHandler PropertyChanged; |
||||
|
protected bool RaiseAndSetIfChanged<T>(ref T field, T value, [CallerMemberName] string propertyName = null) |
||||
|
{ |
||||
|
if (!EqualityComparer<T>.Default.Equals(field, value)) |
||||
|
{ |
||||
|
field = value; |
||||
|
RaisePropertyChanged(propertyName); |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) |
||||
|
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace Avalonia.Native |
||||
|
{ |
||||
|
internal class DoubleClickHelper |
||||
|
{ |
||||
|
private int _clickCount; |
||||
|
private Rect _lastClickRect; |
||||
|
private ulong _lastClickTime; |
||||
|
|
||||
|
public bool IsDoubleClick( |
||||
|
ulong timestamp, |
||||
|
Point p) |
||||
|
{ |
||||
|
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>(); |
||||
|
var doubleClickTime = settings.DoubleClickTime.TotalMilliseconds; |
||||
|
|
||||
|
if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime) |
||||
|
{ |
||||
|
_clickCount = 0; |
||||
|
} |
||||
|
|
||||
|
++_clickCount; |
||||
|
_lastClickTime = timestamp; |
||||
|
_lastClickRect = new Rect(p, new Size()) |
||||
|
.Inflate(new Thickness(settings.DoubleClickSize.Width / 2, settings.DoubleClickSize.Height / 2)); |
||||
|
|
||||
|
return _clickCount == 2; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,4 @@ |
|||||
|
Compat issues with assembly Avalonia.Themes.Fluent: |
||||
|
CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Themes.Fluent.FluentTheme' does not inherit from base type 'Avalonia.Styling.Styles' in the implementation but it does in the contract. |
||||
|
MembersMustExist : Member 'public void Avalonia.Themes.Fluent.FluentTheme..ctor()' does not exist in the implementation but it does exist in the contract. |
||||
|
Total Issues: 2 |
||||
@ -0,0 +1,62 @@ |
|||||
|
<Styles xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="Avalonia.Themes.Fluent.Controls.FluentControls"> |
||||
|
<!-- Define ToolTip first so its styles can be overriden by other controls (e.g. TextBox) --> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ToolTip.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/DataValidationErrors.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/FocusAdorner.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Button.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Carousel.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/CheckBox.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ComboBox.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ComboBoxItem.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ContentControl.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Label.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/GridSplitter.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ItemsControl.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ListBox.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ListBoxItem.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Menu.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ContextMenu.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/MenuItem.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/OverlayPopupHost.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/PathIcon.xaml" /> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/PopupRoot.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ProgressBar.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/RadioButton.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/RepeatButton.xaml" /> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Separator.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Slider.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ScrollBar.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ScrollViewer.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TabStrip.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TabStripItem.xaml"/> |
||||
|
<!-- TabControl needs to come after TabStrip as it redefines the inner TabStrip.ItemsPanel--> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TabControl.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TabItem.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TextBox.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ToggleButton.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Expander.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TitleBar.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TreeView.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TreeViewItem.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/UserControl.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Window.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/EmbeddableControlRoot.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/CalendarButton.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/CalendarDayButton.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/CalendarItem.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/Calendar.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/NumericUpDown.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/WindowNotificationManager.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/NotificationCard.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/ToggleSwitch.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/SplitView.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/DatePicker.xaml"/> |
||||
|
<StyleInclude Source="avares://Avalonia.Themes.Fluent/Controls/TimePicker.xaml"/> |
||||
|
</Styles> |
||||
@ -1,12 +1,12 @@ |
|||||
using Avalonia.Markup.Xaml; |
using Avalonia.Markup.Xaml; |
||||
using Avalonia.Styling; |
using Avalonia.Styling; |
||||
|
|
||||
namespace Avalonia.Themes.Fluent |
namespace Avalonia.Themes.Fluent.Controls |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// The default Avalonia theme.
|
/// The default Avalonia theme.
|
||||
/// </summary>
|
/// </summary>
|
||||
public class FluentTheme : Styles |
public class FluentControls : Styles |
||||
{ |
{ |
||||
} |
} |
||||
} |
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue