Передача «косвенного» объекта между страницами в XMAL / C # - PullRequest
0 голосов
/ 06 февраля 2020

Я определил объект Player следующим образом:

public class Player
    {
        [PrimaryKey, AutoIncrement]
        public int ID { get; set; }
        public string PlayerName { get; set; }
        public DateTime JoinDate { get; set; }
        public int TotalMatchesWon { get; set; }
        public int TotalMatchesLost { get; set; }
        public float WinPercentage { get; set; }
        public int Rank { get; set; }
    }

Я храню проигрыватели в базе данных SQLite. Я реализую следующие страницы для приложения android в Xamarin:

Учетная запись -> Подробная информация о реестре -> Редактировать плеер

Страницы имеют следующие функциональные возможности:

Ростер: 1. Roster.xmal содержит ListView of Players (Список), заполняемый из следующей функции в Roster.xmal.cs.

protected override async void OnAppearing()
        {
            base.OnAppearing();

            listView.ItemsSource = await App.Database.GetPlayersAsync();
        }
Добавить нового игрока в реестр. Это вызывает страницу редактирования проигрывателя с пустыми полями, используя следующий код в файле Roster.xmal.cs.
async void OnPlayerAddedClicked(object send, EventArgs e)
        {
            await Navigation.PushAsync(new RosterEntryPage
            {
                BindingContext = new Player()
            });
        }
Вы можете выбрать игрока из списка. Это берет SelectedItem и отправляет Player в PlayerDetailPage (также в Roster.xmal.cs)
async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)
        {
            if (e.SelectedItem != null)
            {
                await Navigation.PushAsync(new PlayerDetailPage
                {
                    BindingContext = e.SelectedItem as Player
                });
            }
        }

Сведения о ростере: 1. Отображает объект Player, который был передается ему из функции OnListViewItemSelected (). На странице нет кода, который бы указывал на наличие проигрывателя, но я могу ссылаться на поля проигрывателя в файле RosterDetails.xmal (поэтому я и называю его «косвенным» объектом), например:

<Label Grid.Column="2" 
                               Text="{Binding PlayerName}"
                               FontSize="18"
                               FontAttributes="Bold" />
Пользователь может нажать на кнопку, чтобы отредактировать плеер. Это снова вызывает RosterEntryPage (например, для добавления нового игрока), но на этот раз он пропускает игрока, который у него уже есть. Это та часть, которая сломана. Если я вызываю страницу редактирования напрямую из Roster.xmal, я могу предварительно заполнить все пустые поля (но это только PlayerName) и обновить запись SQLite. Я хотел бы передать косвенный объект, используемый RosterDetail.xmal, на страницу редактирования, чтобы сделать то же самое.

Вот RosterDetail.xmal.cs:

public partial class PlayerDetailPage : ContentPage
    {
        public PlayerDetailPage()
        {
            InitializeComponent();
        }

        async void OnEditPlayerButtonClicked(object send, EventArgs e)
        {
            await floatingButtonEdit.ScaleTo(1.5, 500);
            await floatingButtonEdit.ScaleTo(0, 500, Easing.SpringOut);

            await Navigation.PushAsync(new RosterEntryPage
            {
                BindingContext = new Player()
            });
        }

    }

Я знаю, что проблема в BindingContext = new Player (), но я понятия не имею, чем заменить его. Я пробовал разные вещи, такие как BindingContext = e.Player, но это выдает ошибку, что e.Player недействителен. Я также попытался изменить параметры функции, чтобы они соответствовали OnListViewItemSelected (), чтобы он был OnEditPlayerButtonClicked (отправитель объекта, SelectedItemChangedEventArgs e), но это приводит к тому, что приложение обрабатывает sh.

EDIT Здесь это xmal для страницы, где вы вводите данные, чтобы добавить нового игрока или отредактировать существующий.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Foosball.RosterEntryPage"
             Title="Roster Entry">
    <StackLayout Margin="20">

        <Editor Placeholder="Enter player name"
                Text="{Binding PlayerName}"
                HeightRequest="50" />

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Button Text="Save"
                            Clicked="OnRosterEntrySaveButtonClicked"
                            Grid.Row="1" />
            <Button Text="Delete"
                            Clicked="OnRosterEntryDeleteButtonClicked"
                            Grid.Row="1" 
                            Grid.Column="1"/>
        </Grid>
    </StackLayout>
</ContentPage>

Вот соответствующий файл .cs

public partial class RosterEntryPage : ContentPage
    {
        public RosterEntryPage()
        {
            InitializeComponent();
        }

        public RosterEntryPage(Player newPlayer)
        {
            InitializeComponent();
        }

        async void OnRosterEntrySaveButtonClicked(object sender, EventArgs e)
        {
            var player = (Player)BindingContext;

            player.JoinDate = DateTime.UtcNow;
            await App.Database.SavePlayerAsync(player);

            await Navigation.PopAsync();
        }

        async void OnRosterEntryDeleteButtonClicked(object sender, EventArgs e)
        {
            var player = (Player)BindingContext;

            await App.Database.DeletePlayerAsync(player);

            await Navigation.PopAsync();
        }
    }

Ответы [ 2 ]

0 голосов
/ 07 февраля 2020

На странице нет кода, который бы указывал на наличие проигрывателя, но я могу ссылаться на поля проигрывателя в файле RosterDetails.xmal (поэтому я и называю его "косвенным" объектом)

Вы можете ссылаться на поля Player в файле RosterDetails.xmal, потому что вы присвоили BindingContext при нажатии на PlayerDetailPage.

Таким образом, вы можете получить текущего игрока с помощью BindingContext и передать его RosterEntryPage:

public partial class PlayerDetailPage : ContentPage
{
    public PlayerDetailPage()
    {
        InitializeComponent();
    }

    async void OnEditPlayerButtonClicked(object send, EventArgs e)
    {
        await floatingButtonEdit.ScaleTo(1.5, 500);
        await floatingButtonEdit.ScaleTo(0, 500, Easing.SpringOut);

        Player myPlayer = this.BindingContext as Player;

        await Navigation.PushAsync(new RosterEntryPage
        {
            BindingContext = myPlayer
        });
    }

}
0 голосов
/ 06 февраля 2020

вместо установки BindingContext страницы перед тем, как перейти к ней, передайте данные через конструктор и дайте странице установить свою собственную BindingContext

    Player ViewModel { get; set; }

    public PlayerDetailPage(Player player)
    {
        InitializeComponent();

        this.BindingContext = ViewModel = player;
    }

затем

    async void OnEditPlayerButtonClicked(object send, EventArgs e)
    {
        await floatingButtonEdit.ScaleTo(1.5, 500);
        await floatingButtonEdit.ScaleTo(0, 500, Easing.SpringOut);

        await Navigation.PushAsync(new RosterEntryPage(ViewModel));
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...