diff --git a/README.md b/README.md index 54d11b1..fb83a2d 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,26 @@ You can now use Ursa controls in your Avalonia Application. ![Demo](./assets/demo.jpg) +## ReactiveUI +If you're familiar with and often use Avalonia.ReactiveUI for development, you can use the Irihi.Ursa.ReactiveUIExtension package. This package implements the ReactiveUI versions of UrsaWindow and UrsaView. + +You just need to replace ReactiveWindow or ReactiveUserControl with ReactiveUrsaWindow or ReactiveUrsaView. +```xaml + +... + +``` +```csharp +public partial class WindowHome : ReactiveUrsaWindow +{ + +} +``` + ## Support We offer limited free community support for Semi Avalonia and Ursa. Please join our group via FeiShu(Lark) diff --git a/Ursa.sln b/Ursa.sln index 8e0c259..ab83bf9 100644 --- a/Ursa.sln +++ b/Ursa.sln @@ -1,5 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35209.166 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ursa", "src\Ursa\Ursa.csproj", "{14E5B6D1-E3ED-41D7-9664-37ABE3B22558}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ursa.Demo", "demo\Ursa.Demo\Ursa.Demo.csproj", "{407A91FD-A88B-459B-8DCE-8C6AA98279FE}" @@ -22,12 +25,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ursa.PrismDialogDemo", "dem EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution Files", "{9D34CC2C-9BFA-4138-BA5A-CD3744F9B589}" ProjectSection(SolutionItems) = preProject - src\Package.props = src\Package.props demo\Directory.Build.props = demo\Directory.Build.props + src\Package.props = src\Package.props EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox", "demo\Sandbox\Sandbox.csproj", "{1E94BAFD-867E-425F-8E12-7F416D523C94}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ursa.ReactiveUIExtension", "src\Ursa.ReactiveUI\Ursa.ReactiveUIExtension.csproj", "{1317FA08-1C62-4E64-9568-3DF210760B48}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -74,6 +79,13 @@ Global {1E94BAFD-867E-425F-8E12-7F416D523C94}.Debug|Any CPU.Build.0 = Debug|Any CPU {1E94BAFD-867E-425F-8E12-7F416D523C94}.Release|Any CPU.ActiveCfg = Release|Any CPU {1E94BAFD-867E-425F-8E12-7F416D523C94}.Release|Any CPU.Build.0 = Release|Any CPU + {1317FA08-1C62-4E64-9568-3DF210760B48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1317FA08-1C62-4E64-9568-3DF210760B48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1317FA08-1C62-4E64-9568-3DF210760B48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1317FA08-1C62-4E64-9568-3DF210760B48}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {407A91FD-A88B-459B-8DCE-8C6AA98279FE} = {A41BAF0D-DA61-4A63-889A-084BAD36FD66} 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..a530383 --- /dev/null +++ b/src/Ursa.ReactiveUI/Ursa.ReactiveUIExtension.csproj @@ -0,0 +1,30 @@ + + + + netstandard2.0;net8 + enable + latest + WCKYWCKF, IRIHI Technology + 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.ReactiveUI See: https://docs.avaloniaui.net/zh-Hans/docs/concepts/reactiveui/] + +这个是一个Ursa拓展包。这个包整合并互相兼容了UrsaWindow和UrsaView与Avalonia.ReactiveUI的功能。【Avalonia.ReactiveUI参见:https://docs.avaloniaui.net/docs/concepts/reactiveui/】 + 1.0.1 + + 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