diff --git a/.gitignore b/.gitignore index 2d94781984..9602fa91e5 100644 --- a/.gitignore +++ b/.gitignore @@ -449,3 +449,4 @@ src/Tools/ # MSBuild generator editor configs **/*.GeneratedMSBuildEditorConfig.editorconfig /app +.dotnet/ diff --git a/src/ReactiveUI.Maui/ReactiveEntryCell.cs b/src/ReactiveUI.Maui/ReactiveEntryCell.cs index f32bde2a4b..961c1e183f 100644 --- a/src/ReactiveUI.Maui/ReactiveEntryCell.cs +++ b/src/ReactiveUI.Maui/ReactiveEntryCell.cs @@ -3,6 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System; using Microsoft.Maui.Controls; namespace ReactiveUI.Maui; @@ -17,6 +18,7 @@ namespace ReactiveUI.Maui; [RequiresDynamicCode("ReactiveEntryCell uses methods that require dynamic code generation")] [RequiresUnreferencedCode("ReactiveEntryCell uses methods that may require unreferenced code")] #endif +[Obsolete("ListView and its cells are obsolete in .NET MAUI, please use CollectionView with a DataTemplate and a ReactiveContentView-based view instead. This will be removed in a future release.")] public partial class ReactiveEntryCell : EntryCell, IViewFor where TViewModel : class { diff --git a/src/ReactiveUI.Maui/ReactiveImageCell.cs b/src/ReactiveUI.Maui/ReactiveImageCell.cs index df092bfcc3..0f4e8fa8f3 100644 --- a/src/ReactiveUI.Maui/ReactiveImageCell.cs +++ b/src/ReactiveUI.Maui/ReactiveImageCell.cs @@ -3,6 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System; using Microsoft.Maui.Controls; namespace ReactiveUI.Maui; @@ -17,6 +18,7 @@ namespace ReactiveUI.Maui; [RequiresDynamicCode("ReactiveImageCell uses methods that require dynamic code generation")] [RequiresUnreferencedCode("ReactiveImageCell uses methods that may require unreferenced code")] #endif +[Obsolete("ListView and its cells are obsolete in .NET MAUI, please use CollectionView with a DataTemplate and a ReactiveContentView-based view instead. This will be removed in a future release.")] public partial class ReactiveImageCell : ImageCell, IViewFor where TViewModel : class { diff --git a/src/ReactiveUI.Maui/ReactiveImageItemView.cs b/src/ReactiveUI.Maui/ReactiveImageItemView.cs new file mode 100644 index 0000000000..0f538e914c --- /dev/null +++ b/src/ReactiveUI.Maui/ReactiveImageItemView.cs @@ -0,0 +1,171 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Microsoft.Maui.Controls; +using Microsoft.Maui.Graphics; + +namespace ReactiveUI.Maui; + +/// +/// A that displays an image with text content similar to an ImageCell, +/// but designed for use with CollectionView and DataTemplates. This serves as a modern replacement +/// for ReactiveImageCell which relied on the deprecated ListView. +/// +/// The type of the view model. +/// +#if NET6_0_OR_GREATER +[RequiresDynamicCode("ReactiveImageItemView uses methods that require dynamic code generation")] +[RequiresUnreferencedCode("ReactiveImageItemView uses methods that may require unreferenced code")] +#endif +public partial class ReactiveImageItemView : ReactiveContentView + where TViewModel : class +{ + /// + /// The image source bindable property. + /// + public static readonly BindableProperty ImageSourceProperty = BindableProperty.Create( + nameof(ImageSource), + typeof(ImageSource), + typeof(ReactiveImageItemView), + default(ImageSource)); + + /// + /// The text bindable property for the primary text. + /// + public static readonly BindableProperty TextProperty = BindableProperty.Create( + nameof(Text), + typeof(string), + typeof(ReactiveImageItemView), + default(string)); + + /// + /// The detail bindable property for the secondary text. + /// + public static readonly BindableProperty DetailProperty = BindableProperty.Create( + nameof(Detail), + typeof(string), + typeof(ReactiveImageItemView), + default(string)); + + /// + /// The text color bindable property. + /// + public static readonly BindableProperty TextColorProperty = BindableProperty.Create( + nameof(TextColor), + typeof(Color), + typeof(ReactiveImageItemView), + default(Color)); + + /// + /// The detail color bindable property. + /// + public static readonly BindableProperty DetailColorProperty = BindableProperty.Create( + nameof(DetailColor), + typeof(Color), + typeof(ReactiveImageItemView), + default(Color)); + + private readonly Image _image; + private readonly Label _textLabel; + private readonly Label _detailLabel; + + /// + /// Initializes a new instance of the class. + /// + public ReactiveImageItemView() + { + _image = new Image + { + WidthRequest = 40, + HeightRequest = 40, + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Start + }; + + _textLabel = new Label + { + FontSize = 16, + VerticalOptions = LayoutOptions.Center + }; + + _detailLabel = new Label + { + FontSize = 12, + VerticalOptions = LayoutOptions.Center, + Opacity = 0.7 + }; + + var textStackLayout = new StackLayout + { + Orientation = StackOrientation.Vertical, + VerticalOptions = LayoutOptions.Center, + HorizontalOptions = LayoutOptions.Fill, + Children = { _textLabel, _detailLabel } + }; + + var mainStackLayout = new StackLayout + { + Orientation = StackOrientation.Horizontal, + VerticalOptions = LayoutOptions.Center, + Padding = 16, + Spacing = 12, + Children = { _image, textStackLayout } + }; + + Content = mainStackLayout; + + // Bind the control properties to the bindable properties + _image.SetBinding(Image.SourceProperty, new Binding(nameof(ImageSource), source: this)); + _textLabel.SetBinding(Label.TextProperty, new Binding(nameof(Text), source: this)); + _textLabel.SetBinding(Label.TextColorProperty, new Binding(nameof(TextColor), source: this)); + _detailLabel.SetBinding(Label.TextProperty, new Binding(nameof(Detail), source: this)); + _detailLabel.SetBinding(Label.TextColorProperty, new Binding(nameof(DetailColor), source: this)); + } + + /// + /// Gets or sets the image source to display. + /// + public ImageSource? ImageSource + { + get => (ImageSource?)GetValue(ImageSourceProperty); + set => SetValue(ImageSourceProperty, value); + } + + /// + /// Gets or sets the primary text to display. + /// + public string? Text + { + get => (string?)GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + + /// + /// Gets or sets the detail text to display. + /// + public string? Detail + { + get => (string?)GetValue(DetailProperty); + set => SetValue(DetailProperty, value); + } + + /// + /// Gets or sets the color of the primary text. + /// + public Color TextColor + { + get => (Color)GetValue(TextColorProperty); + set => SetValue(TextColorProperty, value); + } + + /// + /// Gets or sets the color of the detail text. + /// + public Color DetailColor + { + get => (Color)GetValue(DetailColorProperty); + set => SetValue(DetailColorProperty, value); + } +} \ No newline at end of file diff --git a/src/ReactiveUI.Maui/ReactiveSwitchCell.cs b/src/ReactiveUI.Maui/ReactiveSwitchCell.cs index b64079ca3c..4af0e3bdd1 100644 --- a/src/ReactiveUI.Maui/ReactiveSwitchCell.cs +++ b/src/ReactiveUI.Maui/ReactiveSwitchCell.cs @@ -3,6 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System; using Microsoft.Maui.Controls; namespace ReactiveUI.Maui; @@ -17,6 +18,7 @@ namespace ReactiveUI.Maui; [RequiresDynamicCode("ReactiveSwitchCell uses methods that require dynamic code generation")] [RequiresUnreferencedCode("ReactiveSwitchCell uses methods that may require unreferenced code")] #endif +[Obsolete("ListView and its cells are obsolete in .NET MAUI, please use CollectionView with a DataTemplate and a ReactiveContentView-based view instead. This will be removed in a future release.")] public partial class ReactiveSwitchCell : SwitchCell, IViewFor where TViewModel : class { diff --git a/src/ReactiveUI.Maui/ReactiveTextCell.cs b/src/ReactiveUI.Maui/ReactiveTextCell.cs index 924f3be4ee..34815ce447 100644 --- a/src/ReactiveUI.Maui/ReactiveTextCell.cs +++ b/src/ReactiveUI.Maui/ReactiveTextCell.cs @@ -3,6 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System; using Microsoft.Maui.Controls; namespace ReactiveUI.Maui; @@ -17,6 +18,7 @@ namespace ReactiveUI.Maui; [RequiresDynamicCode("ReactiveTextCell uses methods that require dynamic code generation")] [RequiresUnreferencedCode("ReactiveTextCell uses methods that may require unreferenced code")] #endif +[Obsolete("ListView and its cells are obsolete in .NET MAUI, please use CollectionView with a DataTemplate and a ReactiveContentView-based view instead. This will be removed in a future release.")] public partial class ReactiveTextCell : TextCell, IViewFor where TViewModel : class { diff --git a/src/ReactiveUI.Maui/ReactiveTextItemView.cs b/src/ReactiveUI.Maui/ReactiveTextItemView.cs new file mode 100644 index 0000000000..44f4fc4770 --- /dev/null +++ b/src/ReactiveUI.Maui/ReactiveTextItemView.cs @@ -0,0 +1,134 @@ +// Copyright (c) 2025 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Microsoft.Maui.Controls; +using Microsoft.Maui.Graphics; + +namespace ReactiveUI.Maui; + +/// +/// A that displays text content similar to a TextCell, +/// but designed for use with CollectionView and DataTemplates. This serves as a modern replacement +/// for ReactiveTextCell which relied on the deprecated ListView. +/// +/// The type of the view model. +/// +#if NET6_0_OR_GREATER +[RequiresDynamicCode("ReactiveTextItemView uses methods that require dynamic code generation")] +[RequiresUnreferencedCode("ReactiveTextItemView uses methods that may require unreferenced code")] +#endif +public partial class ReactiveTextItemView : ReactiveContentView + where TViewModel : class +{ + /// + /// The text bindable property for the primary text. + /// + public static readonly BindableProperty TextProperty = BindableProperty.Create( + nameof(Text), + typeof(string), + typeof(ReactiveTextItemView), + default(string)); + + /// + /// The detail bindable property for the secondary text. + /// + public static readonly BindableProperty DetailProperty = BindableProperty.Create( + nameof(Detail), + typeof(string), + typeof(ReactiveTextItemView), + default(string)); + + /// + /// The text color bindable property. + /// + public static readonly BindableProperty TextColorProperty = BindableProperty.Create( + nameof(TextColor), + typeof(Color), + typeof(ReactiveTextItemView), + default(Color)); + + /// + /// The detail color bindable property. + /// + public static readonly BindableProperty DetailColorProperty = BindableProperty.Create( + nameof(DetailColor), + typeof(Color), + typeof(ReactiveTextItemView), + default(Color)); + + private readonly Label _textLabel; + private readonly Label _detailLabel; + + /// + /// Initializes a new instance of the class. + /// + public ReactiveTextItemView() + { + _textLabel = new Label + { + FontSize = 16, + VerticalOptions = LayoutOptions.Center + }; + + _detailLabel = new Label + { + FontSize = 12, + VerticalOptions = LayoutOptions.Center, + Opacity = 0.7 + }; + + var stackLayout = new StackLayout + { + Orientation = StackOrientation.Vertical, + VerticalOptions = LayoutOptions.Center, + Padding = 16, + Children = { _textLabel, _detailLabel } + }; + + Content = stackLayout; + + // Bind the label properties to the bindable properties + _textLabel.SetBinding(Label.TextProperty, new Binding(nameof(Text), source: this)); + _textLabel.SetBinding(Label.TextColorProperty, new Binding(nameof(TextColor), source: this)); + _detailLabel.SetBinding(Label.TextProperty, new Binding(nameof(Detail), source: this)); + _detailLabel.SetBinding(Label.TextColorProperty, new Binding(nameof(DetailColor), source: this)); + } + + /// + /// Gets or sets the primary text to display. + /// + public string? Text + { + get => (string?)GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + + /// + /// Gets or sets the detail text to display. + /// + public string? Detail + { + get => (string?)GetValue(DetailProperty); + set => SetValue(DetailProperty, value); + } + + /// + /// Gets or sets the color of the primary text. + /// + public Color TextColor + { + get => (Color)GetValue(TextColorProperty); + set => SetValue(TextColorProperty, value); + } + + /// + /// Gets or sets the color of the detail text. + /// + public Color DetailColor + { + get => (Color)GetValue(DetailColorProperty); + set => SetValue(DetailColorProperty, value); + } +} \ No newline at end of file diff --git a/src/ReactiveUI.Maui/ReactiveViewCell.cs b/src/ReactiveUI.Maui/ReactiveViewCell.cs index 7ef8eca87a..23315a55fc 100644 --- a/src/ReactiveUI.Maui/ReactiveViewCell.cs +++ b/src/ReactiveUI.Maui/ReactiveViewCell.cs @@ -3,6 +3,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. +using System; using Microsoft.Maui.Controls; namespace ReactiveUI.Maui; @@ -17,6 +18,7 @@ namespace ReactiveUI.Maui; [RequiresDynamicCode("ReactiveViewCell uses methods that require dynamic code generation")] [RequiresUnreferencedCode("ReactiveViewCell uses methods that may require unreferenced code")] #endif +[Obsolete("ListView and its cells are obsolete in .NET MAUI, please use CollectionView with a DataTemplate and a ReactiveContentView-based view instead. This will be removed in a future release.")] public partial class ReactiveViewCell : ViewCell, IViewFor where TViewModel : class {