Problem z pingowaniem

0

Witam.
Tworzę launcher do gry i mam problem z pingowaniem serwera.
Gdy uruchamiam aplikację wszystko ładuje się do momentu odczytania wiadomości z serwera, a dokładniej ilości graczy i czy serwer jest aktywny.
Launcher zawiesza się lub dłuższą chwilę ładuje dane i zostają one pokazane.
Wiadomo, że dla użytkownika takiej aplikacji jest to mega uciążliwe i chciałbym się pozbyć tego problemu.

Tutaj kod używany podczas ładowania strony głównej:

        private void Window_Loaded(object sender, EventArgs e)
        {
            MineStat ms = new MineStat("mc.skkf.net", 25565);
            if (ms.ServerUp)
            {
            serverstatus2.Text = ms.CurrentPlayers;
            }
            else
                serverstatus2.Text = "Server is offline!";

        }

Tutaj kod na pingowanie serwera stworzony przez ldilley z GitHuba:

using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Diagnostics;

namespace launchek.Core
{
    public class MineStat
    {
        const ushort dataSize = 512;  // this will hopefully suffice since the MotD should be <=59 characters
        const ushort numFields = 6;   // number of values expected from server
        const int defaultTimeout = 5; // default TCP timeout in seconds

        public string Address { get; set; }
        public ushort Port { get; set; }
        public int Timeout { get; set; }
        public string Motd { get; set; }
        public string Version { get; set; }
        public string CurrentPlayers { get; set; }
        public string MaximumPlayers { get; set; }
        public bool ServerUp { get; set; }
        public long Latency { get; set; }

        public MineStat(string address, ushort port, int timeout = defaultTimeout)
        {
            var rawServerData = new byte[dataSize];

            Address = address;
            Port = port;
            Timeout = timeout * 1000;   // milliseconds

            try
            {
                var stopWatch = new Stopwatch();
                var tcpclient = new TcpClient();
                tcpclient.ReceiveTimeout = Timeout;
                stopWatch.Start();
                tcpclient.Connect(address, port);
                stopWatch.Stop();
                Latency = stopWatch.ElapsedMilliseconds;
                var stream = tcpclient.GetStream();
                var payload = new byte[] { 0xFE, 0x01 };
                stream.Write(payload, 0, payload.Length);
                stream.Read(rawServerData, 0, dataSize);
                tcpclient.Close();
            }
            catch (Exception)
            {
                ServerUp = false;
                return;
            }

            if (rawServerData == null || rawServerData.Length == 0)
            {
                ServerUp = false;
            }
            else
            {
                var serverData = Encoding.Unicode.GetString(rawServerData).Split("\u0000\u0000\u0000".ToCharArray());
                if (serverData != null && serverData.Length >= numFields)
                {
                    ServerUp = true;
                    Version = serverData[2];
                    Motd = serverData[3];
                    CurrentPlayers = serverData[4];
                    MaximumPlayers = serverData[5];
                }
                else
                {
                    ServerUp = false;
                }
            }
        }

        #region Obsolete

        [Obsolete]
        public string GetAddress()
        {
            return Address;
        }

        [Obsolete]
        public void SetAddress(string address)
        {
            Address = address;
        }

        [Obsolete]
        public ushort GetPort()
        {
            return Port;
        }

        [Obsolete]
        public void SetPort(ushort port)
        {
            Port = port;
        }

        [Obsolete]
        public string GetMotd()
        {
            return Motd;
        }

        [Obsolete]
        public void SetMotd(string motd)
        {
            Motd = motd;
        }

        [Obsolete]
        public string GetVersion()
        {
            return Version;
        }

        [Obsolete]
        public void SetVersion(string version)
        {
            Version = version;
        }

        [Obsolete]
        public string GetCurrentPlayers()
        {
            return CurrentPlayers;
        }

        [Obsolete]
        public void SetCurrentPlayers(string currentPlayers)
        {
            CurrentPlayers = currentPlayers;
        }

        [Obsolete]
        public string GetMaximumPlayers()
        {
            return MaximumPlayers;
        }

        [Obsolete]
        public void SetMaximumPlayers(string maximumPlayers)
        {
            MaximumPlayers = maximumPlayers;
        }

        [Obsolete]
        public long GetLatency()
        {
            return Latency;
        }

        [Obsolete]
        public void SetLatency(long latency)
        {
            Latency = latency;
        }

        [Obsolete]
        public bool IsServerUp()
        {
            return ServerUp;
        }

        #endregion
    }
}

Dziękuję za wszelką pomoc!

1

Spróbuj utworzyć taką metodę

        public static async Task LoadServerInfo()
        {
            await Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Server is offline!";
            });
        }

I w Window_Load zastąp tamten kod wywołaniem funkcji LoadServerInfo();
Uruchom i daj znać czy działa.

EDIT: Nie wiem czy java nie byłaby lepszym rozwiązaniem.

0
Yukiteru Gromadzki napisał(a):

Spróbuj utworzyć taką metodę

        public static async Task LoadServerInfo()
        {
            await Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Server is offline!";
            });
        }

I w Window_Load zastąp tamten kod wywołaniem funkcji LoadServerInfo();
Uruchom i daj znać czy działa.

EDIT: Nie wiem czy java nie byłaby lepszym rozwiązaniem.

Teoretycznie ldilley wrzucił również kod JS oraz Java, ale nie znam się na tym kompletnie + nie wiem czy jest możliwość dodania go w aplikacji tworzonej w C# WPF.

Co do Twojej metody:

  • dodałem odwołanie do obiektu
HomePage hmp = new HomePage();
hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Server is offline!";
  • dostaję błędny komunikat "CS0123 C# Żadne z przeciążeń dla elementu „LoadServerInfo” nie pasuje do delegata „RoutedEventHandler”."
0

To LoadServerInfo powinieneś odpalać wewnątrz Window_Loaded, robisz tak?

0
Ktos napisał(a):

To LoadServerInfo powinieneś odpalać wewnątrz Window_Loaded, robisz tak?

        private void Window_Loaded(object sender, EventArgs e)
        {
            string RootPath = Environment.GetEnvironmentVariable("appdata") + "\\SkyCraft";

            Minecraft.init(RootPath);
            versions = MProfileInfo.GetProfiles();
            Versions.Items.Clear();
            foreach (var item in versions)
            {
                Versions.Items.Add(item.Name);
            }

            async Task LoadServerInfo()
            {
                await Task.Run(() =>
                {
                    MineStat ms = new MineStat("mc.skkf.net", 25565);
                    serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Server is offline!";
                });
            }
        }

Dokładnie tak to robię.
Nie ma żadnego rezultatu.
"Ostrzeżenie CS8321 Funkcja lokalna „LoadServerInfo” jest zadeklarowana, lecz nie jest nigdy używana"

1

Wklej ją na poziomie klasy i wewnątrz Window_Loaded uruchom (po prostu LoadServerInfo();), bo tak obecnie to tworzysz funkcję wewnętrzną i nie odpalasz.

0
Ktos napisał(a):

Wklej ją na poziomie klasy i wewnątrz Window_Loaded uruchom (po prostu LoadServerInfo();), bo tak obecnie to tworzysz funkcję wewnętrzną i nie odpalasz.

Zrobiłem to w następujący sposób:

    public partial class HomePage : Page
    {
        public static async Task LoadServerInfo()
        {
            await Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                HomePage hmp = new HomePage();
                hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Server is offline!";
            });
        }
        public HomePage()
        {
            InitializeComponent();

        }

        MProfileInfo[] versions;
        MSession session;
        GamePatch Patcher;

        private void Window_Loaded(object sender, EventArgs e)
        {
            LoadServerInfo();
        }

Całość nie zawiera błędów, jedynie ostrzeżenie odnośnie LoadServerInfo();:
"CS4014 Ponieważ to wywołanie nie jest oczekiwane, wykonywanie bieżącej metody będzie kontynuowane bez oczekiwania na ukończenie wywołania. Rozważ możliwość zastosowania operatora „await” do wyniku wywołania."
Jednak całość nadal nie działa.

0
Yukiteru Gromadzki

Po prostu nie działa. Wyskakuje takie ostrzeżenie, lecz po załadowaniu aplikacji całość nie działa.

2

Generalnie Task użyty tutaj służy do tego, żeby okno użytkownika się załadowało i mógł on na nim wykonywać akcje, a same dane zostały doczytane "na boku" i zaktualizowały się, kiedy zostaną pobrane. Więc nie wiem, czy dobrze zrobiłeś wrzucając "HomePage hmp = new HomePage();" w LoadServerInfo();

Poza tym kod stworzony przez ldilley ma pewną wadę, a mianowicie ustawia timeout dla TcpClient tylko podczas odbioru wiadomości.
Proponuję w nim zmienić kawałek:

                tcpclient.ReceiveTimeout = Timeout;
                stopWatch.Start();
                tcpclient.Connect(address, port);

Na:

                tcpclient.ReceiveTimeout = Timeout;
                tcpclient.SendTimeout = Timeout;
                stopWatch.Start();
                var result = tcpclient.BeginConnect(address, port, null, null);
                var success = result.AsyncWaitHandle.WaitOne(Timeout);
                if (!success)
                {
                    throw new Exception("Connection timed out.");
                }
0
Dyzma napisał(a):

Generalnie Task użyty tutaj służy do tego, żeby okno użytkownika się załadowało i mógł on na nim wykonywać akcje, a same dane zostały doczytane "na boku" i zaktualizowały się, kiedy zostaną pobrane. Więc nie wiem, czy dobrze zrobiłeś wrzucając "HomePage hmp = new HomePage();" w LoadServerInfo();

Poza tym kod stworzony przez ldilley ma pewną wadę, a mianowicie ustawia timeout dla TcpClient tylko podczas odbioru wiadomości.
Proponuję w nim zmienić kawałek:

                tcpclient.ReceiveTimeout = Timeout;
                stopWatch.Start();
                tcpclient.Connect(address, port);

Na:

                tcpclient.ReceiveTimeout = Timeout;
                tcpclient.SendTimeout = Timeout;
                stopWatch.Start();
                var result = tcpclient.BeginConnect(address, port, null, null);
                var success = result.AsyncWaitHandle.WaitOne(Timeout);
                if (!success)
                {
                    throw new Exception("Connection timed out.");
                }

Zrobiłem tak jak powiedziałeś, lecz nic to nie dało :/
Nadal cała aplikacja zacina się podczas ładowania informacji o serwerze + pokazuje, że serwer jest offline podczas gdy jest włączony.

0

A zrobiłeś coś z "HomePage hmp = new HomePage();" w LoadServerInfo(); ?

0
Dyzma napisał(a):

A zrobiłeś coś z "HomePage hmp = new HomePage();" w LoadServerInfo(); ?

Edytowałem ten element, który napisałeś wyżej, a w Window_Loaded zmieniłem cały kod na ten, który był na samym początku.

        private void Window_Loaded(object sender, EventArgs e)
        {
            MineStat ms = new MineStat("mc.skkf.net", 25565);
            if (ms.ServerUp)
            {
                serverstatus2.Text = ms.CurrentPlayers;
            }
            else
                serverstatus2.Text = "Offline";
1

Poprawka, którą zaproponowałem do kodu ldilley ma na celu jedynie umożliwienie ustawienia czasu połączenia i wysyłania wiadomości, po którym nastąpi timeout.
Sama w sobie nie rozwiąże problemu, bo jak pisałem, po to jest Task. Żeby umożliwić interakcje dla użytkownika, kiedy trwa połączenie z serwerem i pobieranie danych.
Dalej potrzebujesz Task'ów. Wrzucasz jedynie kawałki kodu i do tego partiale, więc nie wiem, jak Ci to pokazać konkretnie, bo nie znam flow w Twoim programie.

0
Dyzma napisał(a):

Poprawka, którą zaproponowałem do kodu ldilley ma na celu jedynie umożliwienie ustawienia czasu połączenia i wysyłania wiadomości, po którym nastąpi timeout.
Sama w sobie nie rozwiąże problemu, bo jak pisałem, po to jest Task. Żeby umożliwić interakcje dla użytkownika, kiedy trwa połączenie z serwerem i pobieranie danych.
Dalej potrzebujesz Task'ów. Wrzucasz jedynie kawałki kodu i do tego partiale, więc nie wiem, jak Ci to pokazać konkretnie, bo nie znam flow w Twoim programie.

Działanie aplikacji odbywa się następująco:

  • progressbar z pobieraniem javy
  • okno ze stroną logowania
  • następne okno ze stroną główną
  • reszta stron odpowiadających za poszczególne funkcje

Problem leży w tym, że po zalogowaniu się przez użytkownika przerzuca go z okna logowania do okna ze stroną główną na której znajduje się informacja o tym czy serwer jest aktualnie aktywny czy też nie. W momencie przerzucenia ładowane są dane na temat aktywności serwera przez co dochodzi do około 10/15s zwieszenia się programu przed ukazaniem informacji.
Moim pytaniem było czy jest opcja zmniejszenia do minimum / wyeliminowania tego zwieszenia.

0

Jedyne co możesz zrobić, jeśli odpowiedź trwa tak długo (swoją drogą, to ciekawy serwer skoro tyle odpowiada), to użyć w/w task'ów.
Wtedy w momencie kiedy użytkownikowi pokazuje się strona główna nie czytasz od razu danych z serwera.
Ładujesz wszystko co potrzebne poza tymi danymi, a pobranie tych danych odpalasz "w tle" właśnie na oddzielnym task'u.
Efekt będzie taki, że użytkownik wbije na stronę główną, danych nie zobaczy, bo będą puste (można dodać jakiegoś progres bara "pobieranie danych w toku"),
ale będzie mógł od razu korzystać z tej strony.

0
Dyzma napisał(a):

Jedyne co możesz zrobić, jeśli odpowiedź trwa tak długo, to użyć w/w task'ów.
Wtedy w momencie kiedy użytkownikowi pokazuje się strona główna nie czytasz od razu danych z serwera.
Ładujesz wszystko co potrzebne poza tymi danymi, a pobranie tych danych odpalasz "w tle" właśnie na oddzielnym task'u.
Efekt będzie taki, że użytkownik wbije na stronę główną, danych nie zobaczy, bo będą puste (można dodać jakiegoś progres bara "pobieranie danych w toku"),
ale będzie mógł od razu korzystać z tej strony.

Szczerze mówiąc jestem początkujący w sprawie pisania aplikacji, staram się być samoukiem i czerpać z Internetu i porad innych jak najwięcej.
Rozumiem o co Ci chodzi i w jaki sposób miało by to funkcjonować, zwizualizowałem to sobie w głowie, lecz nie mam pomysłu jak stworzyć takowy proces w tle.

1

Ten proces w tle to właśnie ten fragment kodu:

        public static async Task LoadServerInfo()
        {
            await Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Server is offline!";
            });
        }

Dorzuciłeś wcześniej do niego:

HomePage hmp = new HomePage();

Co może nie być najlepszym pomysłem, bo ten obiekt wydaje mi się powinien już istnieć w momencie wywołania LoadServerInfo().
Jedyne co ma robić ta funkcja to uzupełnić danymi istniejący obiekt.
Czyli ładujesz okno główne dla użytkownika, kończy się ładowanie kontrolek i wszystkich innych funkcjonalności, wtedy wołasz funkcję LoadServerInfo(),
która zaczyna w tle pobierać dane i jak skończy uzupełni puste pola w oknie głównym.

Radzę poczytać o taskach w C#. Wbrew pozorom podstawowa wielowątkowość oparta właśnie o taski jest względnie prosta i rozwiązuje wiele problemów. ;)
(Czasami inne generuje, ale to już inna bajka...)

0
Dyzma napisał(a):

Dorzuciłeś wcześniej do niego:

HomePage hmp = new HomePage();

Co może nie być najlepszym pomysłem, bo ten obiekt wydaje mi się powinien już istnieć w momencie wywołania LoadServerInfo().
Jedyne co ma robić ta funkcja to uzupełnić danymi istniejący obiekt.
Czyli ładujesz okno główne dla użytkownika, kończy się ładowanie kontrolek i wszystkich innych funkcjonalności, wtedy wołasz funkcję LoadServerInfo(),
która zaczyna w tle pobierać dane i jak skończy uzupełni puste pola w oknie głównym.

To jest aktualny początek strony

    public partial class HomePage : Page
    {
        public HomePage()
        {
            InitializeComponent();

        }

Gdy nie stworzę HomePage hmp = new HomePage(); i nie wstawię go w to miejsce hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Server is offline!"; to całość wyrzuca błąd, iż serverstatus2.Text musi mieć odwołanie do obiektu, chociaż obiekt jest na tej stronie stworzony.
Dopiero po wrzuceniu hmp. całość usuwa błąd.

0

Pokaż kod jak możesz. Żeby było widać gdzie wołasz metody, gdzie tworzysz obiekt i czy jedno do drugiego ma dostęp.
Bo jakby co, ten obiekt stwórz wcześniej. Tak, żeby metoda mogła się do niego odwołać.

0
Dyzma napisał(a):

Pokaż kod jak możesz. Żeby było widać gdzie wołasz metody, gdzie tworzysz obiekt i czy jedno do drugiego ma dostęp.
Bo jakby co, ten obiekt stwórz wcześniej. Tak, żeby metoda mogła się do niego odwołać.

namespace launchek
{
    /// <summary>
    /// Logika interakcji dla klasy HomePage.xaml
    /// </summary>
    public partial class HomePage : Page
    {
        public static async Task LoadServerInfo()
        {
            HomePage hmp = new HomePage();
            await Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
            });
        }
        public HomePage()
        {
            InitializeComponent();
        }


        MProfileInfo[] versions;
        MSession session;
        GamePatch Patcher;

        private void Window_Loaded(object sender, EventArgs e)
        {
            LoadServerInfo();

            string RootPath = Environment.GetEnvironmentVariable("appdata") + "\\SkyCraft";

            Minecraft.init(RootPath);
            versions = MProfileInfo.GetProfiles();
            Versions.Items.Clear();
            foreach (var item in versions)
            {
                Versions.Items.Add(item.Name);
            }
            Patcher = new GamePatch(session);

        }

        private void Play_Click_Btn(object sender, RoutedEventArgs e)
        {

        }

        private void GameFolder_Click_Btn(object sender, RoutedEventArgs e)
        {
            Patcher.OpenFolder();
        }
    }
}

Co do LoadServerInfo(); w Window_Loaded wyskakuje mi ostrzeżenie: "CS4014 Ponieważ to wywołanie nie jest oczekiwane, wykonywanie bieżącej metody będzie kontynuowane bez oczekiwania na ukończenie wywołania. Rozważ możliwość zastosowania operatora „await” do wyniku wywołania."

1

Co do ostrzeżenia, wynika ono z tego, że nigdzie nie czekasz, aż to się wywoła. Ale Ty nie chcesz czekać, więc jest ok. ;)
Spróbuj tak:

namespace launchek
{
    /// <summary>
    /// Logika interakcji dla klasy HomePage.xaml
    /// </summary>
    public partial class HomePage : Page
    {
        public HomePage()
        {
            InitializeComponent();
        }

        MProfileInfo[] versions;
        MSession session;
        GamePatch Patcher;

        private void Window_Loaded(object sender, EventArgs e)
        {
            HomePage hmp = new HomePage();
            Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
            });

            string RootPath = Environment.GetEnvironmentVariable("appdata") + "\\SkyCraft";

            Minecraft.init(RootPath);
            versions = MProfileInfo.GetProfiles();
            Versions.Items.Clear();
            foreach (var item in versions)
            {
                Versions.Items.Add(item.Name);
            }
            Patcher = new GamePatch(session);

        }

        private void Play_Click_Btn(object sender, RoutedEventArgs e)
        {

        }

        private void GameFolder_Click_Btn(object sender, RoutedEventArgs e)
        {
            Patcher.OpenFolder();
        }
    }
}
0
Dyzma napisał(a):

Co do ostrzeżenia, wynika ono z tego, że nigdzie nie czekasz, aż to się wywoła. Ale Ty nie chcesz czekać, więc jest ok. ;)

Całość załączyła się normalnie, lecz po dojściu do momentu hmp.serverstatus2 = ms.ServerUp ? ms.CurrentPlayers : "Offline"; wyskakuje błąd "System.InvalidOperationException: „Wątek wywołujący nie może uzyskać dostępu do tego obiektu, ponieważ należy on do innego wątku.”
Stworzyłem string:

        private void Window_Loaded(object sender, EventArgs e)
        {
            string status2 = serverstatus2.Text;
            Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                status2 = ms.ServerUp ? ms.CurrentPlayers : "Offline";
            });

Po uruchomieniu całość nie wyrzuca żadnego błędu, lecz z napisem status nic się nie dzieje.

Dane wyjściowe:
"Wątek 0xf08 zakończył działanie z kodem 0 (0x0).
Zgłoszony wyjątek: „System.Exception” w launchek.exe
Wątek 0x4178 zakończył działanie z kodem 0 (0x0).
Wątek 0x3c90 zakończył działanie z kodem 0 (0x0).
Wątek 0x5254 zakończył działanie z kodem 0 (0x0).
Wątek 0x1ac0 zakończył działanie z kodem 0 (0x0).
Wątek 0x25d0 zakończył działanie z kodem 0 (0x0)."

2

Ach sorry, zapomniałem. Nie zrobisz tego bezpośrednio, bo GUI leci na innym wątku.
Zmień:

            Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
            });

Na:

            Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                if (hmp.serverstatus2.Text.InvokeRequired)
                    hmp.serverstatus2.Text.Invoke(new Action(() => hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"));
                else
                    hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
            });

EDIT: Poprawiłem nazwy kontrolki.

0
Dyzma napisał(a):

Ach sorry, zapomniałem. Nie zrobisz tego bezpośrednio, bo GUI leci na innym wątku.

Zmieniłem, lecz pojawia się błąd "CS1061 Element „string” nie zawiera definicji „Invoke” i nie odnaleziono dostępnej metody rozszerzenia „Invoke”, która przyjmuje pierwszy argument typu „string” (czy nie brakuje dyrektywy using lub odwołania do zestawu?)."

Pamiętam, że też miałem jakiś problem z Invoke w C# i dodawałem "System.Windows..." przed, ale nie pamiętam jak to dokładnie się robiło.

1

Ponownie sorry, piszę w przerwach w pracy i za dużo copy-paste zrobiłem.
Poprawiona wersja:

            Task.Run(() =>
            {
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                if (hmp.serverstatus2.InvokeRequired)
                    hmp.serverstatus2.Invoke(new Action(() => hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"));
                else
                    hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
            });
0
Dyzma napisał(a):

Ponownie sorry, piszę w przerwach w pracy i za dużo copy-paste zrobiłem.

Rozumiem, ale i tak się cieszę, że ktokolwiek zainteresował się tym, żeby mi pomóc i jestem wdzięczny.

Teraz pokazuje mi informację o tym, że TextBlock nie zawiera tej definicji.
Jeszcze dodając - zapomniałem wspomnieć, że piszę to w C# WPF. O ile się nie mylę jest to dosyć istotna informacja, a zapomniałem jej dodać :/
Aktualny kod:

        private void Window_Loaded(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                HomePage hmp = new HomePage();
                MineStat ms = new MineStat("mc.skkf.net", 25565);
                if (hmp.serverstatus2.InvokeRequired)
                    hmp.serverstatus2.Invoke(new Action(() => hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"));
                else
                    hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
            });

Błąd: "CS1061 Element „TextBlock” nie zawiera definicji „Invoke” i nie odnaleziono dostępnej metody rozszerzenia „Invoke”, która przyjmuje pierwszy argument typu „TextBlock” (czy nie brakuje dyrektywy using lub odwołania do zestawu?)."

1

Spoko, nie ma sprawy. ;)
Co do WPF'a, to zmienia postać rzeczy.
Zmień:

                if (hmp.serverstatus2.InvokeRequired)
                    hmp.serverstatus2.Invoke(new Action(() => hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"));
                else
                    hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";

Na:

if (hmp.serverstatus2.Dispatcher.CheckAccess())
     hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
else
     hmp.serverstatus2.Dispatcher.Invoke((Action) (() => { hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline" } ));

Powinno zadziałać, ale za to już nie ręczę.

2

Tę składnię Invoke można nieco uprościć:

Dispatcher.Invoke(() => { hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline" });
0
Ktos napisał(a):

Tę składnię Invoke można nieco uprościć:

Po uproszczeniu MineStat "Błąd IDE1008 'Element „MineStat” nie zawiera konstruktora, który przyjmuje wiele argumentów. "

Dyzma napisał(a):
if (hmp.serverstatus2.Dispatcher.CheckAccess())
     hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline";
else
     hmp.serverstatus2.Dispatcher.Invoke((Action) (() => { hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline" } ));

Powinno zadziałać, ale za to już nie ręczę.

Tutaj dodałem Dispatcher.Invoke

                if (hmp.serverstatus2.InvokeRequired)
                    hmp.serverstatus2.Dispatcher.Invoke(new Action(() => hmp.serverstatus2.Text = ms.ServerUp ? ms.CurrentPlayers : "Offline"));

lecz przy InvokeRequired wyskakuje błąd: "Błąd CS1061 Element „TextBlock” nie zawiera definicji „InvokeRequired” i nie odnaleziono dostępnej metody rozszerzenia „InvokeRequired”, która przyjmuje pierwszy argument typu „TextBlock” (czy nie brakuje dyrektywy using lub odwołania do zestawu?)."

0

Zamiast:

if (hmp.serverstatus2.InvokeRequired)

Ma być:

if (hmp.serverstatus2.Dispatcher.CheckAccess())

Rzuć okiem na przykład ode mnie. ;)
Swoja drogą po "uproszczeniu" nie powinien rzucać takim błędów.
Zastosuj uproszczenie i wrzuć ponownie cały kod.

1 użytkowników online, w tym zalogowanych: 0, gości: 1