Problem z rozwijaniem TreeView za pomocą kodu

Problem z rozwijaniem TreeView za pomocą kodu
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

Potrzebuję dokopać się za pomocą kodu do pewnych miejsc w TreeView. Kodzik:

Kopiuj
private void button2_Click(object sender, EventArgs e)
        {

            foreach (TreeNode tn in tvMain.Nodes)
            {
                if (tn.Text == "Test1")
                {
                    tn.Expand();
                }

            }

                foreach (TreeNode tn2 in tvMain.Nodes[26].Nodes)
                {

                    if (tn2.Text == "Test2")
                    {
                        richTextBox1.Text += tn2.Text + "\n";
                        tn2.Expand();
                    }
                }   

        } 

Pierwsza pętla działa, znajduje i rozwija węzeł "Test1". Z drugą jest problem, bo w powyższej postaci po prostu nie rozwija dziecka Test1. Próbowałem np while'em czekać aż tvMain.Nodes[26].Nodes.IsExpaned będzie true, ale mimo, że faktycznie jest, to następny węzeł nie jest rozwijany. W celach testowych wrzuciłem sobie MessageBox'a między pętlami, i po kliknięciu "OK" rozwijany jest "Test2". Dodam, że kolejne węzły po rozwinięciu są tworzone w czasie rzeczywistym za pomocą API. Jeśli nie da się tego naprawić w tym miejscu to wrzucę funkcję AfterExpand. Dzięki z góry.

edytowany 1x, ostatnio: m4tius
sephirot8608
  • Rejestracja:około 17 lat
  • Ostatnio:około 8 lat
  • Lokalizacja:Wrocław
0

Trochę brzydki ten Twój kod. Rozumiem, że
tvMain.Nodes[26].Nodes
jest tym samym co znaleziony wcześniej element z tekstem "Test1"? Jeżeli tak to zapamiętaj ten element po znalezieniu i użyj go do iterowania po podrzędnych.

Co to znaczy "w czasie rzeczywistym za pomocą API" ? Daj więcej kodu to będziemy mogli pomóc. Pokaż jak generujesz elementy i w jakim miejscu to wywołujesz.

edytowany 1x, ostatnio: sephirot8608
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

No faktycznie, może być trochę niejasno. tvMain.Nodes[26].Nodes to zbiór podwęzłów węzła "Test1", po którym druga pętla właśnie iteruje. Jeśli chodzi o to zapamiętywanie - akurat w tym przypadku od początku wiem, że "Test1" ma indeks 26, faktycznie niezbyt profesjonalnie, ale potem to poprawie. Napisałem celowo o czasie rzeczywistym, ponieważ węzły nie są tworzone wcześniej, ale na bieżąco w czasie "expandowania" przy pomocy API do pewnego serwisu (ten kod to fragment przerabianej na własne potrzeby aplikacji). Dlatego też myślę, że przez to druga pętla nie działa jeśli uruchomimy ją zaraz po pierwszej. Przykład z MessageBox między pętlami - po kliknięciu OK, otworzył się węzeł z drugiej pętli.

Funkcja AfterExpand:

Kopiuj
private void tvMain_AfterExpand(object sender, System.Windows.Forms.TreeViewEventArgs e)
        {
            if (e.Node != null)
            {
                e.Node.Nodes.Clear();
                //e.Node.Nodes.Add(new TreeNode("Loading..."));

                int eventParentId = 0;

                if (e.Node != null)
                {
                    CSharpAPI6.betfair.api.global.BFEvent eventItem = (CSharpAPI6.betfair.api.global.BFEvent)e.Node.Tag;
                    eventParentId = eventItem.eventId;
                }

                GetEventAsyncRequest(eventParentId, e.Node).ToString();
                
            }
            //Expanded = true;
        } 

Przyznam bez bicia, że nie ogarniam dobrze kodu całej aplikacji. Sporo plików w projekcie jak na moje małe doświadczenie.

sephirot8608
  • Rejestracja:około 17 lat
  • Ostatnio:około 8 lat
  • Lokalizacja:Wrocław
0

Spróbuj wstawić

Kopiuj
Application.DoEvents;

pomiędzy pętle (w miejscu gdzie miałeś MessageBox-a). Powinno pomóc.

M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

Niestety, wstawienie

Kopiuj
Application.DoEvents();

między pętlami nie pomogło. Specjalnie przetestowałem to na drzewie, w którym wszystkie nody znane są przed przeszukiwaniem - zadziałało. Zastanawia mnie też dlaczego takie coś nie pomaga (choć z tym jest podobnie jak z MessageBox, przed nim Count = 0, po nim wskazuje właściwą liczbę nod):

Kopiuj
while (tvMain.Nodes[id].Nodes.Count > 20); //id - indeks wyższego węzła
break;
 
sephirot8608
  • Rejestracja:około 17 lat
  • Ostatnio:około 8 lat
  • Lokalizacja:Wrocław
0

Problem będzie zapewne z funkcją GetEventAsyncRequest możesz wrzucić jej źródło? Coś wykonuje się w niej asynchronicznie (jej nazwa na to wskazuje) dlatego nie możesz się "zgrać" bo już po ustawieniu Expanded=true może się coś zmieniać w drzewie..

M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0
Kopiuj
private IAsyncResult GetEventAsyncRequest(int eventParentId, TreeNode node)
        {
            // Get session from session manager
            string session = SessionTokenManager.GetSessionToken();

            // If no session, log in and get another one
            if (session == null)
            {
                session = MakeSession();
            }

            CSharpAPI6.betfair.api.global.GetEventsReq request = null;

            request = new CSharpAPI6.betfair.api.global.GetEventsReq();
            request.header = new CSharpAPI6.betfair.api.global.APIRequestHeader();
            request.header.sessionToken = session;
            request.eventParentId = eventParentId;

            var state = new CustomAsyncStateContainer(0, node, new object[] { eventParentId, node }, DateTime.Now);

            return simpleAPIWrapper.BFGlobalService.BegingetEvents(request, GetEventAsyncCallback, state);
        } 

Jeszcze tworzenie nod:

Kopiuj
private void DisplayGetEventTypes(CSharpAPI6.betfair.api.global.GetEventTypesResp resp, CustomAsyncStateContainer state)
        {
            // We need to display information from the provided API response
            tvMain.Nodes.Clear();

            if (resp.eventTypeItems != null)
            {
                CSharpAPI6.betfair.api.global.EventType[] eventItems = resp.eventTypeItems;

                int nodeCount = eventItems.Length;
                TreeNode[] nodes = new TreeNode[nodeCount];
                for (int i = 0; i < nodeCount; i++)
                {
                    CSharpAPI6.betfair.api.global.BFEvent eventItem = new CSharpAPI6.betfair.api.global.BFEvent();
                    eventItem.eventName = eventItems[i].name;
                    eventItem.eventId = eventItems[i].id;

                    nodes[i] = new TreeNode(eventItems[i].name);
                    nodes[i].Tag = eventItem;
                    nodes[i].Nodes.Add(new TreeNode("")); // Create a fake child node
                }
                tvMain.Nodes.AddRange(nodes);
            } 
edytowany 1x, ostatnio: m4tius
sephirot8608
  • Rejestracja:około 17 lat
  • Ostatnio:około 8 lat
  • Lokalizacja:Wrocław
0

Wrzuć jeszcze deklarację IAsyncResult

edytowany 2x, ostatnio: sephirot8608
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0
Kopiuj
public interface IAsyncResult
    {
        // Summary:
        //     Gets a user-defined object that qualifies or contains information about an
        //     asynchronous operation.
        //
        // Returns:
        //     A user-defined object that qualifies or contains information about an asynchronous
        //     operation.
        object AsyncState { get; }
        //
        // Summary:
        //     Gets a System.Threading.WaitHandle that is used to wait for an asynchronous
        //     operation to complete.
        //
        // Returns:
        //     A System.Threading.WaitHandle that is used to wait for an asynchronous operation
        //     to complete.
        WaitHandle AsyncWaitHandle { get; }
        //
        // Summary:
        //     Gets a value that indicates whether the asynchronous operation completed
        //     synchronously.
        //
        // Returns:
        //     true if the asynchronous operation completed synchronously; otherwise, false.
        bool CompletedSynchronously { get; }
        //
        // Summary:
        //     Gets a value that indicates whether the asynchronous operation has completed.
        //
        // Returns:
        //     true if the operation is complete; otherwise, false.
        bool IsCompleted { get; }
    } 
sephirot8608
  • Rejestracja:około 17 lat
  • Ostatnio:około 8 lat
  • Lokalizacja:Wrocław
0

No to masz odpowiedź, musisz sprawdzić czy pole IsCompleted w obiekcie zwróconym przez GetEventAsyncRequest zawiera true. To powinieneś sprawdzać w pętli żeby upewnić się czy dane już się załadowały.

edytowany 3x, ostatnio: sephirot8608
M4
  • Rejestracja:prawie 14 lat
  • Ostatnio:ponad 7 lat
  • Postów:18
0

Hmm, nie bardzo wiem jak i w którym miejscu to zrobić. Spróbowałem wstawić while w funkcji buttona (która właśnie sprawdza i otwiera drzewa) między pętlami:

Kopiuj
while (async.IsCompleted)
                break; 

Tutaj jednak nie znalazło tego pola i dlatego zdefiniowałem zmienną async, podobnie jak w funckji MakeSession, ale nie pomogło:

Kopiuj
public string MakeSession()
        {
            string session = null;
            var async = LoginAsyncRequest(simpleAPIWrapper.username, simpleAPIWrapper.password, simpleAPIWrapper.productId, simpleAPIWrapper.softwareId, null);

            int count = 0;
            while (!async.IsCompleted || !SessionTokenManager.HasSessions)
            {
                Thread.Sleep(500);

                if ((count++) == 20)
                {
                    throw new Exception("Time out occured in \"public string MakeSession()\"");
                }
            }
            session = SessionTokenManager.GetSessionToken();

            if (session == null)
            {
                throw new Exception("String session is NULL in \"public string MakeSession()\"");
            }

            return session;
        }

To pewnie trzeba sprawdzić w AfterExpand, ale nie wiem jak się odnieść do tego pola.

edytowany 1x, ostatnio: m4tius
sephirot8608
  • Rejestracja:około 17 lat
  • Ostatnio:około 8 lat
  • Lokalizacja:Wrocław
0

Proponuję napisać klasę implementującą ten interfejs i zadeklarowanie IsCompleted jako public. A później zapisujesz rezultat do egzemplarza tej klasy.

RE
wystarczy "Completed", bo już sam w sobie ten wyraz jest przymiotnikiem.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.