英文:
Selected Card via Picker is not displaying data
问题
Here is the translated code:
public partial class MenuPage : ContentPage, INotifyPropertyChanged
{
// Transactions
private ObservableCollection<TransactionData> _transactions = new ObservableCollection<TransactionData>();
public ObservableCollection<TransactionData> Transactions
{
get { return _transactions; }
set
{
_transactions = value;
OnPropertyChanged(nameof(Transactions));
}
}
// Cards
private ObservableCollection<CardData> _cards = new ObservableCollection<CardData>();
public ObservableCollection<CardData> Cards
{
get { return _cards; }
set
{
_cards = value;
OnPropertyChanged(nameof(Cards));
}
}
// Selected Card
private CardData _selectedCard;
public CardData SelectedCard
{
get { return _selectedCard; }
set { _selectedCard = value; OnPropertyChanged(nameof(SelectedCard)); OnPropertyChanged(nameof(IsCardSelected)); }
}
public bool IsCardSelected
{
get { return SelectedCard != null; }
}
// Active Account
public Account SelectedAccount { get; }
// Account Balance
public class AccountBalance
{
[JsonProperty("status")]
public string status { get; set; }
[JsonProperty("msg")]
public string msg { get; set; }
[JsonProperty("data")]
public string data { get; set; }
}
public MenuPage(Account _selectedAccount)
{
InitializeComponent();
Title = "Transactions";
BindingContext = this;
SelectedAccount = _selectedAccount;
}
// When the screen appears
protected override async void OnAppearing()
{
base.OnAppearing();
await GetTransactionsAsync();
await GetBalanceAsync();
await GetCardsAsync();
}
// Confirm you want to go back
protected override bool OnBackButtonPressed()
{
MainThread.BeginInvokeOnMainThread(async () =>
{
var result = await this.DisplayAlert("Alert!", "Do you really want to choose another account?", "Yes", "No");
if (result) await this.Navigation.PopAsync();
});
return true;
}
// Get Transactions from Account
private async Task GetTransactionsAsync()
{
string iban = App.ActiveAccount.iban;
string url = "https://example";
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
TransactionsResponse responseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<TransactionsResponse>(json);
Transactions = responseObj.data;
}
else
{
Debug.WriteLine("Error: Unable to get transactions data.");
}
}
// Get Account Balance
private async Task GetBalanceAsync()
{
string iban = App.ActiveAccount.iban;
string url = "https://example";
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(url);
var responseString = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
JObject resultX = JObject.Parse(responseString);
JObject data = (JObject)resultX["data"];
string account_balance = (string)data["account_balance"];
balanceLabel.Text = account_balance + "€";
}
else
{
Debug.WriteLine("Error: Unable to get balance data.");
}
}
// Get Client Cards
private async Task GetCardsAsync()
{
int id_client = App.ActiveAccount.id_client_account;
string url = "https://example";
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
CardsResponse responseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<CardsResponse>(json);
Cards = responseObj.data;
}
else
{
Debug.WriteLine("Error: Unable to get Card data.");
}
}
// More Transactions -> Updates
public new event PropertyChangedEventHandler PropertyChanged;
protected override void OnPropertyChanged(string propertyName)
{
base.OnPropertyChanged(propertyName);
if (propertyName == "Transactions")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Transactions"));
}
else
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class TransactionsResponse
{
public ObservableCollection<TransactionData> data { get; set; }
}
public class CardsResponse
{
public ObservableCollection<CardData> data { get; set; }
}
private void GotoTransactionPage(object sender, EventArgs e)
{
Navigation.PushAsync(new MakeTransactionPage());
}
private void GotoLoanPage(object sender, EventArgs e)
{
Navigation.PushAsync(new LoansPage(SelectedAccount));
}
}
Please note that the code you provided contains HTML-encoded characters (e.g., "
), which should be replaced with their actual characters (e.g., "
). The code I provided assumes that these HTML-encoded characters have been corrected.
英文:
What I'm trying to do:
API retrieves an array of cards. However, only 1 is displayed. The user chooses whichever card he wants to use via a Picker. After selecting a card, the card data is displayed (Card Number, Valid Month and Year, etc.)
What is happening:
Picker is getting populated with the data from the API. After selecting a card, no data is displayed.
Things that I have checked:
Feedback is that the code is fine. Visual Studio is not reporting any data binding errors. Debugging runs fine, no exceptions, no nothing. API is running and data is being retrieved.
MenuPage.xaml
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:BankingApp"
xmlns:res="clr-namespace:BankingApp.Resources"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="BankingApp.MenuPage"
Title="MenuPage"
BackgroundColor="#041014"
Shell.NavBarIsVisible="False" NavigationPage.HasBackButton="False">
<ScrollView>
<VerticalStackLayout>
<Label HorizontalOptions="Center" Margin="0,20,0,20" Text="{x:Static res:LanguageResources.YourAccount}" FontSize="32"/>
<!--Account Bank Card-->
<Grid Margin="25,0,25,0" >
<!--<Image Source="bankcardesb.svg" Aspect="AspectFill"/>-->
<StackLayout x:Name="selectedCardLayout"
IsVisible="{Binding IsCardSelected}">
<Label Text="{Binding SelectedCard.card_number}"
FontAttributes="Bold"/>
<Label Text="{Binding SelectedCard.card_type}" />
<Label Text="{Binding SelectedCard.valid_month}"/>
</StackLayout>
<Frame>
<Label x:Name="balanceLabel" FontSize="Medium" />
</Frame>
</Grid>
<Picker x:Name="CardPicker"
Margin="0,0,20,20"
BackgroundColor="#5fb3f9"
HorizontalTextAlignment="Center"
HeightRequest="50"
WidthRequest="150"
HorizontalOptions="End"
SelectedItem="{Binding SelectedCard}"
ItemsSource="{Binding Cards}"
SelectedIndex="0"
ItemDisplayBinding="{Binding card_number}" />
<Button HorizontalOptions="Center" Margin="10" WidthRequest="200" HeightRequest="50" BackgroundColor="#00B2FF"
Text="{x:Static res:LanguageResources.MakeTransaction}" TextColor="White" FontFamily="AgeoBold" FontSize="18" Clicked="GotoTransactionPage"/>
<Button HorizontalOptions="Center" Margin="10" WidthRequest="200" HeightRequest="50" BackgroundColor="#00B2FF"
Text="{x:Static res:LanguageResources.GoToLoans}" TextColor="White" FontFamily="AgeoBold" FontSize="18" Clicked="GotoLoanPage"/>
<!--TransactionList-->
<StackLayout Margin="50,10,50,0" VerticalOptions="EndAndExpand" BindableLayout.ItemsSource="{Binding Transactions}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<toolkit:Expander BackgroundColor="#5fb3f9" Margin="0,0,0,5" Padding="10">
<toolkit:Expander.Header>
<StackLayout Orientation="Horizontal">
<Label FontFamily="OpenSansSemibold" Text="{Binding date_time}" FontSize="Small" HorizontalOptions="StartAndExpand" />
<Label FontFamily="OpenSansSemibold" Text="{Binding amount}" FontSize="Small" HorizontalOptions="End" />
<Label FontFamily="OpenSansSemibold" Text="{Binding currency}" FontSize="Small" HorizontalOptions="End" />
</StackLayout>
</toolkit:Expander.Header>
<StackLayout IsVisible="{Binding IsExpanded}">
<StackLayout Orientation="Horizontal">
<Label FontFamily="AgeoBold" Text="{x:Static res:LanguageResources.RecipientName} " FontSize="Small" />
<Label Text="{Binding name_recipient}" FontSize="Small" />
</StackLayout>
<StackLayout Orientation="Horizontal" >
<Label FontFamily="AgeoBold" Text="{x:Static res:LanguageResources.IBANPayer}" FontSize="Small" />
<Label Text="{Binding iban_payer}" FontSize="Small" />
</StackLayout>
<StackLayout Orientation="Horizontal" >
<Label FontFamily="AgeoBold" Text="{x:Static res:LanguageResources.IBANRecipient}" FontSize="Small" />
<Label Text="{Binding iban_recipient}" FontSize="Small" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label FontFamily="AgeoBold" Text="{x:Static res:LanguageResources.PaymentDescription}" FontSize="Small" />
<Label Text="{Binding payment_description}" FontSize="Small" />
</StackLayout>
<StackLayout Orientation="Horizontal" >
<Label FontFamily="AgeoBold" Text="{x:Static res:LanguageResources.ReferenceNumber}" FontSize="Small" />
<Label Text="{Binding reference_number}" FontSize="Small" />
</StackLayout>
</StackLayout>
</toolkit:Expander>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
MenuPage.xaml.cs
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using BankingApp.Models;
using Microsoft.Maui.Controls;
using BankingApp.Services;
using Microsoft.Maui.Controls.Xaml;
using Newtonsoft.Json.Linq;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Xml;
using BankingApp.Views;
using Newtonsoft.Json;
using System.Runtime.CompilerServices;
namespace BankingApp
{
public partial class MenuPage : ContentPage, INotifyPropertyChanged
{
//Transactions
private ObservableCollection<TransactionData> _transactions = new ObservableCollection<TransactionData>();
public ObservableCollection<TransactionData> Transactions
{
get { return _transactions; }
set
{
_transactions = value;
OnPropertyChanged(nameof(Transactions));
}
}
//Cards
private ObservableCollection<CardData> _cards = new ObservableCollection<CardData>();
public ObservableCollection<CardData> Cards
{
get { return _cards; }
set
{
_cards = value;
OnPropertyChanged(nameof(Cards));
}
}
//Selected Card
private CardData _selectedCard;
public CardData SelectedCard
{
get { return _selectedCard; }
set { _selectedCard = value; OnPropertyChanged(nameof(SelectedCard)); OnPropertyChanged(nameof(IsCardSelected)); }
}
public bool IsCardSelected
{
get { return SelectedCard != null; }
}
//Active Account
public Account SelectedAccount { get; }
//Account Balance
public class AccountBalance
{
[JsonProperty("status")]
public string status { get; set; }
[JsonProperty("msg")]
public string msg { get; set; }
[JsonProperty("data")]
public string data { get; set; }
}
public MenuPage(Account _selectedAccount)
{
InitializeComponent();
Title = "Transactions";
BindingContext = this;
SelectedAccount = _selectedAccount;
}
//When the screen appears
protected override async void OnAppearing()
{
base.OnAppearing();
await GetTransactionsAsync();
await GetBalanceAsync();
await GetCardsAsync();
}
//Confirm you want to go back
protected override bool OnBackButtonPressed()
{
MainThread.BeginInvokeOnMainThread(async () => {
var result = await this.DisplayAlert("Alert!", "Do you really want to choose another account?", "Yes", "No");
if (result) await this.Navigation.PopAsync();
});
return true;
}
//Get Transactions from Account
private async Task GetTransactionsAsync()
{
string iban = App.ActiveAccount.iban;
string url = $"https://example";
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
TransactionsResponse responseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<TransactionsResponse>(json);
Transactions = responseObj.data;
}
else
{
Debug.WriteLine("Error: Unable to get transactions data.");
}
}
//Get Account Balance
private async Task GetBalanceAsync()
{
string iban = App.ActiveAccount.iban;
string url = $"https://example";
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(url);
var responseString = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
JObject resultX = JObject.Parse(responseString);
JObject data = (JObject)resultX["data"];
string account_balance = (string)data["account_balance"];
balanceLabel.Text = account_balance + "€";
}
else
{
Debug.WriteLine("Error: Unable to get balance data.");
}
}
//Get Client Cards
private async Task GetCardsAsync()
{
int id_client = App.ActiveAccount.id_client_account;
string url = $"https://example";
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
CardsResponse responseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<CardsResponse>(json);
Cards = responseObj.data;
}
else
{
Debug.WriteLine("Error: Unable to get Card data.");
}
}
//More Transactions -> Updates
public new event PropertyChangedEventHandler PropertyChanged;
protected override void OnPropertyChanged(string propertyName)
{
base.OnPropertyChanged(propertyName);
if (propertyName == "Transactions")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Transactions"));
}
else
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class TransactionsResponse
{
public ObservableCollection<TransactionData> data { get; set; }
}
public class CardsResponse
{
public ObservableCollection<CardData> data { get; set; }
}
private void GotoTransactionPage(object sender, EventArgs e)
{
Navigation.PushAsync(new MakeTransactionPage());
}
private void GotoLoanPage(object sender, EventArgs e)
{
Navigation.PushAsync(new LoansPage(SelectedAccount));
}
}
}
GetCards.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BankingApp.Services
{
public class CardData
{
[JsonProperty("id_client_account")]
public string id_client_account { get; set; }
[JsonProperty("card_number")]
public string card_number { get; set; }
[JsonProperty("valid_month")]
public int valid_month { get; set; }
[JsonProperty("valid_year")]
public int valid_year { get; set; }
[JsonProperty("card_type")]
public string card_type { get; set; }
}
}
答案1
得分: 0
根据您提供的代码,Grid布局中,Frame包裹着StackLayout,所以您可能无法看到数据。您可以通过设置Grid布局中的RowDefinition和ColumnDefinition来安排子元素,或者使用其他布局方式。
此外,目前Picker的SelectedIndex属性存在问题,您可以在代码中设置SelectedIndex,而不是在XAML中设置:
public MainPage()
{
InitializeComponent();
...
CardPicker.SelectedIndex = 0;
}
更多信息,请参考Grid文档。希望对您有所帮助。
英文:
<Grid Margin="25,0,25,0" >
<StackLayout x:Name="selectedCardLayout">
<Label Text="{Binding SelectedCard.card_number}">
......
</StackLayout>
<Frame >
<Label x:Name="balanceLabel" FontSize="Medium" />
</Frame>
</Grid>
According to your code above, in the Grid layout, the Frame shelters the StackLayout. So you cannot see the data. You could set the RowDefinition RowDefinition and ColumnDefinition to arrange the children in Grid layout or use other layout.
Also, there is an issue about SelectedIndex for Picker now : Picker SelectedIndex property not working. A workaround is to set SelectedIndex in the code behind instead of xaml:
public MainPage()
{
InitializeComponent();
...
CardPicker.SelectedIndex = 0;
}
For more info, you could refer to Grid
Hope it works.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论