UWP — Как указать порядок обновлений при использовании x: Bind?

Я разрабатываю приложение UWP и столкнулся с проблемой. Приложение использует шаблон MVVM с Template10. Я создал аналогичное решение, которое воссоздает проблему, с которой я столкнулся. В этом решении отображается список заказов, пользователь выбирает заказ, а затем нажимает кнопку «Изменить». Затем отображается вторая страница с предварительно загруженным предыдущим выбранным заказом, на этой второй странице пользователь может редактировать заказ. Проблема на второй странице, данные, привязанные к полям со списком, не отображаются. Возможно, проблема связана с этим вопросом. В моем случае 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));
        }));

    }
}

person Wacho    schedule 16.11.2017    source источник


Ответы (1)


Это известная проблема x:Bind, когда SelectedValue в ComboBox иногда устанавливается перед его ItemsSource, вы можете узнать больше об этом здесь.

В качестве обходного пути вы можете использовать Bindings вместо x:Bind, но убедитесь, что привязка ItemsSource размещена перед привязкой SelectedValue в XAML.

В качестве альтернативы вы можете попробовать вызвать Bindings.Update() в событии Page_Loaded вашей второй страницы.

person A. Milto    schedule 16.11.2017
comment
Попробовав оба решения, использование Binding вместо x:Bind помогло. Предложение Bindings.Update() не сработало - person Wacho; 20.11.2017