首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >.Net Maui在视图之间导航和传递对象

.Net Maui在视图之间导航和传递对象
EN

Stack Overflow用户
提问于 2022-09-14 01:34:04
回答 2查看 666关注 0票数 0

我正在努力使用.Net Maui和一个独立于UI的MVVM模式将一个对象从一个视图传递到另一个视图。

到目前为止,我发现的大多数或所有MAUI示例都使用并推广了MVVM。他们还倾向于在UI项目中存储视图模型,并直接利用MAUI导航。在我看来和理解中,这可能忽略了MVVM的一些好处,因为View模型不会与其他UI项目一起工作。

我尝试创建一个工作示例*,视图模型、模型和服务位于一个独立的UI独立项目中,并由包含视图的UI项目引用。示例项目发布到GitHub我想用一个解决方案来更新这个项目,这样它就可以成为一个有用的例子。

当从对象列表中单击单个对象时,它会打开一个详细视图,但该对象没有被成功传递。在本例中,我的示例使用了客户订单列表,当单击订单列表中的订单时,我尝试在详细视图中打开订单。

我的问题在XAML绑定到GoToOrdersCommand、命令如何实现和订单对象传递给Order之间。

为什么我同时有一个DelegateCommand和RelayCommand,我不确定。我看过的不同的例子使用了这些名字,我不确定一个名字是否正确。或者它们是否应该合并成一个类。我认为这个例子唯一的显著区别是RelayCommand接受一个对象作为参数。

订单视图-模型

代码语言:javascript
运行
复制
    namespace Orders.Common.ViewModel
    {
        public class OrdersViewModel : ViewModelBase
        {
            public ObservableCollection<Order> Orders { get; } = new();
    
            private readonly OrderDataProvider _orderDataProvider;
            private IOrderNavigation _navigationService;
    
            public RelayCommand<Order> GoToOrdersCommand { get; }
    
            private Order _order;
    
            public OrdersViewModel(IOrderNavigation navigationService)
            {
                Orders = new ObservableCollection<Order>();
                _orderDataProvider = new OrderDataProvider();
                _navigationService = navigationService;
    
                _order = new Order();
    
                GoToOrdersCommand = new RelayCommand<Order>((order) => OrderDetails(_order));
    
                Load();
            }
    
            public void Load()
            {
                var orders = _orderDataProvider.GetAllOrders();
                Orders.Clear();
    
                foreach (var order in orders)
                    Orders.Add(order);
            }
    
            public void OrderDetails(Order order)
            {
                if (order == null)
                    return;
    
                _navigationService.NavigateToOrderAsync(order);
            }
        }
    }

订单视图-模型

代码语言:javascript
运行
复制
public class OrderViewModel : ViewModelBase
    {
        private Order _order;

        public Order Order
        {
            get => _order;
            set
            {
                if (_order != value)
                {
                    _order = value;
                    RaisePropertyChanged();
                }
            }
        }

        private OrderDataProvider _orderDataProvider = new OrderDataProvider();

        public DelegateCommand SaveCommand { get; }

        public ICommand SaveOrder { get; set; }


        public OrderViewModel()
        {
            _order = new Order() { OrderID = -1, Customer = "", OrderDate = DateTime.Now };

            SaveCommand = new DelegateCommand(Save, () => CanSave);
        }

        public OrderViewModel(Order order)
        {
            _order = order;

            SaveCommand = new DelegateCommand(Save, () => CanSave);
        }

        public bool CanSave => !string.IsNullOrEmpty(CustomerName) && CustomerName.Length >= 3;

        public void Save()
        {
            throw new NotImplementedException();
        }

        public int OrderID
        {
            get => _order.OrderID;
            set
            {
                if (_order.OrderID != value)
                {
                    _order.OrderID = value;
                    RaisePropertyChanged();
                }
            }
        }

        public string CustomerName
        {
            get => _order.Customer;
            set
            {
                if (_order.Customer != value)
                {
                    _order.Customer = value;
                    RaisePropertyChanged();
                    RaisePropertyChanged(nameof(CanSave));
                    SaveCommand.RaiseCanExecuteChanged();
                }
            }
        }

        public DateTime OrderDate
        {
            get => _order.OrderDate;
            set
            {
                if (_order.OrderDate != value)
                {
                    _order.OrderDate = value;
                    RaisePropertyChanged();
                }
            }
        }
    }

继承的UI特定导航

代码语言:javascript
运行
复制
    namespace TestOrders.Navigate
    {
        public class OrderNavigationService : IOrderNavigation
        {
            public void NavigateToOrdersAsync()
            {
                Shell.Current.GoToAsync(nameof(OrdersPage));
            }
    
            public void NavigateToOrderAsync(Order order)
            {
                Shell.Current.GoToAsync(nameof(OrderPage), true, new Dictionary<string, object> { { "Order", order } });
            }        
        }
    }

RelayCommand

代码语言:javascript
运行
复制
namespace Orders.Common.ViewModel.Command
{
    public class RelayCommand<T> : ICommand
    {
        private Action<object> _execute;
        private Func<object, bool> _canExecute;

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged;

        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, EventArgs.Empty);
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null || _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}

订单视图

代码语言:javascript
运行
复制
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TestOrders.Pages.OrdersPage"
             Title="OrdersPage"
             xmlns:model="clr-namespace:Orders.Common.Model;assembly=Orders.Common"
             xmlns:viewmodel="clr-namespace:Orders.Common.ViewModel;assembly=Orders.Common"
             x:DataType="viewmodel:OrdersViewModel">

        <VerticalStackLayout>
            <Label Text="Orders" HorizontalOptions="Center"/>

            <CollectionView
                    ItemsSource="{Binding Orders}"
                    SelectionMode="None">
                <CollectionView.ItemTemplate>
                    <DataTemplate x:DataType="model:Order">
                        <Grid Padding="10">
                            <Frame HeightRequest="70">
                                <Frame.GestureRecognizers>
                                    <TapGestureRecognizer 
                                            Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:OrdersViewModel}}, Path=GoToOrdersCommand}"
                                            CommandParameter="{Binding .}"/>
                                </Frame.GestureRecognizers>
                                
                                <Grid Padding="0" ColumnDefinitions="20,*">
                                    <Label Text="{Binding OrderID}" Grid.Column="0"/>
                                    <Label Text="{Binding Customer}" Grid.Column="1"/>
                            </Grid>
                            </Frame>
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </VerticalStackLayout>
</ContentPage>

*对于.Net Maui、基于XAML的UI、MVVM模式以及对接口和委托等其他主题缺乏经验,我可能错过了一些最佳实践或编码约定。我还试图避免使用MVVM社区工具包或其他工具包,直到我更好地了解MVVM以及接口和命令是如何工作的。

EN

回答 2

Stack Overflow用户

发布于 2022-09-14 02:42:52

我相信这个

代码语言:javascript
运行
复制
GoToOrdersCommand = new RelayCommand<Order>((order) => OrderDetails(_order));

应该是

代码语言:javascript
运行
复制
GoToOrdersCommand = new RelayCommand<Order>((order) => OrderDetails(order));

_order是在前面的行上创建的一个新实例,而不是从视图的绑定传入的实例

票数 2
EN

Stack Overflow用户

发布于 2022-09-14 22:44:18

更改为OrdersViewModel构造器

代码语言:javascript
运行
复制
public OrdersViewModel(IOrderNavigation navigationService)
{
    Orders = new ObservableCollection<Order>();
    _orderDataProvider = new OrderDataProvider();
    _navigationService = navigationService;


    GoToOrdersCommand = new RelayCommand<Order>((order) => OrderDetails((Order)order));
    GoToNewOrderCommand = new DelegateCommand(NewOrder); // Additional navigate without object

    Load();
}

用于导航到添加到OrdersViewModel的新/空订单详细信息以供参考的附加命令方法

代码语言:javascript
运行
复制
private void NewOrder()
{
    _navigationService.NavigateToOrderAsync();
}

更新的顺序导航

代码语言:javascript
运行
复制
public class OrderNavigationService : IOrderNavigation
{
    public void NavigateToOrdersAsync()
    {
        Shell.Current.GoToAsync(nameof(OrdersPage));
    }

    public void NavigateToOrderAsync(Order order)
    {
        Shell.Current.GoToAsync(nameof(OrderPage), true, new Dictionary<string, object> { { "Order", order } });
    }

    public void NavigateToOrderAsync()
    {
        Shell.Current.GoToAsync(nameof(OrderPage));
    }
}

OrderPage查看文件背后的代码

添加了QueryProperty,如果提供了Order对象,则创建OrderViewModel的字段和方法。

代码语言:javascript
运行
复制
[QueryProperty(nameof(order), "Order")]
public partial class OrderPage : ContentPage
{
    public Order order
    {
        set
        {
            Load(value);
        }
    }

    public OrderPage()
    {
        InitializeComponent();

        BindingContext = new OrderViewModel();
    }

    private void Load(Order order)
    {
        if (order != null)
            BindingContext = new OrderViewModel(order);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73710578

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档