UWP - 如何在使用 x:Bind 时指定更新顺序?

UWP - How to specify the order of updates when use x:Bind?

我正在开发 UWP 应用程序,但遇到了问题。该应用程序使用带有 Template10 的 MVVM 模式。我创建了一个类似的solution that recreates the problem that I'm facing. In that solution, a list of orders are displayed, the user chooses an order and then click the "Edit" button. Then a second page is displayed and pre-loaded with the previous selected order, in this second page the user can edit the order. The problem is in the second page, the data bound to comboboxes doesn't show. Maybe the problem is related to this question。在我的例子中,SelectedValue 设置在 ItemsSource 之前。经过调试,我在OrderEditionPage.g.cs:

中达到了这几行代码
private void Update_ViewModel(global::ComboApp.ViewModels.OrderEditionPageViewModel obj, int phase)
{
    this.bindingsTracking.UpdateChildListeners_ViewModel(obj);
    if (obj != null)
    {
        if ((phase & (NOT_PHASED | DATA_CHANGED | (1 << 0))) != 0)
        {
            this.Update_ViewModel_SelectedOrder(obj.SelectedOrder, phase);
        }
        if ((phase & (NOT_PHASED | (1 << 0))) != 0)
        {
            this.Update_ViewModel_BusinessAssociates(obj.BusinessAssociates, phase);
            this.Update_ViewModel_TransactionTypes(obj.TransactionTypes, phase);
            this.Update_ViewModel_OrderTypes(obj.OrderTypes, phase);
            this.Update_ViewModel_ShowSelectedOrder(obj.ShowSelectedOrder, phase);
        }
    }
}

如果能实现最后执行这行代码,我的问题就解决了:this.Update_ViewModel_SelectedOrder(obj.SelectedOrder, phase);

我怎样才能做到这一点? Visual Studio 如何确定这些行的顺序?

OrderEditionPage.xaml

<Page
    x:Class="ComboApp.Views.OrderEditionPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:myconverters="using:ComboApp.Converters"
    xmlns:t10converters="using:Template10.Converters"
    mc:Ignorable="d">

    <Page.Resources>
        <t10converters:ChangeTypeConverter x:Key="TypeConverter" />
        <myconverters:DateTimeConverter x:Key="DateTimeConverter" />
    </Page.Resources>

    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <StackPanel
            Padding="15, 5"
            Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <TextBox
                Header="Order #"
                Margin="5"
                Width="150"
                HorizontalAlignment="Left"
                Text="{x:Bind ViewModel.SelectedOrder.ExternalId, Mode=TwoWay}" />
            <ComboBox
                Header="Business Associate"
                Margin="5"
                MinWidth="300"
                SelectedValuePath="BusinessAssociateId"
                DisplayMemberPath="Name1"
                ItemsSource="{x:Bind ViewModel.BusinessAssociates}"
                SelectedValue="{x:Bind ViewModel.SelectedOrder.BusinessAssociateId, Mode=TwoWay, Converter={StaticResource TypeConverter}}" />
            <DatePicker
                Header="Delivery Date"
                Margin="5"
                MinWidth="0"
                Width="200"
                Date="{x:Bind ViewModel.SelectedOrder.DeliveryDate, Mode=TwoWay, Converter={StaticResource DateTimeConverter}}" />
            <ComboBox
                Header="Transaction"
                MinWidth="200"
                Margin="5"
                SelectedValuePath="Value"
                DisplayMemberPath="Display"
                ItemsSource="{x:Bind ViewModel.TransactionTypes}"
                SelectedValue="{x:Bind ViewModel.SelectedOrder.TransactionType, Mode=TwoWay}" />
            <TextBox
                Header="Priority"
                Margin="5"
                MaxWidth="150"
                HorizontalAlignment="Left"
                Text="{x:Bind ViewModel.SelectedOrder.Priority}" />
            <ComboBox
                Header="Type"
                Margin="5"
                MinWidth="200"
                SelectedValuePath="Value"
                DisplayMemberPath="Display"
                ItemsSource="{x:Bind ViewModel.OrderTypes}"
                SelectedValue="{x:Bind ViewModel.SelectedOrder.OrderType, Mode=TwoWay}" />
            <TextBox
                Header="Information"
                Margin="5"
                Height="100"
                AcceptsReturn="True"
                TextWrapping="Wrap"
                ScrollViewer.VerticalScrollBarVisibility="Auto"
                Text="{x:Bind ViewModel.SelectedOrder.Information, Mode=TwoWay}" />
            <Button
                Margin="5"
                Content="Show"
                Width="100"
                HorizontalAlignment="Right"
                Command="{x:Bind ViewModel.ShowSelectedOrder}" />
        </StackPanel>
    </ScrollViewer>
</Page>

OrderEditionPage.xaml.cs

using ComboApp.ViewModels;
using Windows.UI.Xaml.Controls;

namespace ComboApp.Views
{
    public sealed partial class OrderEditionPage : Page
    {
        public OrderEditionPageViewModel ViewModel => DataContext as OrderEditionPageViewModel;

        public OrderEditionPage()
        {
            this.InitializeComponent();
        }
    }
}

OrderEditionPageViewModel.cs

using ComboApp.Models;
using ComboApp.Services;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Template10.Mvvm;
using Template10.Utils;
using Windows.UI.Xaml.Navigation;

namespace ComboApp.ViewModels
{
    public class OrderEditionPageViewModel
        : ViewModelBase
    {
        private IBusinessAssociateService businessAssociateService;

        private Order selectedOrder;
        public Order SelectedOrder
        {
            get { return selectedOrder; }
            set { Set(ref selectedOrder, value); }
        }

        public ObservableCollection<object> TransactionTypes { get; set; } = new ObservableCollection<object>();
        public ObservableCollection<object> OrderTypes { get; set; } = new ObservableCollection<object>();
        public ObservableCollection<BusinessAssociate> BusinessAssociates { get; set; } = new ObservableCollection<BusinessAssociate>();

        public OrderEditionPageViewModel(IBusinessAssociateService businessAssociateService)
        {
            this.businessAssociateService = businessAssociateService;

            TransactionTypes.Add(new { Value = "I", Display = "Incoming" });
            TransactionTypes.Add(new { Value = "O", Display = "Outgoing" });
            TransactionTypes.Add(new { Value = "T", Display = "Transfer" });

            OrderTypes.Add(new { Value = "M", Display = "Manual" });
            OrderTypes.Add(new { Value = "A", Display = "Automatic" });
            OrderTypes.Add(new { Value = "S", Display = "Semi-automatic" });
        }

        public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> state)
        {
            // Loading buiness associates
            var response = await businessAssociateService.GetNextPageAsync();
            if (response.IsSuccessful)
            {
                BusinessAssociates.AddRange(response.Result.Items);
            }

            SelectedOrder = (Order)parameter;
            await base.OnNavigatedToAsync(parameter, mode, state);
        }

        private DelegateCommand showSelectedOrder;
        public DelegateCommand ShowSelectedOrder => showSelectedOrder ?? (showSelectedOrder = new DelegateCommand(async () =>
        {
            await Views.MessageBox.ShowAsync(JsonConvert.SerializeObject(SelectedOrder, Formatting.Indented));
        }));

    }
}

ComboBoxSelectedValue 有时设置在其 ItemsSource 之前时,这是 x:Bind 的一个已知问题,您可以阅读更多相关信息 here.

作为解决方法,您可以使用 Bindings 而不是 x:Bind,但请确保 ItemsSource 绑定位于 XAML 中的 SelectedValue 绑定之前。

或者您可以尝试在第二页的 Page_Loaded 事件中调用 Bindings.Update()