#c# #android #user-interface #xamarin.forms
#c# #Android #пользовательский интерфейс #xamarin.forms
Вопрос:
Я пытаюсь создать простой графический интерфейс с помощью Xamarin и сталкиваюсь со всевозможными проблемами. Это эксперимент, поэтому код немного уродливый, но в основном у меня есть 2 страницы; Главная страница и страница настроек. На главной странице я хочу выйти и выполнить вызов REST и заполнить список (в настоящее время жестко заданный). Все шло нормально, пока я не решил выполнить вызов Rest как асинхронную задачу. Теперь topLabel не будет обновляться, listview тоже не будет (хотя, если я нажму на него, это произойдет). и кнопка не будет переключать страницы. Многое из этого для меня ново, но это похоже на игру в whack a mole. Я решаю 1 проблему, а еще 4 перестают работать. Я уверен, что мне не хватает какой-то фундаментальной вещи. Любая помощь приветствуется.
Xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TheButton.MainPage">
<StackLayout Spacing="1">
<Label x:Name="topLabel" TextColor="{Binding TopTextColor}" Text="{Binding itsTopText}" BackgroundColor="LightSlateGray" HorizontalTextAlignment="Center"
FontSize="Title" HorizontalOptions ="FillAndExpand" Padding="10,10,30,10" HeightRequest="50"/>
<StackLayout Spacing="5" VerticalOptions="FillAndExpand">
<ListView x:Name="soundsListView" ItemsSource="{Binding itsButtonSounds}" Margin="5"
ItemSelected="OnListViewItemSelected"
ItemTapped="OnListViewItemTapped"
RowHeight="70">
<ListView.ItemTemplate>
<DataTemplate >
<ViewCell >
<Grid BackgroundColor="{Binding LEDColor}" Padding="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label VerticalTextAlignment="Center" HorizontalTextAlignment="Start" VerticalOptions="CenterAndExpand" Grid.Column="1" Grid.Row="0"
Text="{Binding Name}" FontSize="Title"
FontAttributes="Bold" />
<Label Grid.ColumnSpan="3"
Grid.Column="2"
Text="{Binding Description}"
VerticalOptions="StartAndExpand" VerticalTextAlignment="Center"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout Spacing="5" Orientation="Horizontal" HeightRequest="120" VerticalOptions="Center" HorizontalOptions="Center">
<Button Text="Add Sound" FontSize="45" Clicked="Handle_Clicked" VerticalOptions="Fill" HorizontalOptions="Fill"/>
</StackLayout>
</StackLayout>
</StackLayout>
</ContentPage>
И главная страница
namespace TheButton
{
public partial class MainPage : ContentPage
{
public string whatever = "[ { "Name": "hello", "ImageUrl": "./Sounds/hello.mp3", "color": [255,0,255], "Description":"hello!", "order": 1 }]";
public ObservableCollection<ButtonSound> itsButtonSounds { get; private set; }
public ButtonSound tappedItem;
public bool connectedToModule;
public string itsTopText { get; set; }
public Color TopTextColor { get; set; }
public MainPage()
{
BindingContext = this;
InitializeComponent();
connectedToModule = false;
Console.WriteLine("HI!!!!!");
itsButtonSounds = new ObservableCollection<ButtonSound>();
TopTextColor = Color.Red;
itsTopText = "CONNECTING... Please Wait!";
Console.WriteLine("Connection");
Task.Run( connectToModule);
Console.WriteLine("Done Connection");
MessagingCenter.Subscribe<SettingPage, ButtonSound>(this, "Hi", (itsSender, butt) =>
{
Console.WriteLine("HI!!!!!");
if (tappedItem== null)
{
itsButtonSounds.Add(butt);
}
else
{
var index = itsButtonSounds.IndexOf(tappedItem);
itsButtonSounds[index] = butt;
}
});
}
int count = 0;
void Handle_Clicked(object sender, System.EventArgs e)
{
if (connectedToModule ==true)
{
tappedItem = null;
SettingPage comingPage = new SettingPage();
comingPage.SetToButtonSound();
Navigation.PushModalAsync(comingPage);
}
else
{
DisplayAlert("Not Connected!", "Please put Button into Connection mode by holding the options button for 3 seconds", "OK");
}
}
public async Task connectToModule()
{
var client = new RestClient("http://raspberrypi:5000");
var request = new RestRequest("con", Method.GET);
while (true)
{
Console.WriteLine("REST REQUIESSTT");
var response = client.Execute(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK amp;amp; response.Content == "accept")
{
connectedToModule = true;
Console.WriteLine($"CONNECTED! OMGOMG!{connectedToModule}");
InitButtonSounds();
Console.WriteLine(response.Content);
Console.WriteLine(connectedToModule == true);
break;
}
Thread.Sleep(500);
}
}
public void InitButtonSounds()
{
//string fileName = "TheButton.data.json";
//var backingFile = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "data.json");
//Console.WriteLine(backingFile);
//string jsonString = File.ReadAllText(backingFile);
Console.WriteLine("Nonesense! initbuttons!");
TopTextColor = Color.LightCyan;
itsTopText = "Connected To... Button1";
var jsonButtons = JsonConvert.DeserializeObject<List<ButtonSound>>(whatever);
foreach( ButtonSound bs in jsonButtons)
{
bs.LEDColor = Color.FromRgb(bs.color[0], bs.color[1], bs.color[2]);
Console.WriteLine(bs.Name);
itsButtonSounds.Add(bs);
}
itsButtonSounds.Add(new ButtonSound
{
Name = "Hellosss",
Description ="C:/SomePath",
ImageUrl = "THIS IS REDUNDANT",
LEDColor = Color.FromRgb(225,0,0)
});
itsButtonSounds.Add(new ButtonSound
{
Name = "bye",
Description = "C:/SomePath BLah BLah BLah bladsfgdsfsadhfdshfkadshfkldsafhasdklfdshfdklsafjhdslfka fdsf adsf dsaf adsf h Blah",
ImageUrl = "THIS IS REDUNDANT",
LEDColor = Color.FromRgb(12, 233, 31)
});
itsButtonSounds.Add(new ButtonSound
{
Name = "Doot",
Description = "C:/SomePath",
ImageUrl = "THIS IS REDUNDANT",
LEDColor = Color.FromRgb(122, 122, 11)
});
soundsListView.ItemsSource = itsButtonSounds;
}
void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)
{
ButtonSound selectedItem = e.SelectedItem as ButtonSound;
}
void OnListViewItemTapped(object sender, ItemTappedEventArgs e)
{
tappedItem = e.Item as ButtonSound;
Console.WriteLine(tappedItem.Name);
SettingPage comingPage = new SettingPage();
comingPage.itsButton = tappedItem;
comingPage.SetToButtonSound();
Navigation.PushModalAsync(comingPage);
}
}
}
Комментарии:
1. docs.microsoft.com/en-us/xamarin/essentials/main-thread
2. Мои конструкторы и все, что не является асинхронной задачей, не выполняются в основном потоке?
3. Сейчас у меня нет времени просматривать ваш код, но обычно, когда проблема заключается в том, что «Пользовательский интерфейс не обновляется», ответ — «MainThread»
4. Перенос содержимого в асинхронные задачи, которые повлияли на графический интерфейс, в основной поток. BeginInvokeOnMainThread(() => Кажется, это исправляет. Однако кажется, что это накладка на плохой дизайн, и я не могу понять, как это исправить должным образом.
5. Замечены две вещи (но не уверены): 1. Вам может понадобиться это
Task.Run(async () =>
в вашем конструкторе. 2. Попробуйтеawait Task.Delay(500);
вместо « Нитки. Sleep(500); «