Laden...

Alle Controls für kurze Zeit auf Aktiv setzen

Erstellt von Briefkasten vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.785 Views
Briefkasten Themenstarter:in
446 Beiträge seit 2004
vor 12 Jahren
Alle Controls für kurze Zeit auf Aktiv setzen

Hallo,

ich habe eine Liste von Controls die ich alle nach der Reihe kurz aktiv setzen will. Ich hab das momentan so gemacht:

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (var item in _GraphVisualization.VertexVisualizationList)
            {
                item.Focus();
                Thread.Sleep(900);
            }
        }
                    <Style TargetType="{x:Type ui:VertexVisualization}">
                        <Style.Triggers>                           <Trigger Property="IsFocused" Value="True">
                                <Setter Property="BorderBrush" Value="Green" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>

Das Programm soll also alle Controls kurzzeitig auf Aktiv setzen, damit man sieht wo sie sich befinden.

Allerdings klappt das mit dem Focus nicht so recht. Wenn ich auf den Button klicke tut sich einige Zeit gar nichts und am Schluss ist nur ein Control Grün umrahmt.

Hat jemand eine Idee warum das so ist und wie ich das lösen kann?

Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp

1.346 Beiträge seit 2008
vor 12 Jahren
Briefkasten Themenstarter:in
446 Beiträge seit 2004
vor 12 Jahren

Ich habs auch so schon probiert gehabt ohne erfolg:


            Thread setFocusonControls = new Thread(new ThreadStart(delegate
            {

                this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(
                    delegate()
                    {
                        foreach (var item in this.buttonlist)
                        {
                            item.Background = Brushes.Green;
                            Thread.Sleep(900);


                        }
                    }));

            }));
            setFocusonControls.Start();

Im Prinzip geht, es darum, dass ein Algorithmus visualisiert wird. Je nach dem bei welchem Element gerade ist wird das Visualisierende Element Gefocused, damit er per Trigger anzeigt, dass der Algorithmus gerade "hier" ist.

Da er den Algorithmus zu schnell abarbeitet, muss ich ihn bremsen, damit man auch sieht, wie er schritt für schritt alles ab arbeitet.

Gibts eine bessere möglichkeit, das mit Thread.Sleep zu lösen?

Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp

D
615 Beiträge seit 2009
vor 12 Jahren

Hallo Briefkasten

Gibts eine bessere möglichkeit, das mit Thread.Sleep zu lösen?

Schau dir ggf. mal dies an : WaitOne

Beste Grüsse

Diräkt

16.827 Beiträge seit 2008
vor 12 Jahren

Wenn die Animation der Controls in einem eigenen Thread läuft - und das sollte sie - ist das Sleep nicht so schlimm.
Dann musst halt für jedes Control "invoken", damit Du auf den GUI-Thread zugreifen darfst. Aber da wirst nich drumrum kommen.

Prinzipiell wird aber pdelvo mit seinem Einwand recht haben.

Alternativ kann man das auch alles über Events lösen. Denke eine Story is hier nicht angebracht, da dynamisch.

1.552 Beiträge seit 2010
vor 12 Jahren

Wenn die Animation der Controls in einem eigenen Thread läuft - und das sollte sie - ist das Sleep nicht so schlimm.

Verbessere mich wenn ich mich irre, aber er invoked zwar die Action, jedoch ist in diesem invoke Block wiederrum ein Thread.Sleep drinnen, welcher im GUI-Thread ausgeführt wird und somit die GUI blockiert wird.

@Briefkasten,
wenn du die Controls im Abstand von .9 Sekunden fokusieren möchtest, schiebe alles zusammen in einen DispatcherTimer, der dir alle .9 Sekunden eine Aktion ausführt. Dort in dieser Aktion kannst du deine Controls fokusieren und machen was du willst, da die Aktion immer im GUI-Thread ausgeführt wird

Gruß
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

Briefkasten Themenstarter:in
446 Beiträge seit 2004
vor 12 Jahren

@Briefkasten,
wenn du die Controls im Abstand von .9 Sekunden fokusieren möchtest, schiebe alles zusammen in einen DispatcherTimer, der dir alle .9 Sekunden eine Aktion ausführt. Dort in dieser Aktion kannst du deine Controls fokusieren und machen was du willst, da die Aktion immer im GUI-Thread ausgeführt wird

Gruß
Michael

Hallo,

vielen Dank! Das war die Lösung.

Hier noch ein Bsp http://wangmo.wordpress.com/2007/09/07/dispatchertimer-in-wpf/

Hier noch der Code:

            //count all VertexControls
            int counter = _GraphVisualization.VertexVisualizationList.Count;

            timer.Interval = TimeSpan.FromMilliseconds((9 * 120));
            //iterate from behind and save iteration position so that only one control in the eventhandler will be set IsFocused=true
            timer.Tick += new EventHandler(new EventHandler(delegate
            {
                if (counter == -1) this.timer.Stop();
                for (int i = counter; i > 0; i--)
                {
                    Vertex v = _GraphVisualization.VertexVisualizationList[i - 1].Vertex;

                    _GraphVisualization.setFocus(v);
                    counter--;
                    return;

                }
            }));
            timer.Start();

Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp

Briefkasten Themenstarter:in
446 Beiträge seit 2004
vor 12 Jahren

Also angenommen ich will den Algo. DFS (Depth-first search) visualsieren)

Die Methode von DFS sieht dann in etwa so aus.

  procedure DFS(G,v):
2      label v as explored
3      for all edges e in G.incidentEdges(v) do
4          if edge e is unexplored then
5              w  G.opposite(v,e)
6              if vertex w is unexplored then
7                  label e as a discovery edge
8                  recursively call DFS(G,w)
9          else 
10             label e as a back edge

Jetzt muss ich irgendwie zeigen, dass der Algorithmus gerade bei Vertex x bzw. Edge y ist. Also setze ich den Focus im DFS Algo. (grob das man ca. weiß was ich meine)

 procedure DFS(G,v):
     label v as explored
     for all edges e in G.incidentEdges(v) do
         [COLOR]_graphcontrol.setFocus(edge);
[/color]
         if edge e is unexplored then
             w ? G.opposite(v,e)
             if vertex w is unexplored then
                [COLOR]_graphcontrol.setFocus(vertex );
[/color]
                 label e as a discovery edge
                 recursively call DFS(G,w)
         else 
             label e as a back edge

Nun das Problem ist wie gesagt, dass der Algo. viel zu schnell abgearbeitet wird. Nur wie kann ich hier den DispatcherTimer verwenden?

Als einzige Lösung fällt mir ein, dass ich zum DFS algo. Flags einbauen, damit der Dispatcher weiß, wo er bereits war, und wo er weiter machen muss. Das ganze wird aber somit unglaublich umständlich und komplex. Hat jemand vlt. eine Idee wie das ganze einfacher gehen würde?

Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp

5.742 Beiträge seit 2007
vor 12 Jahren

Hallo Briefkasten,

lasse den Algorithmus einfach in einem zweiten Thread laufen und visualisiere den Forschritt im UI Thread (Invoke nicht vergessen!).

Durch z.B. ManualResetEvents kannst du den Algorithmus dann noch entsprechend ausbremsen.

Briefkasten Themenstarter:in
446 Beiträge seit 2004
vor 12 Jahren

Hallo,

danke für den Tipp. Damit hats geklappt. Hier meine Lösung:

            Thread thread = new Thread(new ParameterizedThreadStart(delegate(object arr) { GetAllV((Vertex)(arr), null); }));
            thread.Start(graph.Vertices.First());

        }
        ManualResetEvent mre = new ManualResetEvent(false);
        public void GetAllV(Vertex v, Vertex firstVertex) //als bsp alle vertices mal durchlaufen
        {
            if (v == firstVertex) return;
            if (firstVertex == null) firstVertex = v;

            _GraphVisualization.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(
              delegate()
              {
                  _GraphVisualization.setFocus(v);
              }));
            mre.WaitOne(10 * 120);

            foreach (Edge e in v.Edges)
            {
                GetAllV(e.V, firstVertex);
                return; //weil z.b Vertex 3 -> 4 und 3->4 verbunden sein kann
            }

        }

Ich werd noch schauen, dass ich

_GraphVisualization.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(
              delegate()
              {
                  _GraphVisualization.setFocus(v);
              }));

das irgendwie auslagern kann, damit es etwas schöner aussieht.

Schaut mal im IRC vorbei:
Server: https://libera.chat/ ##chsarp