diff --git a/src/Ursa.ReactiveUI/AssemblyInfo.cs b/src/Ursa.ReactiveUI/AssemblyInfo.cs new file mode 100644 index 0000000..5d28eeb --- /dev/null +++ b/src/Ursa.ReactiveUI/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using Avalonia.Metadata; + +[assembly: XmlnsDefinition("https://irihi.tech/ursa", "Ursa.ReactiveUIExtension")] \ No newline at end of file diff --git a/src/Ursa.ReactiveUI/ReactiveUrsaView.cs b/src/Ursa.ReactiveUI/ReactiveUrsaView.cs new file mode 100644 index 0000000..b725b23 --- /dev/null +++ b/src/Ursa.ReactiveUI/ReactiveUrsaView.cs @@ -0,0 +1,63 @@ +using Avalonia; +using ReactiveUI; +using Ursa.Controls; + +/* These codes are ported from Avalonia.ReactiveUI. + * **/ + +namespace Ursa.ReactiveUIExtension; +/// +/// A ReactiveUI that implements the interface and +/// will activate your ViewModel automatically if the view model implements . +/// When the DataContext property changes, this class will update the ViewModel property with the new DataContext +/// value, and vice versa. +/// +/// ViewModel type. +public class ReactiveUrsaView : UrsaView, IViewFor where TViewModel : class +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1002", Justification = "Generic avalonia property is expected here.")] + public static readonly StyledProperty ViewModelProperty = AvaloniaProperty + .Register, TViewModel?>(nameof(ViewModel)); + + /// + /// Initializes a new instance of the class. + /// + public ReactiveUrsaView() + { + // This WhenActivated block calls ViewModel's WhenActivated + // block if the ViewModel implements IActivatableViewModel. + this.WhenActivated(disposables => { }); + } + + /// + /// The ViewModel. + /// + public TViewModel? ViewModel + { + get => GetValue(ViewModelProperty); + set => SetValue(ViewModelProperty, value); + } + + object? IViewFor.ViewModel + { + get => ViewModel; + set => ViewModel = (TViewModel?)value; + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == DataContextProperty) { + if (ReferenceEquals(change.OldValue, ViewModel) + && change.NewValue is null or TViewModel) { + SetCurrentValue(ViewModelProperty, change.NewValue); + } + } + else if (change.Property == ViewModelProperty) { + if (ReferenceEquals(change.OldValue, DataContext)) { + SetCurrentValue(DataContextProperty, change.NewValue); + } + } + } +} \ No newline at end of file diff --git a/src/Ursa.ReactiveUI/ReactiveUrsaWindow.cs b/src/Ursa.ReactiveUI/ReactiveUrsaWindow.cs new file mode 100644 index 0000000..36d58a5 --- /dev/null +++ b/src/Ursa.ReactiveUI/ReactiveUrsaWindow.cs @@ -0,0 +1,63 @@ +using Avalonia; +using ReactiveUI; +using Ursa.Controls; + +/* These codes are ported from Avalonia.ReactiveUI. + * **/ + +namespace Ursa.ReactiveUIExtension; +/// +/// A ReactiveUI that implements the interface and will +/// activate your ViewModel automatically if the view model implements . When +/// the DataContext property changes, this class will update the ViewModel property with the new DataContext value, +/// and vice versa. +/// +/// ViewModel type. +public class ReactiveUrsaWindow : UrsaWindow, IViewFor where TViewModel : class +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1002", Justification = "Generic avalonia property is expected here.")] + public static readonly StyledProperty ViewModelProperty = AvaloniaProperty + .Register, TViewModel?>(nameof(ViewModel)); + + /// + /// Initializes a new instance of the class. + /// + public ReactiveUrsaWindow() + { + // This WhenActivated block calls ViewModel's WhenActivated + // block if the ViewModel implements IActivatableViewModel. + this.WhenActivated(disposables => { }); + } + + /// + /// The ViewModel. + /// + public TViewModel? ViewModel + { + get => GetValue(ViewModelProperty); + set => SetValue(ViewModelProperty, value); + } + + object? IViewFor.ViewModel + { + get => ViewModel; + set => ViewModel = (TViewModel?)value; + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == DataContextProperty) { + if (ReferenceEquals(change.OldValue, ViewModel) + && change.NewValue is null or TViewModel) { + SetCurrentValue(ViewModelProperty, change.NewValue); + } + } + else if (change.Property == ViewModelProperty) { + if (ReferenceEquals(change.OldValue, DataContext)) { + SetCurrentValue(DataContextProperty, change.NewValue); + } + } + } +} \ No newline at end of file diff --git a/src/Ursa.ReactiveUI/Ursa.ReactiveUIExtension.csproj b/src/Ursa.ReactiveUI/Ursa.ReactiveUIExtension.csproj new file mode 100644 index 0000000..80bc0ff --- /dev/null +++ b/src/Ursa.ReactiveUI/Ursa.ReactiveUIExtension.csproj @@ -0,0 +1,27 @@ + + + + netstandard2.0;net8 + enable + latest + WCKFWCKY + Irihi.Ursa.ReactiveUIExtension + irihi.png + https://github.com/irihitech/Ursa.Avalonia + MIT + enable + True + This is a Ursa expansion. This package integrates and is compatible with UrsaWindow and UrsaView with Avalonia.ReactiveUI. [Avalonia.ReactiveU See: https://docs.avaloniaui.net/zh-Hans/docs/concepts/reactiveui/] + +这个是一个Ursa拓展包。这个包整合并互相兼容了UrsaWindow和UrsaView与Avalonia.ReactiveUI的功能。【Avalonia.ReactiveU参见:https://docs.avaloniaui.net/docs/concepts/reactiveui/】 + 1.0.1 + WCKFWCKY + https://github.com/irihitech/Ursa.Avalonia + + + + + + + + diff --git a/src/Ursa.ReactiveUI/irihi.png b/src/Ursa.ReactiveUI/irihi.png new file mode 100644 index 0000000..01c68d9 Binary files /dev/null and b/src/Ursa.ReactiveUI/irihi.png differ