1

Im new in MAUI and i have problem with tcp listener. The listener is working properly but not visualisation signals in UI at (CollectionView).The (CollectionView) in UI stay freeze. When user clicl at CollectionView show buffered signals and stop again to next change on selected row.I try async Task and Thread without succsess. Where im wrong ? Please HELP !

C# code

using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Xml;
using Microsoft.Maui.Controls;
using Npgsql;

namespace Black_Program;

public partial class SignalsPage : ContentPage
{
    public static bool searchRedy = true;
    public static int daysNotPayedAlarm = 60;
    System.Threading.Thread ReadTerminalSignals;

    public SignalsPage()
    {
        InitializeComponent();

        Task.Run(async () => await ReadFromIp());
    }

    async Task ReadFromIp()
    {
        var terminalSignalsList = new List<string>();
        int terminalSignalsCount = 0;
        TcpClient tcpclnt = new TcpClient();
        try
        {
            while (true)
            {
                try
                {
                    tcpclnt.Connect(MainPage.sqlServerIP, MainPage.sqlServerTerminalPort);
                }
                catch (Exception)
                {
                }
                while (tcpclnt.Connected)
                {
                    Thread.Sleep(10);
                    string messege = string.Empty;
                    Stream stream = tcpclnt.GetStream();
                    byte[] bytes = new byte[1024];
                    int length = stream.Read(bytes, 0, 1024);

                    /* Convert from ascii to stream */
                    for (int i = 0; i < length; i++)
                        messege += (Convert.ToChar(bytes[i]));

                    //byte[] utfBytes = Encoding.Default.GetBytes(messege);
                    messege = Encoding.UTF8.GetString(bytes);
                    try
                    {
                        ////Update new signal if object selected
                        string[] newMessages = messege
                            .Split(new char[] { '-' }
                            , StringSplitOptions.RemoveEmptyEntries)
                            .ToArray();
                        if (signals_number_search.Text == newMessages[0].TrimEnd())
                        {
                            string numberData = signals_number_search.Text.Replace(" ", string.Empty); ;// Read the input from the user.
                            DateTime time = DateTime.Now;
                            string dateToday = time.AddDays(1).ToString("yyyy'-'MM'-'dd"); // 2 days log
                            string dateBefore = time.AddDays(-5).ToString("yyyy'-'MM'-'dd");
                            ShowSignalsFromLogDB(numberData, dateToday, dateBefore);
                        }
                    }
                    catch (Exception)
                    {
                    }

                    //Application.Current.MainPage.Dispatcher.Dispatch(() => terminalSignalsList.Add(messege));
                    terminalSignalsList.Add(messege);
                    signals_terminal.ItemsSource = terminalSignalsList;

                    terminalSignalsCount++;
                    Application.Current.MainPage.Dispatcher.Dispatch(() => signals_terminal.ScrollTo(terminalSignalsCount));
                    
                }
            }
        }
        catch (Exception)
        {

        }
    }

UI Code

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Black_Program.SignalsPage"
             Title="Сигнали">
    <ScrollView
        BackgroundColor="Black">
        <!-- Navigation Menu-->
        
        
        <!-- Test design -->
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="AUTO"/><!--0-->
                <RowDefinition Height="AUTO"/><!--1-->
                <RowDefinition Height="AUTO"/><!--2-->
                <RowDefinition Height="AUTO"/><!--3-->
                <RowDefinition Height="AUTO"/><!--4-->
                <RowDefinition Height="AUTO"/><!--5-->
                <RowDefinition Height="AUTO"/><!--6-->
                <RowDefinition Height="AUTO"/><!--7-->
            </Grid.RowDefinitions>


            <!-- Cool Adres and Users -->
            <HorizontalStackLayout
                HeightRequest="{OnPlatform Default='40',iOS='40',Android='35'}"
                Margin="{OnPlatform Default='5,0,10,0',iOS='5,0,5,0',Android='5,0,5,0'}"
                Grid.Row="1"
                HorizontalOptions="CenterAndExpand">
                
                <ScrollView>
                    <CollectionView
                        MaximumHeightRequest="300"
                        x:Name="signals_terminal"
                        SelectionMode="Single">
                        <CollectionView.ItemsSource>
                            <x:Array Type="{x:Type x:String}">
                                <x:String>Няма данни</x:String>
                            </x:Array>
                        </CollectionView.ItemsSource>
                    </CollectionView>
                </ScrollView>
            </Frame>
        </Grid>
    </ScrollView>
</ContentPage>

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
Luki
  • 11
  • 3
  • 1
    you've posted way too much code - please edit it down to the specific parts that you're having a problem with. And try to provide a better explanation of the problem - ie, "method X should update UI element Y but it does not refresh with the new data" – Jason Oct 16 '22 at 17:44
  • You must use Dispatcher.Invoke() when updating a UI element from a different thread. – A.B. Oct 16 '22 at 17:54
  • I edit the code now is only part of TCP Listener. I can't better explain situation. Listener is working in background but not showing live data. When clicked on [CollectionView] show all data that reader and freeze again. I thing im wrong at function and is not working in background properly. – Luki Oct 16 '22 at 17:55
  • 2
    `catch (Exception) {}` <-- **don't do this** - your code simply swallows all exceptions, so no-wonder you're not seeing any messages or errors. – Dai Oct 16 '22 at 18:18
  • @Dai First is for no internet on server and second is for when connection interrupt when reading. No need to show errors for bad internet. But you right is bad practic. – Luki Oct 16 '22 at 18:55
  • 2
    _"No need to show errors for bad internet"_ - _eeehhhhh_-not quite: you don't need to do something like a `MessageBox`, no, but you should still have some debug/verbose logging set-up, and you **need** to inspect the caught exception's type and/or error-codes **to make sure it actually is** a bad-network error and not something more critical or unrelated in which case you should `throw;` it (or better yet: use `when` to avoid catching it in the first place). – Dai Oct 16 '22 at 18:58
  • use [MainThread](https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/appmodel/main-thread) to force UI updates to run on the UI thread – Jason Oct 16 '22 at 20:36
  • @Jason Hi. I try MainThread.BeginInvokeOnMainThread(() => {Application.Current.MainPage.Dispatcher.Dispatch(() => signals_terminal.ScrollTo(terminalSignalsCount)); }); but notw working i cant understand how to implement it in code. I put in inside my task (async Task ReadFromIp()). Any sugestions or help ? – Luki Oct 17 '22 at 12:37
  • *"not working"*: Add `Debug.WriteLine(terminalSignalsCount.ToString());` after that line. - see if that line is being called when you expect, and that terminalSignalsCount is increasing as expected. – ToolmakerSteve Oct 17 '22 at 19:14
  • @ToolmakerSteve Its working corect in background. But not updating UI. ```-ReadFromIp>>>>>>0697 - 10:20:11 - Тест -UpdateTerminalUi>>>>>>10 -ReadFromIp>>>>>>4320 - 10:20:11 - Тест -UpdateTerminalUi>>>>>>11 -ReadFromIp>>>>>>4910 - 10:20:11 - Тест -UpdateTerminalUi>>>>>>12 -ReadFromIp>>>>>>5702 - 10:20:11 - Тест -UpdateTerminalUi>>>>>>13 [EGL_emulation] app_time_stats: avg=273.12ms min=113.23ms max=661.39ms count=4 -ReadFromIp>>>>>>7259 - 10:20:14 - Тест -UpdateTerminalUi>>>>>>14 [EGL_emulation] app_time_stats: avg=2735.18ms min=2735.18ms max=2735.18ms count=1``` – Luki Oct 18 '22 at 07:22

1 Answers1

1
  • Move changes to terminalSignalsList, and setting of ItemsSource INSIDE the dispatch. Reason: anything that affects UI, safest to be run on MainThread (Dispatcher thread).
  • Index of final item is 1 less than the count. (Your count is one too high.)
  • REMOVE <ScrollView> - CollectionView does its own scrolling. (Nested scrolling can interfere.)
  • Don't need BOTH Dispatcher.Dispatch AND MainThread.Invoke... Either one should work. Result:
Application.Current.MainPage.Dispatcher.Dispatch(() =>
{
    terminalSignalsList.Add(messege);
    signals_terminal.ItemsSource = terminalSignalsList;
    signals_terminal.ScrollTo(terminalSignalsList.Count - 1));
}
ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196