Grafisches Problem - WinForms zu WPF

  • WPF MVVM
  • .NET (FX) 4.5–4.8

Es gibt 58 Antworten in diesem Thema. Der letzte Beitrag () ist von BitBrösel.

    Grafisches Problem - WinForms zu WPF

    Hallo miteinander :)

    Ich hab mal ein komplexeres Problem, aber fangen wir mal so an, vielleicht erledigt sich dann der Rest:

    An anderer Stelle in meinem Projekt hab ich das hier, und es funktioniert:

    Ziel ist es, für diese Funktion der bass.dll die Werte zu ermitteln für Breite und Höhe, damit das Bild mit den richtigen Parametern erstellt wird. Denn das Image kann in der Größe variieren, je nachdem, wie das Fenster skaliert wird oder der was für ein Format der Bildschirm hat (ich benutze Grids mit prozentualer Angabe für Width and Height).

    XML-Quellcode

    1. <Border BorderThickness="1" BorderBrush="Aquamarine">
    2. <Image Grid.Row="0" Width="{Binding Breite, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" Height="{Binding Hoehe, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" Source="{Binding Bild, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Stretch="Fill" Validation.ErrorTemplate="{x:Null}"/>
    3. </Border>


    Und im ViewModel davon:

    VB.NET-Quellcode

    1. Private _Breite As Integer
    2. Public Property Breite As Integer
    3. Get
    4. Return _Breite
    5. End Get
    6. Set(value As Integer)
    7. _Breite = value
    8. RaisePropertyChanged()
    9. End Set
    10. End Property
    11. Private _Hoehe As Integer
    12. Public Property Hoehe As Integer
    13. Get
    14. Return _Hoehe
    15. End Get
    16. Set(value As Integer)
    17. _Hoehe = value
    18. RaisePropertyChanged()
    19. End Set
    20. End Property
    21. ...
    22. BMP = Spektrum.CreateSpectrumLinePeak(MainModule.streamfx(WelcherEQ - 1), Breite, Hoehe, System.Drawing.Color.Green, System.Drawing.Color.IndianRed, System.Drawing.Color.SlateGray, System.Drawing.Color.Transparent, Breite \ 10, 3, MainModule.SpectrumAnalyzerDistanz, 40, False, True, True)


    Wenn ich aber das hier mache:

    XML-Quellcode

    1. <Canvas Grid.Row="6">
    2. <Image Source="{Binding WaveFormSource, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Canvas.Top="0" Canvas.Left="{Binding XPosition, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Stretch="Fill" Width="{Binding Breite, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" Height="{Binding Hoehe, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
    3. <Line Stroke="Red" StrokeThickness="1" X1="{Binding X_1}" X2="{Binding X_1}" Y1="0" Y2="100"/>
    4. </Canvas>


    und das:

    VB.NET-Quellcode

    1. Private MeineWellenForm As New WaveForm
    2. WellenForm = New Bitmap(MeineWellenForm.CreateBitmap(Breite, Hoehe, -1, -1, True))


    bekomme ich hier immer den Fehler in Zeile 2...

    HResult=0x80004003
    Nachricht = Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
    Quelle = System.Drawing

    ...wenn ich Breite und Hoehe nicht vorher festlege, obwohl das bei dem ersten Beispiel ohne Festlegen funktioniert hat.

    Hat jemand ne Idee, warum das beim zweiten Beispiel nicht funktioniert?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Das liegt daran das die Eigenschaften Width und Height vom Canvas Standardmäßig immer null sind. Du musst also in deinem Fall Width und Height angeben.
    Ich denke aber das du statt eines Canvas besser ein Grid nehmen solltest.

    Wenn ich das richtig gelesen habe können untergeordnete Elemente eines Canvas die Größe nicht ändern. Sie sind fix an ihren Coordinaten.
    Lies mal hier nach
    learn.microsoft.com/de-de/dotn…indowsdesktop-6.0#remarks
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Akanel“ ()

    @Akanel

    Habs mal komplett ohne das Canvas versucht. Da passiert immer noch das Gleiche... Echt komisch an der anderen Stelle im Programm funktioniert das tadellos...

    Ich würde gern mal ein kleines Testprogramm hochladen. Das hat jetzt aber eine NuGet-Abhängigkeit. Wie bereinige ich das Projekt dann? Einfach den Ordner "packages" löschen und das wird dann beim Empfänger automatisch wieder installiert?

    Bevor wir an der Stelle weitermachen und dann in die falsche Richtung denken:

    Ich habe vor mir von meinem Programm eine WaveForm von MP3s zeichnen zu lassen. Das erledigt die bass.dll... Der übergibt man einfach die Werte für Breite und Höhe und dann wird die Waveform der (kompletten!) mp3 so skaliert, dass sie in dein Image/PictureBox passen.
    Nun soll sich das aber mitbewegen, wenn die MP3 abgespielt wird, d.h. genau in der horizontalen Mitte des Image soll eine Linie sein, und das von der bass.dll generierte Bild soll sich so bewegen, dass die Linie immer genau auf die Abspielposition zeigt, d.h. das generierte Bild muss sich in meinem Control nach links bewegen. Daher hatte ich das Canvas gewählt.... Aber geht das auch anders und ich kann mir das Problem mit der dynamischen Breite und Höhe sowieso sparen?
    Das ich das mal verstehe. Ohne ein Canvas hast du bereits alles hinbekommen, und jetzt möchtest du es nur mit einem Canvas probieren?

    Deine Waveform ist ein Bild. Darüber zeichnest du mittig eine Linie. Nun soll sich das Bild so verschieben das die aktuelle Position des Liedes immer in der Mitte ist?
    Also das Bild soll sich nach links, oben und unten bewegen können?
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.
    Ich hab ein funktionierendes WinForms-Beispiel. Nur dass ich da nicht die komplette Picturebox bewege, sondern nur das Bild darin mit veränderter Position zeichne mit der Funktion DrawImage.
    Nach oben und unten brauch ich das Bild nicht bewegen nur rechts/links, aber sonst hast du richtig verstanden.
    Das mit der Hoehe und Breite dynamisch ermitteln hab ich an anderer Stelle in meinem Wpf-Programm schon und es funktioniert, nur hab ich keine Ahnung, warum da jetzt an dieser Stelle immer nur 0 rauskommt....
    Ich kann dir gern mal jeweils das WinForms und Wpf Testprojekt hochladen, bin mir nur unsicher, wie das mit den Nuget-Paketen läuft...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Jupp, das Package kann einfach gelöscht werden, wird bei Bedarf neu geladen. @kafffee Könnte es sein das dir DesignTime/RunTime reingrätscht? Ich mache meinen Mediaplayer auch noch mal mit WPF neu, ich hatte da Probleme im ViewModel zwischen RunTime und DesignTime zu unterscheiden, im Konstruktor von ViewModels hole ich die Services die ich in der App.xml im StartUp hinzufüge, zur Designtime können die nur null sein, deshalb meldete auch der Designer immer (Es wurde keine Object-Instanz.....) in der Zeile wo ich das ViewModel einem DataContext zuweise, aber kompilieren und laufen tut alles. Nun teste ich ob der gewollte service null ist, habe zur Designtime deshalb keine Probleme mehr. Da du ja auch mit Services arbeitest(hatte ja deine andere Projektmappe gesehen), könnte das ja ähnlich sein.

    Wann tritt der Fehler auf, zur DesignTime oder immer?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „BitBrösel“ ()

    @Akanel

    Wie versprochen anbei die zwei Projekte. Du musst im WinForms-Projekt (Zeile 8) noch an einer Stelle und im WPF-Projekt an zwei Stellen den Pfad einer MP3 Datei eingeben (Zeilen 54 und 59), ich hab aber alles soweit kommentiert.
    Im WPF Projekt findest du den relevanten Code im View-Projekt unter MainView.xaml und im ViewModel-Projekt in der MainViewModel.vb.
    Ausserdem brauchst du noch die bass.dll, die lässt sich leider nicht per Nuget installieren, nur der Wrapper, wie ich gerade rausgefunden hab. Du findest sie auf der Un4SeenWebsite ganz oben unter Win32..

    Diese musst du in den bin/debug Ordner vom App-Projekt und ViewModel-Projekt reinkopieren, bzw. beim WinForms den bin/debug Ordner...

    @BitBrösel
    Der Fehler tritt zur Laufzeit auf. Bei mir kann man mit IsInDesignMode oder so ähnlich abfragen, ob der Code zur Desgin- oder Laufzeit ausgeführt wird, ist recht praktisch...
    Dateien
    Ich probiere gerade auch das zu realisieren, gar nicht so einfach, manche Funktionen wollen ein Forms.Control als Argument(WaveForm aus Misc oder Visuals z.B. sobald ein CallBack verwendet wird). Wäre das nicht, hätte ich bereits was, aber ein Verweis auf WinForms kommt mir net in die Tüte. Immerhin hab ich schonmal ein schwarzes Bild ohne Fehlermeldung. Liegt wohl am Konvertieren.

    Ich schau mal in deiner Mappe nach, probiere weiter und berichte bei Erfolg.

    @kafffee

    BuildAusgabe schrieb:

    ​System.Windows.Data Error: 7 : ConvertBack cannot convert value 'NaN' (type 'Double'). BindingExpression:Path=Breite; DataItem='MainViewModel' (HashCode=34181910); target element is 'Image' (Name=''); target property is 'Width' (type 'Double') OverflowException:'System.OverflowException: Der Wert für einen Int32 war zu groß oder zu klein.
    bei System.Convert.ToInt32(Double value)
    bei System.Double.System.IConvertible.ToInt32(IFormatProvider provider)
    bei System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
    bei MS.Internal.Data.SystemConvertConverter.ConvertBack(Object o, Type type, Object parameter, CultureInfo culture)
    bei System.Windows.Data.BindingExpression.ConvertBackHelper(IValueConverter converter, Object value, Type sourceType, Object parameter, CultureInfo culture)'
    "DialogFensterTest2.App.exe" (CLR v4.0.30319: DialogFensterTest2.App.exe): "C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework.resources\v4.0_4.0.0.0_de_31bf3856ad364e35\PresentationFramework.resources.dll" geladen. Das Modul wurde ohne Symbole erstellt.
    Ausnahme ausgelöst: "System.OverflowException" in mscorlib.dll
    System.Windows.Data Error: 7 : ConvertBack cannot convert value 'NaN' (type 'Double'). BindingExpression:Path=Hoehe; DataItem='MainViewModel' (HashCode=34181910); target element is 'Image' (Name=''); target property is 'Height' (type 'Double') OverflowException:'System.OverflowException: Der Wert für einen Int32 war zu groß oder zu klein.
    bei System.Convert.ToInt32(Double value)
    bei System.Double.System.IConvertible.ToInt32(IFormatProvider provider)
    bei System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
    bei MS.Internal.Data.SystemConvertConverter.ConvertBack(Object o, Type type, Object parameter, CultureInfo culture)
    bei System.Windows.Data.BindingExpression.ConvertBackHelper(IValueConverter converter, Object value, Type sourceType, Object parameter, CultureInfo culture)'


    Änder das mal zu double

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „BitBrösel“ ()

    @BitBrösel

    Ja bei den Funktionen mit Callback Funktion gibt's meistens auch eine Überladung ohne Winforms Control.

    Edit @BitBrösel:
    Ja, das mit Problem mit den Doubles hatte ich auch schon und bin kläglich gescheitert. Deshalb hab ich Integer gewählt, das funktioniert auch, man bekommt halt einen roten Rahmen um das Image, den kann man aber unterdrücken mit Validation.ErrorTemplate ="{x:Null} "

    Fehlermeldungen gibt's bei der bass.dll generell nur auf Nachfrage mit BASS_ErrorGetCode... Die spuckt dir die Fehlernummer des jeweils direkt vorangegangen Calls aus.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Das ja, aber sobald man den Konstruktor mit Callback nimmt, ist ein Forms.Control von nöten. Ich habe alles was die BASS angeht in einem weiteren Service, damit ich auch im EqualizerFenster-ViewModel drauf zugreifen kann. Wäre doch schön, sobald eine Datei abgespielt wird, wenn mit Callback die WF generiert wird, sobald fertig ein Event feiern. (EventHandler<BitmapSource>) was im ViewModel abboniert ist.
    Ich glaube ich habe was gefunden, ich denke das rendern ist noch nicht durch und daher der Fehler. MeineWellenFormCallBackFunktion wird nie verwendet, da sind wir wieder bei den CallBacks.

    Was mir jedenfalls aufgefallen ist, das Image das kommt ist nur zum Teil gerendert, siehe Anhang.

    Ich probiere das noch mal ganz anders.
    Bilder
    • Unbenannt.jpg

      28,53 kB, 928×614, 27 mal angesehen
    Nein, das ist dein Projekt ohne Bearbeitung.

    Ich habe die Fehler gefunden. Das Bitmap ist tatsächlich noch nicht fertig. Die While Schleife mit IsRenderingInProgress geht nicht, aber IsRendered liefert das was wir brauchen.

    VB.NET-Quellcode

    1. Private Sub OKDialogOeffnen_Execute(obj As Object)
    2. Dim Objekt = DirectCast(obj, String)
    3. Dim dialogService = ServiceContainer.GetService(Of IDialogWindowService)
    4. Dim fensterService = ServiceContainer.GetService(Of IWindowService)
    5. Select Case Objekt
    6. Case "WaveForm"
    7. Debug.WriteLine("Breite: " & Breite)
    8. Debug.WriteLine("Höhe: " & Hoehe)
    9. Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_CPSPEAKERS, IntPtr.Zero, Nothing)
    10. 'Breite = 500
    11. 'Hoehe = 100
    12. _stream = Bass.BASS_StreamCreateFile("", 0, 0, BASSFlag.BASS_DEFAULT Or BASSFlag.BASS_STREAM_AUTOFREE Or BASSFlag.BASS_SAMPLE_FLOAT) 'hier musst du noch den Pfad einer MP3 Datei eingeben als erstes Argument
    13. Bass.BASS_ChannelPlay(_stream, False)
    14. MeinTimer.Interval = TimeSpan.FromMilliseconds(20)
    15. AddHandler MeinTimer.Tick, AddressOf UpdateVisualization
    16. MeineWellenForm = New WaveForm("") 'hier musst du noch den Pfad der selben MP3 Datei eingeben als Argument
    17. MeineWellenForm.ColorBackground = System.Drawing.Color.Black
    18. MeineWellenForm.RenderStart(True, BASSFlag.BASS_SAMPLE_FLOAT Or BASSFlag.BASS_STREAM_PRESCAN Or BASSFlag.BASS_DEFAULT)
    19. While Not MeineWellenForm.IsRendered
    20. 'todo: prevent endless loop
    21. End While
    22. WellenForm = New System.Drawing.Bitmap(MeineWellenForm.CreateBitmap(1024, 768, -1, -1, True))
    23. WaveFormSource = BitmapToImageSource(WellenForm)
    24. MeinTimer.Start()
    25. End Select
    26. End Sub



    Dann hier:

    VB.NET-Quellcode

    1. If WellenForm IsNot Nothing Then
    2. WellenForm = MeineWellenForm.CreateBitmap(Breite, Hoehe, -1, -1, True)
    3. WaveFormSource = BitmapToImageSource(WellenForm)
    4. End If


    Soll wohl eher:

    VB.NET-Quellcode

    1. If WellenForm Is Nothing


    Also bei mir klappt das nun. Edit @kafffee Code korrigiert, hatte STRG Z gedrück, daher fehlte das Not beim While. Wäre doch schöner mit Callback anstatt mit Loop warten bis fertig.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „BitBrösel“ ()

    @BitBrösel

    Sehe ich das richtig, du lässt die While-Schleife leer, damit einfach nur gewartet wird, bis IsRendered = True ist ohne dass was dabei getan wird?

    Bist mir schon einen Schritt voraus, soweit war ich noch gar nicht mit dem Problem...

    Aber das Breite und Hoehe bei 0 bleiben, das Problem besteht weiterhin... Irgendwas übersehe ich. Trag mal in deinem Code in Zeile 24 statt 1024 Breite ein, und statt 768 Hoehe, dann wirst du sehen was ich meine...

    Vom Image sind ja Horizontal/VerticalAlignment standardmässig auf Stretch. Und wenn ich dann Width und Height mit OneWayToSource an Breite/Hoehe binde, sollte ja dann dort der tatsächliche Wert des Bildes abzufragen sein oder?
    Also wenn du WaveForm.RenderStart callst, startet die BASS die Datei zu analysieren/daten daraus zu laden. RenderStart finde ich einen blöden namen für die Funktion, den rendern ist für mich ein Bild erstellen, egal ob Datei oder direkt auf'm Schirm. Dabei wird ja mit WaveForm.CreateBitmap das Bild gemacht, also irgendwas mit init oder prepare wäre besser. Aber das scannen der Datei dauert halt einen kleinen Moment, daher die While Schleife. Danach ist ja alles parat und man kann sich das Bitmap holen.

    Ich bin dir aber sogar noch einen 2. Schritt voraus. Die Bindung mit der Width/Height gibt mit immer NAN aus. Hier ein Workaround:
    stackoverflow.com/questions/10…rties-back-into-viewmodel

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „BitBrösel“ ()

    @BitBrösel

    Hab bis grade gebraucht um das mal funktionierend nachzubauen... bei mir dauert halt alles bissle länger...

    Das einzige Problem was ich jetzt noch habe, dass der falsche Bildausschnitt gezeigt wird, und somit das Ganze nicht, wie es soll, "synchron" zur Musik angezeigt wird. Ich dachte zuerst das liegt daran, dass ich die Einheiten nicht in Pixel umgerechnet hab aber daran scheints nicht zu liegen sondern eher daran, dass das Imagecontrol das erzeugte Bild einfach nur in seiner ganzen Grösse auf die eigene Grösse skaliert. Ich möchte aber, dass das Bild seine gerenderte Grösse behält und einfach nur der Bildausschnitt "verschoben" wird (dann klapp das nämlich auch mit der Variable Zoom. Im Winforms-Programm ist das ja anders gelöst:

    VB.NET-Quellcode

    1. Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    2. If Not WaveImg Is Nothing Then
    3. e.Graphics.DrawImage(WaveImg, New Point((_trackposition * -1) + (PictureBox1.Width \ 2), 0))


    Wobei WaveImg dass von der bass.dll generierte Bild ist.

    Da wird also das Bild in der PictureBox verschoben und nicht die ganze PictureBox (diese hat Sizemode=Normal)

    Geht das überhaupt so wie ich das mir vorstelle oder bzw. gibt es in der WPF auch irgendeine Methode, um eine Bild wie es ist in ein IMageControl zu zeichen mit Angabe der Koordinaten?

    kafffee schrieb:

    bei mir dauert halt alles bissle länger...


    Nicht schlimm, auch langsam kommt man ins Ziel. Mit WPF dauerts bei mir auch länger, recherchieren, tippen, recherchieren, haare raufen, recherchieren, tippen. Bin froh wenn ich das endlich alles weiß und zum großen Teil das Recherchieren sparen kann. Bei meinem letzten Re-Write meines Mediaplayers in Forms, war ich schon 2-3 mal weiter.

    Also mit dem malen, da bin ich mir nicht ganz so sicher. Manche scheinen bei Custom(nicht user)Controls kein MVVM anzuwenden, täte ich wohl auch so machen, also ich würde eine Klasse anlegen und von Canvas erben lassen. Property für markerposition und Bild rein, dann in OnRender im malen.(CodeBehind) Ich glaube in so einem Fall könnte man mit WVVM auch nichts machen, weil ja im Control selbst gemalt wird, aus dem VM heraus geht das ja nicht so einfach, wenn überhaupt, zumindest sehe ich noch keine Möglichkeit.

    learn.microsoft.com/de-de/dotn…der?view=netframework-4.8

    Dann kannst du im XAML Markerposition und Bild ans ViewModel-Interne binden.

    Ich bin gerade am schauen ob man da nun auch einfach Bewegung ins Bild bekommen könnte, ähnlich wie in WinForms mit Graphics.TranslateTransform, halt nur im XAML und Bindung. Rendert man das Bild 20 mal breiter, könnte man das auch animieren, so das es "mitläuft".

    Bin auch auf CroppedBitmap gestoßen, damit werde ich morgen mal experimentieren.
    learn.microsoft.com/en-us/dotn…N&view=windowsdesktop-6.0

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „BitBrösel“ ()

    @kafffee

    Ich hab mal weiter ein wenig probiert, hab ein Control gemacht, das sowohl DependencyProperties für ein BitmapSource und double hat. BitmapSource is klar, für das WaveForm Bild gedacht, die Property typ double für die Marker-Position, einfach %, kann man gut ausrechnen. Ich finde schon das in dem Fall CodeBehind sinnvoll ist, betrifft ja alles nur das Control-Interne. Solange später die Properties ans VM gebunden werden.

    Das ist ohne WVVM, war zu faul eine ganze Mappe nur für Test-Zwecke vorzubereiten. Muss mir mal ein Projekt Template anlegen. Fehlt noch ein wenig Logik um zu Skallieren und auch um die WaveForm zu "bewegen", besser gesagt immer nur einen Teil davon rendern aber abhängig von der Position im Stream.
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Diagnostics;
    4. using System.Linq;
    5. using System.Text;
    6. using System.Threading.Tasks;
    7. using System.Windows;
    8. using System.Windows.Media;
    9. using System.Windows.Media.Imaging;
    10. using System.Windows.Threading;
    11. using System.Xml.Linq;
    12. using static System.Net.Mime.MediaTypeNames;
    13. namespace BassTest
    14. {
    15. public class MyFrameworkElement : FrameworkElement
    16. {
    17. public double MarkerPercentage
    18. {
    19. get => (double)GetValue(MarkerPercentageProperty);
    20. set => SetValue(MarkerPercentageProperty, value);
    21. }
    22. public BitmapSource Image
    23. {
    24. get => (BitmapSource)GetValue(ImageProperty);
    25. set => SetValue(ImageProperty, value);
    26. }
    27. public static readonly DependencyProperty MarkerPercentageProperty = DependencyProperty.Register("MarkerPercentage", typeof(double), typeof(FrameworkElement), new FrameworkPropertyMetadata(50.0, FrameworkPropertyMetadataOptions.AffectsRender));
    28. public static readonly DependencyProperty ImageProperty = DependencyProperty.Register("Image", typeof(BitmapSource), typeof(FrameworkElement), new FrameworkPropertyMetadata(default(BitmapSource), FrameworkPropertyMetadataOptions.AffectsRender));
    29. protected override void OnRender(DrawingContext dc)
    30. {
    31. base.OnRender(dc);
    32. double x = RenderSize.Width / 100.0d * MarkerPercentage;
    33. System.Windows.Media.Pen pen = new System.Windows.Media.Pen();
    34. pen.Brush = System.Windows.Media.Brushes.Red;
    35. pen.Thickness = 10.0f;
    36. if(Image != null)
    37. {
    38. dc.DrawImage(Image, new Rect(0, 0, RenderSize.Width , RenderSize.Height));
    39. }
    40. dc.DrawLine(pen, new System.Windows.Point(x, 0), new System.Windows.Point(x, RenderSize.Height));
    41. }
    42. }
    43. }




    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Drawing;
    5. using System.IO;
    6. using System.Linq;
    7. using System.Runtime.CompilerServices;
    8. using System.Text;
    9. using System.Threading;
    10. using System.Threading.Tasks;
    11. using System.Windows;
    12. using System.Windows.Controls;
    13. using System.Windows.Data;
    14. using System.Windows.Documents;
    15. using System.Windows.Input;
    16. using System.Windows.Media;
    17. using System.Windows.Media.Imaging;
    18. using System.Windows.Navigation;
    19. using System.Windows.Shapes;
    20. using Un4seen.Bass;
    21. using Un4seen.Bass.Misc;
    22. namespace BassTest
    23. {
    24. /// <summary>
    25. /// Interaktionslogik für MainWindow.xaml
    26. /// </summary>
    27. public partial class MainWindow : Window, INotifyPropertyChanged
    28. {
    29. string mp3File = ".mp3";
    30. int stream = 0;
    31. public MainWindow()
    32. {
    33. InitializeComponent();
    34. }
    35. private BitmapSource _bmpsrc = null;
    36. public BitmapSource BmpSrc
    37. {
    38. get => _bmpsrc;
    39. set
    40. {
    41. if(_bmpsrc != value)
    42. {
    43. _bmpsrc = value;
    44. RaisePropertyChanged();
    45. }
    46. }
    47. }
    48. private void Window_Loaded(object sender, RoutedEventArgs e)
    49. {
    50. if(!Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_SPEAKERS, IntPtr.Zero))
    51. {
    52. MessageBox.Show("ERROR BASS INIT");
    53. Close();
    54. }
    55. stream = Bass.BASS_StreamCreateFile(mp3File, 0, 0, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_AUTOFREE);
    56. if(stream != 0)
    57. {
    58. Bass.BASS_ChannelPlay(stream, false);
    59. CreateWaveForm();
    60. }
    61. }
    62. private void CreateWaveForm()
    63. {
    64. WaveForm wf = new WaveForm(mp3File);
    65. wf.ColorBackground = System.Drawing.Color.Black;
    66. wf.RenderStart(true, BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_PRESCAN | BASSFlag.BASS_DEFAULT);
    67. while(!wf.IsRendered)
    68. {
    69. //todo: prevent endless loop
    70. }
    71. Bitmap bmp = wf.CreateBitmap(4096, 1024, -1, -1, true);
    72. BmpSrc = BitmapToImageSource(bmp);
    73. }
    74. private BitmapImage BitmapToImageSource(Bitmap bitmap)
    75. {
    76. using (MemoryStream memory = new MemoryStream())
    77. {
    78. bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);
    79. BitmapImage bitmapimage = new BitmapImage();
    80. bitmapimage.BeginInit();
    81. bitmapimage.StreamSource = memory;
    82. bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
    83. bitmapimage.EndInit();
    84. return bitmapimage;
    85. }
    86. }
    87. private void Window_Closed(object sender, EventArgs e)
    88. {
    89. if(stream != 0)
    90. {
    91. Bass.BASS_ChannelStop(stream);
    92. }
    93. Bass.BASS_StreamFree(stream);
    94. Bass.BASS_Free();
    95. }
    96. public event PropertyChangedEventHandler PropertyChanged;
    97. protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = "")
    98. {
    99. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    100. }
    101. }
    102. }




    XML-Quellcode

    1. <Window x:Class="BassTest.MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:BassTest"
    7. mc:Ignorable="d"
    8. x:Name="MainWindowName"
    9. Title="MainWindow" Height="1000" Width="1500" Loaded="Window_Loaded" Closed="Window_Closed">
    10. <Grid>
    11. <Grid.RowDefinitions>
    12. <RowDefinition Height="Auto"/>
    13. <RowDefinition/>
    14. </Grid.RowDefinitions>
    15. <Slider Grid.Row="0" Minimum="0" Maximum="100" Value="{Binding ElementName=FWE, Path=MarkerPercentage}"/>
    16. <local:MyFrameworkElement x:Name="FWE" Grid.Row="1" Image="{Binding ElementName=MainWindowName, Path=BmpSrc}"/>
    17. </Grid>
    18. </Window>


    Vermutlich habe ich wieder mal das Rad neu erfunden, mal sehen ob doch noch was besseres kommt. Tut aber seinen Dienst.
    Bilder
    • Unbenannt.jpg

      290,77 kB, 1.491×1.024, 25 mal angesehen

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „BitBrösel“ ()