Laden...

Modern UI for WPF - Punkte auf Kreis animieren

Erstellt von AndyRandy691 vor 7 Jahren Letzter Beitrag vor 7 Jahren 3.031 Views
A
AndyRandy691 Themenstarter:in
6 Beiträge seit 2016
vor 7 Jahren
Modern UI for WPF - Punkte auf Kreis animieren

Hallo zusammen,

ich bin zur Zeit damit beschäftigt ein Programm für kleine Kartrennen zu entwickeln. Dieses soll in der Lage sein die Zwischenzeiten, Rundenzeiten etc. aus einem XML-Stream zu erfassen und weiterzuverarbeiten. Die Erfassung funktioniert soweit schon ganz gut. Neben der Darstellung der Daten in einem DataGrid soll auch eine s.g. CircleMap enthalten sein. Diese ist so gedacht, dass jedes fahrende Kart hier als Punkt auf einem Kreis umläuft und eine Runde des Karts auf der Strecke eine Runde des jeweiligen Punktes auf dem Kreis entsprechen soll.
Da in diesem Fall dynamisch gezeichnet werden muss, entschied ich mich mein kleines Programm fortan nicht mehr als Windows Form, sondern als WPF Application zu entwickeln.

Leider bin ich was WPF angeht ein totaler Neuling. Deshalb habe ich mich mit Hilfe von video2brain, openbooks und dem Rest des Netzes versucht in die Thematik einzuarbeiten. Dabei stieß ich auf die open-source library Modern UI for WPF, welche ich gerne für mein Programm benutzen möchte.

Die XAML des MainWindow sieht folgender maßen aus:


<mui:ModernWindow x:Name="Main" x:Class="TimingToolWPF.MainWindow"
                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                  xmlns:mui="http://firstfloorsoftware.com/ModernUI"
                  xmlns:sys="clr-namespace:System;assembly=mscorlib"
                  Title="ROWE Timing Tool" 
                  Height="900" Width="1600"
                  WindowState="Maximized"
                  ContentSource="Pages/Timing.xaml"
                  Padding="10,0,10,0">

        <mui:ModernWindow.MenuLinkGroups>
            <mui:LinkGroup DisplayName="Timing">
                <mui:LinkGroup.Links>
                    <mui:Link DisplayName="Timing Grid" Source="Pages/Timing.xaml"/>
                </mui:LinkGroup.Links>
            </mui:LinkGroup>

            <mui:LinkGroup DisplayName="Strategy">
                <mui:LinkGroup.Links>
                    <mui:Link DisplayName="Circle Map" Source="Pages/CircleMap.xaml"/>
                </mui:LinkGroup.Links>
            </mui:LinkGroup>
        </mui:ModernWindow.MenuLinkGroups>

</mui:ModernWindow>

Auf der Page Timing.xaml befindet sich ein Button, der per Click einen Timer startet, der die XML-Dateien des Streams überprüft um immer die aktuellsten Daten aus dem Stream zu laden In der Code-behind Datei Timing.xaml.cs werden dazu Listen erzeugt und erweitert.


namespace TimingToolWPF
{
    /// <summary>
    /// Interaction logic for Timing.xaml
    /// </summary>
    public partial class Timing : UserControl
    {
        public string xmlFilePath { get; set; }
        public string xmlFolderPath { get; set; }
        public string Track { get; set; }
        public string Meeting { get; set; }
        public string Competition { get; set; }
        private string extractPath;
        private string sroFileName = "TEAM_INFO.TMP";
        private int fileCount = 0;
        public bool bgwIsWorking = false;
        public string Session { get; set; }
        public List<Car> lstCars = new List<Car>();
        public List<Message> lstMessages = new List<Message>();
        public List<Flag> lstFlags = new List<Flag>();
        private List<string> fileNames;
        public List<TimingList> lstTiming { get; set; }
        public DispatcherTimer tmrXmlRefresh;
        public BackgroundWorker bgwDataImport;
        public System.Windows.Forms.FolderBrowserDialog fbdOpenXmls;

        public Timing()
        {...

Jetzt benötige ich diese Listen aber auch in der Page CircleMap.xaml. Hier liegt schon mein erstes Problem. Wie kann die CircleMap auf die Objekte aus Timing.xaml zugreifen? Oder wie kann ich die Objekte anders anlegen, sodass jede Page Zugriff auf sie hat?
Im Internet finde ich oft, dass man die Objekte bei der Navigation übergeben muss. Leider denke ich befindet sich die Navigation von einem ModernWindow nicht da wo sie sonst ist. Zumindest finde ich die Stelle nicht. Und selbst wenn, was mache ich dann wenn die Daten sich im Hintergrund aktualisieren? Etwas in der Art von "anwendugsweiten Objekten" wäre sehr hilfreich.

Das zweite Problem ist die generelle Umsetzung der CircleMap. Von den Windows Forms her weiß ich, dass ich Formen aus dem Code zeichnen kann. Unter WPF gibt es nun auch die Möglichkeit von Animationen. Daher war zunächst meine Idee, das ganze als eine Pfadanimation umzusetzen - den Kreis als Pfad, kleine Kreise für die Karts als Target. Für die Duration der Animation würde ich die Rundenzeit der letzten Runde nehmen. Ich scheitere jedoch schon daran eine einfache Ellipse als Animationspfad zu benutzen, geschweige denn, dass ich unterschiedlich viele Karts in unterschiedlichen Geschwindigkeiten darauf laufen lassen kann. Daher die Frage, ob mein Ansatz mit der Animation überhaupt Zielführend ist oder ob es nur über das eigenständige Zeichnen von Formen über die Code-behind Datei funktioniert?

Ich weiß das war jetzt viel. Aber ich bin gerade wirklich verzweifelt und muss das Chaos in meinem Kopf erst ordnen. Vielen Dank schonmal für eure Mühen.

LG Andy

5.657 Beiträge seit 2006
vor 7 Jahren

Hi AndyRandy691,

bevor du mit WPF loslegst, solltest du dich erstmal etwas belesen, wie man damit arbeitet, besonders was MVVM und Databinding sowie das Erstellen von UserControls betrifft. Das ist schon etwas anderes als Windows Forms.

Ich würde das so lösen:

  • Im ViewModell ist der Streckenverlauf als Pfad gespeichert, der aus einzelnen Punkten oder Segmenten zusmmengesetzt ist.
  • Im ViewModell gibt es außerdem die aktuelle Position des oder der Autos.
  • In der View gibt es eine Canvas mit einem Pfad, der die Strecke darstellt, und dessen Punkte (oder Segmente) an die Liste des ViewModells gebunden ist.
  • Weiterhin gibt es in der Canvas ein grafisches Objekt (Punkt, Kreis, Auto-Symbol o.ä.), das dein Auto darstellt. Die Position dieses Objektes ist an die Position im ViewModel gebunden.

Wenn du jetzt den Streckenverlauf bzw. die Position des Autos im ViewModell änderst, wird die Darstellung in der View automatisch aktualisiert.

Weeks of programming can save you hours of planning

5.299 Beiträge seit 2008
vor 7 Jahren

@Andy: Dein Ansatz ist iwie voll un-wpf-mässig.
Ich empfehle dir dringend, dich mittm MVVM-Pattern vertraut zu machen.

Du solltest dir für dein Spiel ein Viewmodel überlegen, was die Vorgänge abbildet, und an das du dein Controls bindest.

Ich könnte mir zb was vorstellen, wo man ein Path-Control hat, was im Wesentlichen einen Kreis bildet, mit einem Kart an einer Stelle. Davon die RotateTransform kann man binden, und dann wird der Kart immer entsprechend des vorgegebenen Winkels positioniert dargestellt.

Mit einem DataTemplate kannste aussm gebundenen Viewmodel mehrere solcher Pathes generieren, und zB auf ein Canvas packen, welches als ItemsPanel einer Listbox funktioniert.

Prinzipiell sowas entfernt ähnliches hab ich hier mal verzapft:
Kein Pong!

Der frühe Apfel fängt den Wurm.

A
AndyRandy691 Themenstarter:in
6 Beiträge seit 2016
vor 7 Jahren

Das ging schnell. Danke für die Antworten. Ich hab befürchtet, dass mir noch einiges an Wissen fehlt. Ich werde mir dann jetzt MVVM zu Gemüte führen 😉

A
AndyRandy691 Themenstarter:in
6 Beiträge seit 2016
vor 7 Jahren

So, nachdem ich mich jetzt ziemlich ausführlich mit dem MVVM Pattern beschäftigt habe und mein restliches Programm damit vorangetrieben habe, bin ich wieder bei meiner Circle Map angelangt. Ich glaube ich kann jetzt zumindest nachvollziehen was ihr meint.

@ErfinderDesRades
Wenn ich die RotateTransform Eigenschaft binde, dreht sich dann nicht einfach das Kart-Objekt mit der Tangente des Paths??

Ich versuche gerad zunächst mal ein Auto losgelöst von sämtlichen Daten auf meinen Pfaden fahren zu lassen. Meine Idee dazu ist dies mit einer Pathanimation durchzuführen. Das scheint anders als bei den Vorschlägen bislang zu sein. Ich wollte die Animation mit einem Button starten. Damit alle Objekte im Viewmodel bekannt sind, muss ich die Pfade und den Punkt für das Auto im Viewmodel per Code erstellen. Wie kann ich diese Objekte jetzt in der View anzeigen lassen?
DataContext der View ist auf mein Viewmodel gesetzt, aber ich vermute man muss die Geometrien noch irgendwie dem Canvas hinzufügen.

Vielleicht tappe ich mit der Animation aber auch im Dunkeln.

Einen Winkel im ViewModel berechnen dürfte ja nicht das Problem sein. Nur wie genau kann ich den für die Position auf dem Pfad dann verwenden?

D
985 Beiträge seit 2014
vor 7 Jahren

Eigentlich ist es ja nur die Darstellung eines prozentualen Wertes (wieviel Prozent von der Runde hat das Fahrzeug aktuell zurückgelegt).

Bei einem Kreis rechnet man das in den Winkel um und errechnet zusammen mit dem Radius die aktuelle Koordinate.

5.299 Beiträge seit 2008
vor 7 Jahren

ich glaub nicht, dass eine Wpf-Animation für ein Kart-Rennen geeignet ist.
Eine Animation ist ja ein fest voreingestellter Ablauf, der abläuft.
Ein Kart-Rennen ist aber etwas, wo in die Geschwindigkeit vmtl. per User-Interaktion einzugreifen ist.
Deshalb (und weil Animation imo kein Anfänger-Stoff ist) die Bewegung im Viewmodel abbilden.

Ein Beispiel, wie man mehrere Objekte eigenständig sich bewegen lassen kann, habich ja verlinkt - was hälst du eiglich davon?

Der frühe Apfel fängt den Wurm.

5.657 Beiträge seit 2006
vor 7 Jahren

Einen Winkel im ViewModel berechnen dürfte ja nicht das Problem sein. Nur wie genau kann ich den für die Position auf dem Pfad dann verwenden?

Man würde nicht nur den Winkel berechnen, sondern den daraus resultierenden Punkt auf dem Kreis. Diesen Wert weist du dann der Position-Eigenschaft im ViewModel des Autos zu. Und in der View bindest du diese Eigenschaft an die Position deiner Auto-Grafik über Canvas.Top und Canvas.Left. Siehe dazu: How to: Absolutely Position Elements in a Canvas .

Weeks of programming can save you hours of planning