Laden...

[erledigt] WPF - Images / Bilder verschieben

Erstellt von Jack_AI vor 16 Jahren Letzter Beitrag vor 16 Jahren 7.837 Views
J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren
[erledigt] WPF - Images / Bilder verschieben

Hallo Freunde.

Ich konnte mich noch nicht ganz mit XAML anfreunden (aber das kommt noch) und mache derzeit noch viel auf die "Windows-Forms-Methode". Soll ja angeblich genauso legitim sein. Soviel zur Vorgeschichte.

Was ich gerne wissen würde ist, wie man die Position eines Bildes ändert. In Windows Forms ging das ja mit location (soweit ich mich erinnern kann). Aber location gibt es nicht mehr (soweit ich das sehe).

Mein Code sieht derzeit so aus:


  public class MeinBild : Image
  {
    public MeinBild()
    {
      Source = BitmapFrame.Create(new Uri(@"C:\..."));
      // <- hier Position definieren
    }

    public void PositionAendern()
    {
      // <- ?
    }
  }

Ziemlich mickrig. Ich hoffe aber, dass ich nicht grundsätzlich etwas falsch mache. Danke für alle Antworten.

Jack

2.760 Beiträge seit 2006
vor 16 Jahren

Du musst das Bild auf ein Canvas packen, da gibt es dann sog. Depency-Properties mit denen du das realisieren kannst (Canvas.LeftProperty und Canvas.TopProperty)

siehe auch:
DataItems frei positionieren ? (WPF)

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

Hallo jaensen,

ich habe mal meinen Code von deiner Antwort in dem anderen Thread (siehe dein Link) abgeleitet. Momentan sieht er so aus:


  public class MeinBild : Canvas
  {
    private Image Bild;

    public MeinBild()
    {
      Bild = new Image();
      Bild.Source = BitmapFrame.Create(new Uri(@"..."));
      
      this.Background = Brushes.Black;
      this.Children.Add(Bild);
      this.Width = 100;
      this.Height = 100;
      this.SetValue(Canvas.TopProperty, (double)0);
      this.SetValue(Canvas.LeftProperty, (double)500);
    }

    // bewegt das Bild entlang der Y-Achse zur Position neuePositionX
    public void Fallen(double neuePositionX)
    {
      for (; (double)this.GetValue(TopProperty) < neuePositionX;)
      {
        // mit jedem Durchgang +1 zum Wert TopProperty -> fließende Abwärtsbewegung
        this.SetValue(TopProperty, (double)this.GetValue(TopProperty) + 1);
      }
    }
  }

Wenn ich die Methode "Fallen" ausfühle, passiert allerdings nichts. Vielleicht hat hier noch mal jemand einen Tipp für mich.

Jack

2.760 Beiträge seit 2006
vor 16 Jahren

Du musst dein abgeleitetes Canvas dann auch noch in ein Canvas verschachteln, sonst haben die Depency-Properties keine Depency 😉
Generell kannst du jede von UIElement abgeleitete Klasse in einem Canvas frei positionieren und die meisten unterstützen meines Wissens ein Background Image.

Für das was du suchst, könnte auch Animation nützlich sein.

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

Original von jaensen
Du musst dein abgeleitetes Canvas dann auch noch in ein Canvas verschachteln, sonst haben die Depency-Properties keine Depency 😉

Dependency? Wieso muss ich das verschachteln, das will ich doch gerade vermeiden. Aufgrund des akuten Mangels an WPF-Tutorials habe ich das halbe Internet durchsucht und keine weitere Hilfe für das Problem gefunden. Wieso muss das überhaupt über Dependency gemacht werden? Hast du vielleicht noch einen Tipp für mich, wie ich das Problem lösen kann? Ich weiß auch nicht, wie und wo ich da ein weiteres Canvas unterbringen soll.

Vielen Dank im Voraus und Grüße,
Jack

edit: Natürlich sind auch andere dazu eingeladen zu antworten. 🙂

6.862 Beiträge seit 2003
vor 16 Jahren

Also ableiten um die Position zu setzen ist völlig unnötig. Du fügst dein Bild einfach als Child dem Canvas hinzu und kannst nun über die Dependency Properties die Position setzen. In deinem Beispiel setzt du Top und Left vom Canvas, nicht vom Bild! Dann kann sich die Position vom Bild auch nicht ändern 🙂

Statt


this.SetValue(Canvas.TopProperty, (double)0);
this.SetValue(Canvas.LeftProperty, (double)500);

müsstest du eher


Bild.SetValue(Canvas.TopProperty, (double)0);
Bild.SetValue(Canvas.LeftProperty, (double)500);

sowas schreiben.

Warum das über Dependency Properties geht, hängt mit dem Layoutsystem zu sammen. Dein Satz

...mache derzeit noch viel auf die "Windows-Forms-Methode". Soll ja angeblich genauso legitim sein. kann ich nicht unterstützen. Das ganze Positionierungs/Layoutsystem z.B. arbeitet ganz anders als bei Windows Forms. Ein Control hat einfach keine Position mehr, sondern die Position wird vom Container bestimmt wo es drin ist. Im Idealfall brauch man gar keinen Positionsangaben unter WPF. Deshalb haben auch die Controls von sich aus keine Properties für sowas. Canvas ist ja das einzige Layout Control welches absolute Positionsangaben annimmt, also ist es auch nur konsequent über Canvas Dependencyproperties die Position zu setzen.

Wieso muss das überhaupt über Dependency gemacht werden?

Ach Dependency Properties sind was tolles 🙂 Unter WPF werden viel viel mehr Controls(naja, oder allgemeiner UIElements) erzeugt als unter Windows Forms und auch haben die WPF Controls viel mehr Properties als die Windows Forms Pendants. Nehmen wir mal die TextBox, die hat über 80 Properties. Unter Windows.Forms liegt hinter jedem Property meist auch ne Variable, sprich viel Speicher. Wenn die WPF TextBoxen jetzt nach Windows.Forms Art geschrieben werden, würde man selbst für simple WPF Programme nen riesigen Speicherverbrauch haben. Deshalb gibts die Dependency Properties. Die werden von einem zentralen Dependency Property System verwaltet und die Properties der TextBox z.b. haben keine Variablen dahinter, sondern kapseln nur den Zugriff auf die entsprechenden Dependency Properties mit SetValue und GetValue die du ja schon manuell benutzt hast. Und bei diesem Dependency Property System werden die Properties auch nur angelegt wenn sie benutzt werden. Sprich wenn du von ner TextBox nur 10 Properties nutzt, wird auch nur für die 10 Daten angelegt im Dependency Property System.

Der Speicherverbrauch ist also eine positive Eigenschaft von diesem Dependency Properties System, der zweite ist der, dass man Properties von Controls setzen kann, die diese selbst gar nicht haben, aber von anderen benutzt werden. Das machst du beim Canvas oben. Du setzt Top und LeftProperty vom Canvas des Images, obwohl das Bild die gar nicht hat.

Naja, WPF Tutorials gbts wirklich net viel, aber ein paar richtig gute Bücher. Dependency Properties sind ja nur ein Teil von teilweise komplett anderen Vorgehensweisen bei der WPF, und ohne das man mal wirklich da durchgestiegen ist, glaub ich, kann man nie wirklich gute WPF Oberflächn schreiben. Deshlab würde ich raten, sich nicht zu sehr auf Windows forms vorgehensweisen zu stützen, damit kommt man unter WPF nicht weit.

Baka wa shinanakya naoranai.

Mein XING Profil.

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

Vielen Dank für die umfangreiche Antwort!

Ich verstehe das Ganze jetzt um einiges besser! Das ist auch eine recht ungewohnte Situation für mich, weil ich es eigentlich gewöhnt bin im Internet alles zu finden, was ich brauche. Aber nachdem es so wenig Material zu WPF gibt, stehe ich nun des Öfteren verzweifelt alleine da.

Ich habe das nun so gelöst, indem ich per Designer ein 0x0 Pixel großes Canvas in die obere linke Ecke platziert habe, das nun Grundlage für die Bilddependency bildet. Ziemlich... amateurhaft, ich weiß. Lustigerweise habe ich es nicht hinbekommen, ein Canvas per Code zu erstellen, obwohl ich genau die selben Eigenschaften angegeben habe, wie sie der Designer als XAML einfügt.

Mein Tag ist jetzt schon mal im Ansatz gerettet. Wenn mich noch jemand in dem letzten Punkt aufklären könnte, wäre ich... wie nennt man das... glücklich(?).

Jack

6.862 Beiträge seit 2003
vor 16 Jahren

Naja, dieses 0x0 Pixel Canvas ist in WPF recht beliebt geworden. Durch das geänderte Renderingsystem kann man Controls halt beliebig über andere Controls platzieren und da Canvas das einzige Control mit absoluten Positionsangaben ist nimmt man halt ein 0x0 Canvas und kann dann aber alles was im Canvas ist beliebig positionieren im Window. Achja, was mir da noch einfällt. In WPF sind das alles keine Pixelangaben, sondern logische Einheiten die jeweil 1/96 Inch entsprechen. Mit der Standardauflösung von 96 DPI entspricht dann eine logischen Einheit wieder einem Pixel, das muss aber nicht zwangsläufig sein bei höheren Auflösungen.

Warum das per Code bei dir nicht gelingt weiß ich auch nicht, aber was aus deinem XAML generiert wird, kannst ja mitm Reflector und dazu noch dem BAML Plugin(google mal danach, weiß grad keine URI) anschaun und vergleichen was der Unterschied ist zwischen dem manuell erstellten und generierten Code.

Baka wa shinanakya naoranai.

Mein XING Profil.

J
Jack_AI Themenstarter:in
193 Beiträge seit 2007
vor 16 Jahren

Original von talla
Naja, dieses 0x0 Pixel Canvas ist in WPF recht beliebt geworden. Durch das geänderte Renderingsystem kann man Controls halt beliebig über andere Controls platzieren und da Canvas das einzige Control mit absoluten Positionsangaben ist nimmt man halt ein 0x0 Canvas und kann dann aber alles was im Canvas ist beliebig positionieren im Window. Achja, was mir da noch einfällt. In WPF sind das alles keine Pixelangaben, sondern logische Einheiten die jeweil 1/96 Inch entsprechen. Mit der Standardauflösung von 96 DPI entspricht dann eine logischen Einheit wieder einem Pixel, das muss aber nicht zwangsläufig sein bei höheren Auflösungen.

Ach so, 0x0 Pixel-Canvas sind üblich. Hehe, das hätte man auch einfacher gestalten können. Was soll's. Inzwischen läuft es wieder einigermaßen bei mir und meinem Projekt. Zu deinem letzten Punkt habe ich einen interessanten Link gefunden: http://www.wpflearningexperience.com/?p=41

Original von talla
Warum das per Code bei dir nicht gelingt weiß ich auch nicht, aber was aus deinem XAML generiert wird, kannst ja mitm Reflector und dazu noch dem BAML Plugin(google mal danach, weiß grad keine URI) anschaun und vergleichen was der Unterschied ist zwischen dem manuell erstellten und generierten Code.

Gute Idee! Darauf werde ich bestimmt bei Gelegenheit mal zurück kommen, um die interne Mechanik besser zu verstehen. Für den Moment bin ich allerdings froh, dass ich es überhaupt hinbekommen habe. 😉

Vielen Dank!
Ich würde sagen: "Problem gelöst",
Jack