Ellipse zur Laufzeit bewegen
Hallo,
ich bin neu hier im Forum. Seit kurzem habe ich mit der WP7 Pogrammierung begonnen.
Nun zu meinem Problem. Ich möchte in einem kleinen Programm eine Ellipse auf dem Bildschirm mit den Werten des Accelerometer bewegen. Das Auslesen der Werte geht recht gut, aber wie kann ich die Position der Ellipse zur Laufzeit verändern. Meine Idee war über die Eigenschaft den Wert von Margin zu verändern, aber der ist Schreibgeschützt.
Mit sicherheit sehe ich den Wald vor lauter Bäumen nicht, aber ich komme nicht weiter und würde mich sehr über eine Idee freuen.
Mfg
hobbysucher
AW: Ellipse zur Laufzeit bewegen
Eine Bewegende Ellipse geht mit Silverlight auch sehr sehr leicht. Um mal ein Beispiel zu geben habe ich da mal was gebastelt. Ich muss dazu sagen, dass ich kein WP7 SDK zur Hand habe (falsches OS) und deswegen wahrscheinlich ein paar Tipfehler drin sind.
Zu erst sollte man sich eine Klasse erstellen, an die man sein GUI binden kann.
Code:
using System;
using System.ComponentModel;
using System.Diagnostics;
using Microsoft.Devices.Sensors;
namespace MeinTollerNamensraum{
public class AccelerometerViewModel : INotifyPropertyChanged, IDisposable
{
Accelerometer _accelerometer;
public AccelerometerViewModel()
{
InitializeAccelerometer();
}
void InitializeAccelerometer()
{
if (!Accelerometer.IsSupported)
{
throw new NotSupportedException("Accelerometer is not supported by this device.");
}
_accelerometer = new Accelerometer();
_accelerometer.ReadingChanged += ReadingChanged;
_accelerometer.Start();
}
private void OnSensorReadingChanged(object sender, AccelerometerReadingEventArgs e)
{
// Zum Testen. Ich weiß nicht ob die Parameter so Glücklich sind. Geplant war ungefähr die Mitte zu treffen
// Normal müsste man hier noch darauf achten, dass der Thread stimmt mit dem man die Werte setzt.
// Das übernimmt aber die Helper Methode für mich.
AccelerometerX = 240 + e.AccelerometerReading.X * 240;
AccelerometerZ = 400 + e.AccelerometerReading.Z * 400;
}
double _accelerometerX;
public double AccelerometerX
{
get { return _accelerometerX; }
set { SetValue(ref _accelerometerX, value); }
}
double _accelerometerY;
public double AccelerometerY
{
get { return _accelerometerX; }
set { SetValue(ref _accelerometerX, value); }
}
#region MVVM Helper Methods
protected void SetValue<T>(ref T obj, T value)
{
if (!EqualityComparer<T>.Default.Equals(obj, value)) // obj != value
{
obj = value;
StackTrace stackTrace = new StackTrace();
var method = stackTrace.GetFrame(1).GetMethod();
var name = method.Name.Replace("set_", "");
NotifyPropertyChanged(name);
}
}
protected void NotifyPropertyChanged(string name)
{
var notifyChanged = PropertyChanged;
App.Current.Dispatcher.Invoke(() =>
{
if (notifyChanged != null)
notifyChanged(this, new PropertyChangedEventArgs(name));
});
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public override void Dispose()
{
_accelerometer.Dispose();
}
}
}
Im Grunde passiert da nicht viel. Der Konstruktor startet den Accelerometer. Wenn dieser einen neuen Wert bekommt werden die beiden Properties AccelerometerX und Y gesetzt. Die Helfer Methode die ich dort Methode macht nichts anderes, als den wert zu setzen, und das NotifyPropertyChanged aufzurufen. Ich habe sie mir geschrieben, um mir Schreibarbeit in den Properties selbst zu sparen und Tippfehler zu vermeiden.
Um das nun in die Seite einzubauen braucht man gar kein C# mehr.
in der xaml Datei deiner Seite musst du zuerst den namensraum, in dem die Klasse liegt bekannt machen. Dazu ganz oben in den obersten Tag eine solche Anweisung hinzufügen:
HTML-Code:
xmlns:self="cls-namespace:MeinTollerNamensraum"
Das sagt im Grunde aus, dass wenn ich in der Seite etwas mit self:klasse anspreche, dann kommt es aus dem Namensraum "MeinTollerNamensraum".
Nun setzt man den DataContext der Seite auf eine Instanz der Klasse. Dazu in den PhoneApplicationPage Tag den Datenkontext setzen:
HTML-Code:
<PhoneApplicationPage.DataContext>
<self:AccelerometerViewModel/>
</PhoneApplicationPage.DataContext>
Damit hat man schon alles getan, um ganz einfach auf die Properties zuzugreifen. Dank der Datenbindung und dem NotifyPropertyChanged updaten die Objekte sich selbstständig.
Nun also zu der Elipse: Um Objekte frei zu Positionieren gibt es das Canvas Containerelement.Nur in diesem kann man die Objekte mit einem X und einem Y Wert verankern. Dazu bietet das Canvas Attached Properties an. Das sieht 'in Action' dann so aus:
HTML-Code:
<Canvas>
<Ellipse Width="50" Height="50" Canvas.Left="{Binding AccelerometerX}" Canvas.Top="{Binding AccelerometerZ}" Fill="Red"/>
</Canvas>
Ich hoffe ich konnte dir helfen :)
LG pdelvo
AW: Ellipse zur Laufzeit bewegen
Vielen Dank für die Ideen bzw. Code-Teile
@ Hanno11:
Mit XNA habe ich mich noch garnicht beschäftigt. Ich muss erst einmal laufen Lernen bevor ich anfange zu Renne :-)
Trozdem Danke für den Ansatz!
@pdelov:
Das ist eine Richtig gut Anleitung. Ich bin gestern Abend auch noch über die DataBinding Geschichte gestolpert. Nur habe ich sie nicht zum Laufen bekommen. Die Anleitung die ich gefunden hatte war auch etwas anders, aber ich denke "Viele Wege führen nach Rom".
Nun habe ich es so umgeschrieben wie in Deinem Beispiel. Aber es war klar, auch hier hinke ich hinterher. Was mache ich mit dem folgenden Teil:
Zitat:
<PhoneApplicationPage.DataContext>
<self:AccelerometerViewModel/>
</PhoneApplicationPage.DataContext>
Ich wollte es unterhalb der Namensraum-Deklaration eintragen. Aber meien "PhoneApplication" kennt keine DataContext-Eigenschaft.
Mache ich das an der falschen Stelle?
MfG
hobbysucher
AW: Ellipse zur Laufzeit bewegen
Das muss in den PhoneApplication Tag. Also etwa dahin:
HTML-Code:
<PhoneApplicationPage
xmlns:abc="..."
xmlns:def="..."
xmlns:ghi="...">
<!-- Hier -->
<....>
</....>
</PhoneApplicationPage>
AW: Ellipse zur Laufzeit bewegen
Unglaublich, aber ich bin nicht in der Lage das so umzusetzen.
Alternativ habe ich bei MSDN folgenden Link gefunden: INotifyPropertyChanged Interface
Zumindest komme ich somit an mein Ziel.
Vielen Dank an alle!
MfG
hobbysucher