Hallo,
mein erster Post hier, und gleich mit einem Problem. Habe erst vor kurzem angefangen mit WPF zu arbeiten aber es klemmt noch an vielen Stellen. Akut ist folgendes Problem:
Ich habe ein Tab, indem ich eine animierte Grafik über eine ObservableCollection (shapes) anzeigen und aktualisiert haben möchte.
(MainWindow.xaml)
[...]
<!-- -->
<!-- T A B G R A P H -->
<!-- -->
<!-- -->
<TabItem x:Name="tabGraphic" Header="Graphic" Background="{x:Null}" ClipToBounds="True" GotFocus="tabGraphic_GotFocus" KeyDown="tabGraphic_KeyDown" >
<Canvas x:Name="graphicCanvas" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ItemsControl x:Name="myItemsControl" ItemsSource="{Binding Shapes., IsAsync=True, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate x:Name="myItemTemplate">
<Canvas x:Name="myCanvas" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Canvas>
</TabItem>
[...]
Im MainWindow.xaml.cs
[...]
public MainWindow()
{
InitializeComponent();
// GraphicUI
graphicUIWorker.DoWork += graphicUIWorker_DoWork;
graphicUIWorker.RunWorkerCompleted += graphicUIWorker_RunWorkerCompleted;
graphicViewModel = new ViewModel.GraphicViewModel();
graphicViewModel.PropertyChanged += UpdateGraphic;
graphicCanvas.DataContext = this.graphicViewModel;
graphicUIWorker.RunWorkerAsync();
}
void UpdateGraphic(object sender, PropertyChangedEventArgs e)
{
designerCanvas.InvalidateArrange();
}
// Worker
void graphicUIWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker graphicUIWorker = sender as BackgroundWorker;
graphicUIWorker.WorkerReportsProgress = false;
graphicUIWorker.WorkerSupportsCancellation = true;
Dispatcher.BeginInvoke(new Action(() => { graphicViewModel.StartAnimation(); }));
}
Und die Grafik wird über das Hinzufügen von geometrischen Formen zu einer ObservableCollection erzeugt:
(GraphicViewModel.cs)
private ObservableCollection<Shape> shapes = new ObservableCollection<Shape>();
public ObservableCollection<Shape> Shapes
{
get { return shapes; }
set
{
shapes = value;
}
}
public void StartAnimation()
{
// Vertikalfahrt
foreach (double stroke in strokeList)
{
shapes.Clear();
DrawPunch(stroke);
System.Threading.Thread.Sleep(500);
}
}
private void DrawPunch(double stroke)
{
SolidColorBrush myBrush = new SolidColorBrush(Colors.Red);
//Größe
Rectangle rect = new Rectangle();
rect.Height = 300;
rect.Width = 250;
//Transparenz
rect.Opacity = 50;
//Farbe
myBrush = new SolidColorBrush(Colors.Brown);
rect.Fill = myBrush;
// Position
rect.SetValue(Canvas.LeftProperty, 100);
rect.SetValue(Canvas.TopProperty, stroke);
Shapes.Add(rect);
}
Ich habe den Code stark vereinfacht, aber die Struktur sollte erkennbar sein.
Die Idee ist, dass in einer Schleife das Rechteck neu gezeichnet wird in Abhängigkeit des Weges (stroke, wurde vorher berechnet und die Schritte in einer Liste gespeichert). Leider wird die Grafik erst ganz am Ende aktualisiert.
Ich habe nun mehrere Tage im Internet gesucht und einiges ausprobiert - komme aber keinen Schritt weiter. Nun bin ich eher noch verwirrter als zuvor. Was mache ich falsch / was habe ich übersehen oder was muss ich anders machen?
Hallo,
die GUI wird erst aktualisiert, wenn deine methode "StartAnimation" zurückkehrt. Anstall mit Sleep zu warten, muss du diese zyklisch aufrufen, z.B. mit Hilfe eines Timers (der alle 500ms) ausgelöst wird.
Grüße
Hallo und willkommen,
du hast einen typischen Anfängerfehler beim Umgang mit Threads gemacht:
deine StartAnimation-Methode läuft vollständig im GUI-Thread und durch den Sleep dort, wird die GUI blockiert, s.a. [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke)
Nur die DrawPunch-Methode darfst (bzw. mußt) du 'invoken'.
Und ich bin mir ziemlich sicher, daß du mithilfe der WPF-Animationsklasse wesentlich besser zum Ergebnis kämst.
Vielen Dank für die Antworten. Ich habe mir gestern Abend in ruhe schonmal die FAQ dazu nochmals durchgelesen. Ganz klar, wie ich meine DrawPunch-Routine aufrufen soll ist mir noch nicht, aber ich versuche es mal.
Die Animationsgeschichte habe ich mir vorher schonmal angeschaut - für die einfache Bewegungen z.B. des Stempels sicherlich geeignet. Der Stempel verformt allerdings ein Blech, dessen Darstellung und Verformung nicht ganz so einfach ist - daher habe ich davon Abstand genommen.