Laden...

Forenbeiträge von Gimmick Ingesamt 154 Beiträge

02.03.2023 - 17:03 Uhr

👍 Danke, werde ich morgen direkt ausprobieren. 🙂

02.03.2023 - 15:26 Uhr

Hallo,

ich habe hier eine Assembly, aus welcher ich eine Methode mit einem String-Argument aufrufe.

In C# nach dem Prinzip:


[DLLImport("AssemblyName.dll")]
public static extern void StartMethod(string filepath);

public void Test()
{
StartMethod(@"C:\Test\test.ini");
}

VB:


Public Declare Auto Sub StartMethod Lib "AssemblyName.dll" (ByVal filepath As String)

Public Sub Test()
StartMethod("C:\Test\test.ini")
End Sub

Beide Aufrufe werden in der DLL ausgeführt, nur bei der C# Variante kommt dann eine Meldung darüber, dass die Datei nicht gefunden wurde und der angezeigte Pfad besteht aus chinesischen Zeichen.

Wenn das in VB funktioniert, wie muss ich denn dann den string in C# umwandeln, dass er identisch zu VB übergeben wird? 🙂 Liegt das evtl. an den Escape-Symbolen (@ -> double escape = no escape), weil es ein Pfad ist?

12.01.2023 - 12:35 Uhr

Also wäre es vielleicht so gemeint, dass sich HTML-Technologien verbreiten, weil viel in Richtung Multiplatform geht, aber reine Desktop-Anwendungen betrifft das nicht, sie werden nur weiter zurückgehen.

Gibt es überhaupt etwas, das mit MAUI-Blazor gar nicht geht? Dann würde sich doch eigentlich nur die Frage nach den Plattformen stellen. Wenn kein Interesse an Mobile und Web besteht, spricht nichts gegen WinUI (denke ich? 😄), ansonsten landet man zwangsweise bei Maui-Blazor

12.01.2023 - 08:56 Uhr

Ein weiteres Jahr ist verstrichen und ich für meinen Teil bin bzgl. der Frage nach "DEM" Framework für den Windows-Desktop immer noch nicht schlauer geworden. 😁 Weil es thematisch genau passt und ich mich auch auf Abts Blogeintrag beziehe, mache ich mal keinen neuen Thread auf.

Insbesondere habe ich mich bei dieser Vermutung ein wenig gewundert: "Für Desktop-Apps werden sich vermutlich HTML-Technologien wie Blazor durchsetzen, wobei mit Windows 11 auch WinUI3 viele Anwendungsfälle finden werden."

Welchen Vorteil hätte Blazor denn für eine reine Desktop-Anwendung gegenüber WinUI? Für mich klingt die Konstruktion einer Desktop-Anwendung (mit freiem Dateizugriff, usw) mit Blazor immer furchtbar kompliziert im Vergleich zu einem 'klassischen' Desktop-Programm. Zudem integriert sich die Oberfläche doch auch nicht so einfach in die System-Optik, oder?
Was wären denn Punkte bei denen man sage würde "mach das mal lieber mit Blazor/WinUI"? Oder geht die Überlegung eher in die Richtung: Kleine Programme WinUI, umfangreiche UIs eher mit Blazor? Ähnlich wie bei Winforms und Wpf quasi.

11.01.2023 - 13:47 Uhr

Befrag eine Suchmaschine deiner Wahl nach "c# pdf viewer", ich kenne nichts.

WebView2 (oder ein anderes Browser Control) sollte das doch können.

06.12.2022 - 11:52 Uhr

Danke für die Hilfe 🙂
Denn eigentlich ist das doch eine Zuweisung, oder nicht?

Weise der spielsettings den Inhalt aus der Textdatei zu, und nicht addiere.

Kann er aber nicht, weil der setter private ist.
Bei nicht überschreibbaren Properties wird wohl standardmäßig nach einer Add-Funktion gesucht, um die Werte zu setzen.

14.11.2022 - 07:56 Uhr

Es ist ja nicht so, als gäbe es da nichts.
Häufig verwendet werden Oxyplot und LiveCharts2. Die Anwendungsfälle sind aber ein wenig verschieden und Oxyplot wird wohl gerade ein wenig umgebaut, weshalb einige Funktionen als "Depracted" markiert sind, obwohl die Alternative noch nicht vorhanden ist ^^. LiveCharts2 als Nachfolger von Livecharts ist noch Beta, allerdings sehr weit fortgeschritten.

Beides mit MIT-Lizenz und auf Github einsehbar.

@Abt
Was wäre denn die "togo-Lösung" in der Web-Welt?

29.09.2022 - 19:03 Uhr

Lineare Optimierung unter Zwangsbedingungen -> Simplex Verfahren.
Habe jetzt keine konkrete Implementierung parat, aber das gibt es bestimmt schon zu Hauf.

22.09.2022 - 10:31 Uhr

Ich vermute, dass allein durch das Kapseln der Abfragen zu einer Transaktion die Zeiten nochmal fallen dürften.
Hat sich bei Massenupdates bei einigen Tausend Datensätzen, die per PK geupdatet wurde, enorm bemerkbar gemacht.
Auc spart man eben viel Ping/Pong zwischen Client und Server aus.

T-Virus

So wurde daraus jetzt eine Mischlösung mit einer Teilzusammenfassung. Das hat die Zeit auf unter eine Minute gedrückt - das ist allerdings immernoch unangenehm, wenn man davor sitzt und wartet und der resultierende Query ist etwas "unübersichtlich" 😉

Bin wirklich kein Netzwerkadmin und meine Versuche zu verstehen, warum das da so lahm ist, haben nichts ergeben 😄.
Habe nur wiederholt festgestellt, dass ein Update eines Feldes in einem Datensatz > 100 ms dauert - in einem Netzwerk mit eigenem Server (also Hardware, nicht virtuell) und nicht über das Internet oder so. Eventuell so eine Security/Viren Scanner Geschichte...? Ich hab da keinen Plan von.

10.09.2022 - 14:56 Uhr

Also entweder Prinzip-Hoffnung "wird schon so bleiben" und das so reinknüllen, wie ich das geschrieben hatte, damit leben, dass es langsam ist oder komplett neu aufziehen und dann eben 'richtig' machen.

Da wird es wohl auf "es bleibt alles so wie es ist" hinauslaufen.

10.09.2022 - 11:56 Uhr

@Abt
Da sich die Felder ändern können und die Dateien dann editiert werden, geht das dann so wohl nicht.

@T-Virus
Ja, ich gehe davon aus, dass es NICHT die Verarbeitung auf dem Server ist und eine Zusammenfassung helfen wird. Ganz grob überschlagen dauert jeder Query 150-200+ ms schonmal rein für die Anfrage an sich. Mündete dann in z.B. bei einem Vorgang pro Feld pro Datensatz in 200 ms * 100 * 20 > 6 min. Ich gehe davon aus, dass man das netzwerktechnisch schneller machen kann und ich gehe davon aus, dass das nicht passieren wird xD

Es ist alles indexed.

Key/Value Struktur klingt passend.
Die Rahmenbedingungen können nicht geändert werden. Es ist SQL, es gibt Einträge, die sich über tausende Zeilen wiederholen und eigentlich in eine eigene Tabelle gehören, was aber nicht geht, weil es wohl irgendein Programm gibt, das für irgendwas Daten ausliest und das nur aus einer bestimmten Tabelle kann... [Entwickler in Rente oder was weiß ich xD]
Also egal wie murksig das ist - ich kann es nicht ändern 😁

Ich habe jetzt schon mal ein paar Dinge rausgedröselt und das restliche Problem reduziert sich SQL-technisch schlicht auf:

Pseudo:



foreach(Item item in Items)
{

  //item.Data = Dictionary<string, string>
   [sql]
         Update table SET Feld1 = item.Data[V], Feld2 =  item.Data[W], Feld3= item.Data[X], Feld4 = item.Data[Y], Feld5= item.Data[Z] WHERE [Index] =  item.index
   [/sql]
}

Das möchte ich aber nicht, weil auch das dauern kann.

Daher war die Idee:
Alles in eine Temp-Tabelle mit Index, V, W, X, Y, Z bulken -> über den index joinen zum updaten -> tabelle löschen.

Es ist ja grundsätzlich richtig die reine Existenz dieser Dateien in Frage zu stellen - hilft aber nicht 😁

09.09.2022 - 14:42 Uhr

Jeder ORM braucht ein Mapping. Du brauchst also Modelle, die die Datenbankstruktur darstellen. Aber jede relationale Datenbank kann überhaupt erst benutzt werden, wenn es ein Schema gibt.
Ob die Modelle aus Database First oder Code First (Recommended) kommen - egal.

Wie macht man das denn, wenn man die Felder in der DB vorher nicht kennt? Dachte die Objekte spiegeln mit ihren Properties immer die vorhandenen Spalten wieder - oder eben umgekehrt. Dynamic Object, Dictionary?
Abgesehen schreibt man doch mit einem ORM auch per Object, oder? Wenn das super-lahm ist, würde es zwar richtiger werden, aber nicht schneller.

Hab sowas regelmäßig bei Maschinenbauern.
Wir machen das eigentlich so, dass wir die Daten alle lokal aufarbeiten - zum Beispiel durch Transformationen in XML-Dateien.
Und diese XML-Daten werden dann als Quelle für den (echten) Bulk verwendet.

Ja genau, in die Richtung geht das. Und weil ich schon mal per Bulk sowas in der Art für neue Datensätze gemacht hatte, dachte ich, dass es vielleicht besser wäre möglichst intern zu updaten und die Daten erst mal in den Server zu schieben.
Wenn ich so drüber nachdenke, wäre es vielleicht aber besser diese Dateien in eine Struktur zu bringen -> das in der Datenbank abzubilden und dann nur über Verweise zu schreiben...? Könnten komplizierte Queries werden, aber ich glaube das müsste gehen. 😐

Die Datenmenge entscheidet dann, ob man echtes Bulk verwendet oder halt ein ORM.
Wenn die Op jetzt nicht gerade mehrere Tage dauert, dann brauch ich keine Stunden in nen Bulk investieren (schreiben, testen.. = mehr Aufwand als bei EF), das mit EF in Minuten umgesetzt ist.

Ne Tage dauert das nicht, passiert aber ständig. Mittlerweile wartet da jemand schon mal Minuten mitten während der Arbeit (hab ich schon gesagt, dass da alles unfassbar langsam ist? 😄). Es wäre schön die Zeit zumindest auf Sekunden zu drücken. Der Server verarbeitet die Anfragen zwar schnell, aber von Senden bis Bestätigung empfangen vergeht einiges, daher tendiere ich dazu die Anzahl der Anfragen zu reduzieren aber den Gehalt aufzublasen. Gemessen habe ich die reine Verarbeitungszeit über DateTime-Abfragen am Anfang und Ende des Queries.

08.09.2022 - 10:11 Uhr

Das konkrete Problem ist folgendes:

Es gibt ein paar ganz faszinierende Ini-Dateien, aus denen sich Daten, Bedingungen und Felder für das Update ergeben.
Ganz zu Begin wurde das einzeln aufgedröselt und dann pro Feld und Datensatz geschrieben. Wenn die Datenmenge dann steigt eskaliert das natürlich schnell und plötzlich ist man im Minutenbereich...

Ein paar Dinge sind direkt auf Feldinhalte zurückzuführen und können per WHERE in einem Rutsch abgehandelt werden, aber das sind auch erstellte codes bei, die für jeden Index anders sind...

Daher würde ich das gerne komplett umbauen.

Kann man das Entity Framework auch benutzen, wenn man das erst zur Laufzeit generieren kann? Dachte immer man muss bei "Database first" das Model zumindest bei der Programmerstellung erzeugen.

08.09.2022 - 09:24 Uhr

Moin,

ich suche eine für uns sinnvolle Variante zum Massen-Updaten von SQL-Daten, das heißt zügig und am besten ohne Stored Procedure. Abgesehen von ein paar notwendigen Feldern, sind die Spalten im Voraus unbekannt.

Mein bisheriger Favorit wäre:

  1. Temporäre Tabelle anlegen
  2. Datensätze in Datatable laden
  3. Werte lokal ändern
  4. Bulkcopy in temporäre Tabelle
  5. Wenn alles in temp. Tabelle geschrieben -> Update über Join
  6. Drop temp. Tabelle

Ist das sinnvoll / macht man das so, oder gibt es andere, bessere Möglichkeiten?

24.08.2022 - 14:33 Uhr

Vergleich einfach für den Fall, dass die Liste schon eine Zahl enthält, die neue Zahl, mit der letzten Zahl der Liste.

Abgesehen davon ist in dem Schnipsel X innerhalb der Schleife immer gleich, soll das so?

23.08.2022 - 15:05 Uhr

Wenn die in irgendeiner Weise (horizontal, vertikal, ...) aufgelistet werden sollen, kannst Du z.B. das Control "ItemsControl" (einzelne Items kann man nicht auswählen) oder eine ListBox (einzelne Items kann man auswählen) ansehen.

Dafür schaust Du Dir dann wiederum den Hinweis auf das Databinding an und bindest die ItemsSource der Liste an ein passendes Collection Objekt (List, ObservableCollection,..) und verwendest als Template für die Darstellung innerhalb des Listen-Controls eine ComboBox.

Am Ende fügst Du also keine ComboBoxen in das GUI ein, sondern Du fügst Objekte in deine Liste ein und das Control stellt für jedes Objekt eine ComboBox dar. Wie Du dann die ComboBoxen befüllst, hängt u.A. davon ab, ob sich die Inhalte unterscheiden.

Da gibt es auch bei MS auf den Seiten der Controls Beispiele für.

23.08.2022 - 14:40 Uhr

Wozu und in welchem Kontext willst Du das denn machen?
Sollen mehrere ComboBoxen erscheinen (Liste), wenn man öfter Klickt, oder ist das eher so eine an/aus-Sache, bei der es vielleicht auch einfach reicht die ComboBox ein/auszublenden?

23.08.2022 - 14:22 Uhr

Das Warten auf den Prozess blockiert den GUI Thread, daher der Verweis auf die FAQ. Du musst, wie in der FAQ beschrieben, das Starten und Warten auf das Ende des Prozesses in einen Task auslagern und die Ausgabe des Events dann über den GUI-Thread ausgeben.

Und beachten, dass der User den Prozess wahrscheinlich nicht mehrfach starten können soll.

03.06.2022 - 17:50 Uhr

Wenn du keine passende Klasse hast, mit System.Text.Json kann man meine ich in dynamic deserialisieren.


      dynamic obj = System.Text.Json.JsonSerializer.Deserialize<dynamic>("deinjsontext");

System.Text.Json ist von MS, gibt's im nuget.

03.06.2022 - 15:45 Uhr

Nach den weiteren Änderungen ist das wahrscheinlich schon schnell genug und ich weiß auch nicht, das was ich mir dachte noch was bringt und es ist vielleicht etwas kompliziert gedacht, aber nichtsdestotrotz 😄...

Wenn die Ordner alle nummeriert sind, gibt Directory.EnumerateFiles() immer die gleiche Reihenfolge zurück und man sieht direkt am Pfad, ob beim ersten oder zwischen n und n+1 Einträge fehlen. Dann würde ein Durchlauf reichen und das Array muss nicht komplett in den Speicher.

Setzt aber vorraus, dass man genau weiß, was kommen sollte 😉.

30.05.2022 - 17:54 Uhr

Habe gerade ein paar Test gemacht : File.Exist() und QuickIO.FileExist sind ähnlich schnell. Einlesen in string[] oder List<string> und dann Contains() ist 6 Mal langsamer.
Einlesen in ein Dictionary und dann ContainsKey() ist genauso schnell wie File.Exists.
Bei über 20 Millionen Einträgen reicht der Hauptspeicher aber nicht mehr.

Die Datei findet man so : e:\osm{z}{x}{y}.png

Ich frag mal ganz dumm, weil ich die Sache nicht ganz verstanden habe:
Warum werden die Dateien alle abgefragt? Wegen des Kopierens für den Offline-Zugriff?
Die unterste Ordner-Schicht "y" hat 20 millionen Einträge? Oder alles zusammen? Wenn nur alles zusammen, warum dann alles im Speicher halten?

Wenn das fortlaufend und eindeutig nummeriert ist und es "nur" darum geht festzustellen, was fehlt, hilft es dann nicht eventuell, erst mal zu schauen, ob etwas fehlt und wenn ja in welchem Bereich? Dann könnte man sich Contains() sparen und die Anzahl der Abfragen möglichweise deutlich reduzieren.

Oder evtl., wenn eher viele Dateien fehlen und die dann sowieso runtergeladen werden müssen, EnumerateFiles nutzen und bei jedem Eintrag prüfen, ob zum vorherigen eine Lücke besteht (und wie groß die ist), die fehlenden Bezeichnungen in einem sinnvoll begrenzten Puffer halten und gleichzeitig zur Suche runterladen - und loggen bei welcher Datei man war, damit man nicht wieder von vorne anfängt.

Wäre halt blöd, wenn man wegen einer einzigen Datei x Stunden Pfade abfragt, oder man die Sache vielleicht nur eine begrenzte Zeit laufen lassen möchte und dann feststellt, dass man jedes mal die meiste Zeit mit Suchen und nicht mit runterladen/kopieren verbringt.

Und wenn es mehrere SSDs sind, könnte man das nicht evtl. auch gleichzeitig für jede Platte machen?

11.05.2022 - 08:08 Uhr

😁
Habe mal nachgeschaut... ist mir zuviel Win32 zum "mal eben nachvollziehen". Werde mich an dem WPF-Beispiel orientieren und den Drawing.Font-Dialog so lassen ^^.

10.05.2022 - 06:51 Uhr

Ich rede vom ganz normalen Windows-Forms FontDialog in .NET Framework 4.8/.NET6 Win 10.
In der Tat ist die Darstellung in unterschiedlichen MS-Programmen ebenfalls unterschiedlich. In den Optionen von Windows wird dann von "Metadaten" gesprochen ... so eine richtige Einheitlichkeit scheint es nicht zu geben.

Wäre natürlich schön diese eigene Logik zu kennen 😁 Weniger wegen der Gruppierung, sondern mehr, weil .IsStyleAvailable(style) true zurück gibt, obwohl sich bei Auswahl des Styles gar nichts ändert. Da werden die Styles dann wohl unterstützt, aber nicht verwendet.

Ich vermute ein wenig, dass System.Drawing.Font nicht wie System.Windows.Font zwischen Font-Weight und Font-Style unterscheidet und eben alles über die paar enum-typen für den Style abfackelt.

Habe mir mal das WPF Beispiel von MS angesehen, mit Windows.Media.Font scheinen sich diese Probleme in Luft auf zu lösen.

Tendiere nun doch eher dazu es für Drawing.Font einfach zu halten und den Dialog für Media.Font bei Zeiten nochmal zu ergänzen 😄.

09.05.2022 - 19:44 Uhr

Moin,

ich bastel mir gerade diverse Dialoge mit Zusatzfunktionen nach, unter anderem auch den Forms FontDialog.
Dabei ist mir nun aufgefallen, dass in dem original Dialog einige FontFamilies zusammengefasst und dann über den Style ausgewählt werden, Beispiel:
Arial
Arial Black

Bei mir:
Arial - Regular, Bold, Italic
Arial Black - Regular, Bold, Italic
...

Bei Windows:
Arial - Halb Schmal, Halb Schmal Kursiv, Kursiv, Standard, Halb Schmal Fett, Halb Schmal Fett Kursiv, Fett, Fett Kursiv, Schwarz, Schwarz Schräg

Für das Abfragen der Families nehme ich:


System.Drawing.Text.InstalledFontCollection installedFonts = new System.Drawing.Text.InstalledFontCollection();
Foreach(System.Drawing.Font fontfamily in installedFonts.Families)
//In Liste einfügen ...

Und für das Abfragen der verfügbaren Stile:


foreach(System.Drawing.FontStyle style in Enum.GetValues(typeof(System.Drawing.FontStyle)))
{
if(SelectedFontFamily.IsStyleAvailable(style))
...
}

Mein Frage ist nun: Wie kann man die Fontfamilien so zusammenfassen, wie der Dialog das macht, und die zusätzlichen "Styles" erhalten?

01.04.2022 - 16:13 Uhr

Pro System.Windows.Shapes.Path oder pro PathGeometry?

Dem Path müsste man doch einen Style zuweisen können?

So in etwa


Style style = new Style(typeof(DeineKlasse));

Trigger trigger = new Trigger(){Property = DeineKlasse.IsMouseOver, Value = true/false});
Setter setter = new Setter(DeineKlasse.DasProperty, value);// statt value: new Binding(...falls vorhanden...) {Converter = new DeinConverter() }));

trigger.Setters.Add(setter);
style.Trigger.Add(trigger);

DasObjekt.Style = style;

PathGeometry hat aber kein Property für einen Style.

28.02.2022 - 13:02 Uhr

Wenn Du das sowieso aus einer Datei lädst, sollte das eigentlich mit .BeginInit(), BitmapCacheOption.OnLoad und .EndInit() gehen, wenn Du die .UriSource setzt.

03.07.2019 - 10:10 Uhr

Dann mache doch eine Liste von ViewModel-Objekten, eines pro Zeile, binde dort das Model und UI-Info dran und binde das in das Grid.

Ich habe das Gefühl, ich denke manchmal zu kompliziert x), merci.

01.07.2019 - 13:57 Uhr

Hallo,

ich bin gerade dabei ein paar ältere Forms Programme neu zu schreiben und habe Probleme beim Einfärben der Datagrid Zellen.

Die Daten für das Datagrid kommen aus einer Ini-Datei und können beliebig aufgebaut sein. Alle Informationen für den Zell-Inhalt und die Zell-Farbe liegen als Koordinaten vor. Es gibt keinen direkten Bezug zwischen Zell-Inhalt und -Farbe.

In Forms konnte ich einfach die entsprechenden Koordinaten auslesen und die Farbe direkt den Zellen zuweisen.

Aber wie gehe ich denn da in WPF vor?

Aus den Daten der IniDatei baue ich mir zunächst ein Datatable (den Code habe ich beibehalten) und weise dann einfach über dataGrid.ItemsSource = DataTable.DefaultView den Inhalt zu.
Der DataTable enthält ja aber nur Informationen über die Daten, nicht über die GUI.

Ich stehe da ziemlich auf dem Schlauch, wie ich das DataGrid dafür idealerweise anbinde.

17.06.2019 - 08:09 Uhr

Dann würde ich bei beiden Controls gegen das gleiche VM binden. Musst du doch eh machen, wenn diese auf die gleichen Daten zugreifen sollen.

Ja, das sollen nur idealer Weise die Controls selbst machen, so dass man Control1 und Control2 beliebig über die Toolbox einbauen kann, die Verknüpfung der Pärchen aber automatisch entsteht.

Ich habs jetzt erstmal so gemacht, dass man den Control über eine Methode schon noch sagen muss zu welchem Datenbestand sie gehören.

14.06.2019 - 06:48 Uhr

Wieso erstellst du nicht ein neues UserControl das die Text- und ListBox enthält und dieses Control auf die "Datenbasis" zugreift? Damit kannst du die Daten an dieses Control binden und dann auch mehrfach verwenden.

Moin,

die einzelnen Controls können in unterschiedlichen Fenstern/Reitern liegen. Ich muss die schon trennen.

13.06.2019 - 15:16 Uhr

Nachdem ich einiges ausprobiert habe:

Wenn ich zwei Controls habe und beide auf die selben Daten zugreifen können sollen, muss ich die Datenklasse wohl oder übel statisch setzen.

Damit greifen aber alle Control1s und alle Control2s auf die selben Daten zu.

Ich würde jetzt noch eine Schicht darunter eine statische Klasse einbauen, die eine Liste über die nicht-statischen Datenklassen führt und den Controls über ihren Constructor einen festen Index zuweisen.

Muss ich aber wohl noch einen Finalizer einbauen, um den ganzen Kram mit zu entfernen, wenn das Control entfernt wird =/

13.06.2019 - 12:47 Uhr

Hallo,

ich möchte eine DLL erzeugen, die zwei oder mehr UserControls enthält, welche die jeweils gleiche "Datenbasis" haben und sich über die ToolBox einfügen lassen.
Gleiche "Datenbasis" soll z.B. heißen:
Eine Control enthält eine TextBox, das andere Control eine ListBox -> Das Control mit der TextBox zeigt immer die Anzahl der Elemente in der ListBox an.

Meine erste Frage wäre nun: Geht das überhaupt?
Ein neues Control ist doch eigentlich immer ein eigenständiges Object, woher soll die Verbindung zwischen den einzelnen Controls kommen?

Normalerweise hätte ich das ganze in einer eigenen Klasse umschlossen, sodass die Controls nur zur Laufzeit hinzugefügt werden können "Class1 Cl = new Class1" -> Cl.Control1 .... / Cl.Control2 ....

Dann kann man sich die Controls aber nicht im Designer hinziehen wie man es gerne hätte.

Zweite Frage wäre nun: Wenn das geht: Wie? 🤔

10.05.2019 - 17:07 Uhr

Für einen Kurztest habe ich mal 300 Buttons direkt in ein Panel mit Autoscroll gepackt.
Scroll-Balken stockt nicht, aber die Anzeige der Buttons ist dennoch recht langsam. Zudem hängt auch hier nach ein paar Mal hoch-runter-scrollen auch systemweit die Eingabe.

Sind die Bilder denn einmalig in den Speicher geladen oder lädst du diese immer jeweils von Platte nach?

Die Bilder lade ich einmalig.

Ich habe das Problem jetzt mal in sofern umschifft:

DLL:

  • enthält Forms-Usercontrol mit Splitcontainer

  • Splitcontainer enthält einen "ElementHost"

  • WPF-UserControl mit Wrapper + ScrollViewer

  • WPF-UserControl für die Buttons, Bildinfos und das Bild

Das UserControl mit dem Splitcontainer kommt dann in ein TabControl in der Forms-Anwendung.

Das ist ein "wenig" umständlich, läuft aber. Habe mal ~1000 Bilder geladen und die Darstellung war gar kein Problem.

Jetzt habe ich aber das Problem, dass die Optik der WPF-Controls anpassen muss, weil ich in Forms den "Flatstyle" nutze.
Ist aber mein erster Kontakt mit WPF, werde am WE vermutlich dazu mal einen eigenen Thread erstellen 😁

Habt ihr das in Forms denn mal gegenprobiert?

10.05.2019 - 08:15 Uhr

Wie groß sind die Bilder? Du hast was von Vorschau geschrieben ... Nicht dass das nicht klappt und die Hütte Gigabytes schaufelt?

Moin,

die erste "Komplett-Testversion" hat 150*150 px Bilder in die Controls gezeichnet, die letzten Kurztests haben gar keine Bilder gezeichnet, nur die 3 Buttons.

09.05.2019 - 17:55 Uhr

Da muß es noch eine andere Ursache geben, daß es beim Scrollen hängt.

Bei meinen Spieleprojekten verwende ich auch öfters selbstgezeichnete Controls (inkl. JPG-Bildern) in Panels mit Scrollbalken (und konnte bisher nie eine Verlangsamung feststellen - auch nicht bei mehreren 100 Elementen).

Das ist jetzt evtl. ein Missverständnis, für den Test habe ich einfach ein UserControl mit 3 Buttons per Schleife 100 mal in die Controls des flowlayoutpanels gepackt.

Hab das gerade nochmal auf einem anderen Rechner probiert. Die Kiste hat etwas mehr Hubraum - da stockt erstmal nichts, aber auch hier sieht man wie sich die Controls aufbauen / gestreckt dargestellt werden und wenn man mehrmals hoch-runter-scrollt braucht das System (also auch Windows außerhalb des Programs) ein paar Sekunden bevor überhaupt wieder Mauseingaben funktionieren.

Für das Selberzeichnen von Standard-Steuerelementen gibt es die entsprechenden Renderer-Klassen, z.B.
>
(dies sehe ich aber als allerletzte Möglichkeit zur Optimierung).

Falls es aber zu Flackern kommt, dann hilft
>
.

Ok, danke, schaue ich mir auch mal an.
Habe auch mal über den ElementHost ein WPF-Warppanel in ein Forms gepackt. Auf den ersten Blick lief auch das ganz gut. Im Detail habe ich mir das aber noch nicht angesehen.

09.05.2019 - 14:42 Uhr

Hallo.

* versuche mal durch Verringern der Controls rauszubekommen warum das so lange dauert, wer also der Störenfried ist. Also was du im Code gemacht hast auch auf die Controls anwenden.

Habe schon ein Testprojekt erstell, dass einfach nur ein UserControl mit 3 Buttons x-mal in das Panel packt. Es steht und fällt mit Größe des Fensters, bzw. vermutlich eher mit der Anzahl der gleichzeitig sichtbaren Controls im Panel.
Da hängt beim Scrollen einfach alles.

* im WPF gibt es virtuelle Container, z.B. VirtualStackPanel. Diese generieren Elemente erst wenn sie sichtbar werden. Google mal ob es Ansätze/Codebeispiele/Controls für WinForms existieren dann brauchst du das Rad nicht neu erfinden.

Wie intern die Elemente gehandhabt werden weiß ich nicht. Es kann aber auch an der Zeichengeschwindigkeit liegen und in dem Fall wird selber alles Zeichnen den Braten nicht fett machen. Gerade wenn man scrollt und dann immer alles neu zeichnen... ich seh schon die Flackerhölle vor mir.

Habe auch gerade mal das Ganze in WPF mit einem Wrappanel nachgebaut (einfach ScrollViewer + Wrappanel + 200 UserControls) -> scrollt ohne Probleme.

Der Plan war die Galerie über eine DLL in ein bestehendes Form-Programm einzubauen, wenn ich dafür jetzt WPF nutzen würde, hätte ich dann durch die Mischung mit Problemen zu rechnen? Oder bremst evtl. das langsamste Glied der Kette und WPF in Forms ist genauso lahm wie Forms alleine?

09.05.2019 - 10:10 Uhr

Die langsamere Performance beim Scrollen wird aber wohl eher an dem FlowLayoutPanel sowie der Anzahl der eingefügten Elemente liegen - evtl. müßtest du diese auch selber zeichnen (und die Positionen berechnen).

Dazu hätte ich einige Fragen:

Was bedeutet in dem Fall "selber zeichnen"? Ich verstehe das so, dass ich dann das FlowLayoutPanel rauswerfe, eigene ScrollBars einfüge und anhand der Scrollposition für jedes Bild schaue:

  1. Wo liegt es
  2. Was sehe ich davon

Und dann entsprechend einzeichne.

Aber wie mache ich das mit nutzbaren Controls wie Buttons?
Kann ich evtl. mein UserControl so lassen wie es ist, das Control als Bitmap zwischenlagern und dann in der Zeichenfläche die Mausposition gegen jede errechnete Control/Bild-Position gegenchecken, den Klick abfangen, den Button in den pressed-Zustant setzen -> neues Bild generieren und das einzeichnen?
Oder im Worstcase das Usercontrol als Sammlung an Controls und Koordinaten speichern und nur den Button neu zeichnen?

Da müsste man dann wohl am besten noch eine Listung sichtbarer Objekte führen, damit nur da geprüft wird, wo auch geklickt werden kann.

Klingt aufwendig, oder denke ich zu kompliziert?

GDI-Objekte, wie Brush, Pen o.ä. sollten immer wieder sofort nach Benutzung freigegeben werden (also entweder per Dispose oder aber besser gleich eine using-Anweisung benutzen).

Bei festen Farben reicht es aber direkt auf die Brushes- bzw.Pens-Klasse zuzugreifen:

  
SolidBrush brush = Brushes.White;  
  

so daß nicht jedesmal ein neues temporäres GDI-Objekt erzeugt wird (und wieder freigegeben werden muß)!

PS: Auch die beiden fixen Rectangle könntest du als static readonly-Klassenmember einmalig erzeugen...

Da hast Du absolut Recht, ich wurschtel das Anfangs meistens erstmal so rein und räume später auf, wenn klar ist wohin die Reise überhaupt geht ^^.

08.05.2019 - 15:46 Uhr

Hallo zusammen,

ich tüftel gerade an einer Bildergalerie, die neben der Anzeige eines Vorschaubildes noch mehr Funktionen bieten soll und stoße dabei auf ein Performanceproblem.

Bisher hatte ich es so aufgebaut:

  • Auswahl mehrerer Bilder mit blauem Rahmen als optisches Feedback
  • Ein seletiertes Bild ist das "Hauptobjekt", angezeigt durch einen zusätzlichen orangenen Rahmen
  • zu diesem Hauptobjekt werden in einem Datagrid diverse Infos angezeigt
  • Unter jedem Bild befinden sich Buttons: Als "Hauptobjekt" auswählen, Entfernen, Originalbild öffnen
  • Über jedem Bild ist eine Checkbox, um die Bilder einer Auswahl hinzuzufügen
  • Unter jedem Bild sind zwei label für Dateinamen + Datum

Gebaut hatte ich das folgendermaßen:

Das UserControl enthält die Buttons, Checkbox und label. Das Vorschaubild und die Rahmen zeichne ich direkt in das Control.
In das flowlayoutpanel werden die UserControls eingefügt
Das flowlayoutpanel befindet sich dann zusammen mit dem Datagrid in einem SplitContainer

Funktional ist bisher alles super, aber man merkt einfach, dass es bei ~30+ Bildern unglaublich träge wird. Das Scrollen stockt dann und bei Änderung der Fenstergröße hängt die Galerie deutlich nach.

Das Zeichnen erledige ich im Paint-Event des UserControls:


        private void DrawImage(Image Bild, Graphics G)
        {
            G.DrawImage(Bild, new Point(_StartX, 15));
        }

        private void DrawSelection(bool Val, Graphics G)
        {
            if (Val)
            {
                SolidBrush brush = new SolidBrush(Color.LightBlue);
                G.FillRectangle(brush, new Rectangle(5, 5, 190, 170));
                _paintedBlue = true;
            }
            else if (!Val && (_paintedBlue || _paintedOrange))
            {
                SolidBrush brush = new SolidBrush(Color.White);
                G.FillRectangle(brush, new Rectangle(5, 5, 190, 170));
                _paintedBlue = false;
                _paintedOrange = false;
            }
        }

        private void DrawMainSelection(bool Val, Graphics G)
        {
            if (Val)
            {
                SolidBrush brush = new SolidBrush(Color.DarkOrange);
                G.FillRectangle(brush, new Rectangle(15, 10, 170, 150));
                _paintedOrange = true;
            }

        }

        private void LargeGallery_Image_Paint(object sender, PaintEventArgs e)
        {

            DrawSelection(_Selected, e.Graphics);
            DrawMainSelection(_Mainselection, e.Graphics);
            DrawImage(_Bild, e.Graphics);

        }

Auskommentieren der einzelnen paint-methoden macht es schneller, aber ehrlichgesagt ist es selbst ganz ohne Bild und Rahmen, nur mit den Buttons etc., auch schon zu langsam beim Scrollen.

Habt ihr einen Vorschlag, wie man das besser umsetzen könnte?

15.03.2019 - 14:43 Uhr

Meine "Lösung":


int NumberOfPoints = chart1.Series[0].Points.Count;
double width = chart1.ChartAreas[0].innerPlotPosition.Width * chart.Width / 100;
double PointSpace = width / NumberOfPoints / 2;

chart1.Series[0].SetCustomProperty("PixelPointWidth", ((int)PointSpace).ToString());
chart1.Series[1].SetCustomProperty("PixelPointWidth", ((int)PointSpace).ToString());


Series[0] enthält die Datenpunkte für die Balken
Series[1] enthält die Datenpunkte für die Linien in Form von Fehlerbalken, wobei die drei Y-Koordinaten einfach identisch sind 😄.

Die Breite der Fehlerbalken musste nur angeglichen werden.

15.03.2019 - 12:58 Uhr

Hallo,

ich würde gerne in mein Balkendiagramm (edit: "Column") horizontale Linien zeichnen, die genau in den Balken liegen.

Dafür brauche ich aber die Koordinaten der Balkenränder oder zumindest die Dicke der Balken, die Koordinate der DataPoints kann man ja abfragen.

Ich finde dazu aber nur die CustomProperties:

PointWidth für den Abstand der Balken

und

PixelPointWidth für die Breite der Balken

Wenn ich die benutze, müsste ich mir aber selber überlegen wie ich die Abhängigkeit der Werte zur Chart-Breite und Punkt-Anzahl setze.
Das möchte ich mir eigentlich sparen. 😉

Kennt jemand evtl. noch eine andere Möglichkeit die Linien umzusetzen?

edit2: Bildanhang; Mit Paint gemalt.

15.03.2019 - 08:40 Uhr

Gute Sache, danke fürs Posten 👍

13.03.2019 - 13:29 Uhr

Wenn das Bild auch in voller Auflösung 1:1 sichtbar sein kann, ist das natürlich blöd.

Wenn es sich aber um hochauflösende Fotos handelt, würde ich dennoch (evtl. in Abh. der Monitorauflösung) ein Dummybild erstellen, zwischen 2 MP und 45 MP gäbs dann doch schon noch einen Unterschied ^^.

In Bildbearbeitungsprogrammen gibt es ja auch immer eine Vorschau, das hat schon seinen Grund 😉.

13.03.2019 - 13:23 Uhr

Schau mal hier für das Prinzip:
https://code.msdn.microsoft.com/windowsapps/Blending-Bitmap-2922c196

Wenn das Überblenden nach Schrittzahl gehen soll, könnte man die Schrittweite pro Pixel getrennt hinterlegen und so noch minimal Rechenzeit sparen, soll das Überblenden nach Zeit gehen, müsste man die Schrittweite zumindest nach dem ersten Schritt anpassen.

Ansonsten könnte man auch hier wieder ein bissl lügen und betrügen und z.B. nur jeden zweiten Pixel abwechselnd ändern. 😁

13.03.2019 - 12:03 Uhr

Ich kann nur aus Erfahrung mit diversen Bildbearbeitungsprogrammen sagen, dass die Filter immer ihre Zeit brauchen.

Bei der ColorReduction könnte man schauen, ob es verschiedene Dither-Methoden gibt, die dann evtl. etwas schneller sind.

Wenn Du von eienr Diashow sprichst, klingt das danach, dass eine Reihe von Bildern nach und nach angezeigt werden. Da könnte man zum Kaschieren der Rechenzeit ja schon im Vorraus anfangen zu Rechnen.

Und je nach Aufteilung der Bildanzeige, also Original, farbreduziert und mit ölfilter, benötigst Du ja eventuell auch nicht die volle Auflösung der Bilder.

22.12.2018 - 16:03 Uhr

So ganz klar ist mir die Methode ehrlichgesagt nicht.
Du hast in Deinen FillRectangel()-Aufrufen dem Namen nach immer eine Farbe und eine zoom-abhängige Höhe/Breite als Parameter. Heißt das, dass du für jeden Wert aus deinen Rohdaten ein einfarbiges Rechteck zeichnest?

Ein ganzes Bitmap zu zeichnen geht deutlich schneller.

Ich würde sowas machen wie:

  1. Über Scrollposition und Zoom die Größe und Position des "Datenfensters" bestimmen.

  2. Über HöheBreite3 ein 24bpp 1D-Array erstellen

  3. Die Daten aus dem Fenster Farben zuordnen, in das Array schreiben und das Array über irgendeine Methode auf die Ausgabe skalieren (nearest neighbor evtl. da findet man auch gut was zu).

  4. Die Daten aus dem Array in das Bitmap schreiben (z.B. mit Marshal.Copy/Lockbits)

  5. Bitmap Anzeigen in Picturebox oder direkt zeichnen mit drawImage.

Wenn ich das richtig verstanden habe werden nicht die gesamten Daten mit 25Hz erneuert, sondern alle 40ms kommt eine neue Zeile und die alten Daten werden nach und nach überschreiben? Man könnte dann ja auch Scheibchen-Bilder erstellen oder einen TextureBrush benutzen, müsste man wohl ausprobieren.

20.12.2018 - 08:03 Uhr

Was meinst Du denn mit "komplex"? Die Größe des Bildes oder wird der Inhalt des Bildes erst berechnet und das dauert?

13.12.2018 - 12:48 Uhr

Nur mal ein Update:

Die Arbeit mit einer Kombination aus Gitlab und Redmine hat sich bisher bewährt. Eure Posts haben sehr geholfen, danke.

23.11.2018 - 12:16 Uhr

Doch. Dafür hast Du ja Dein Git Repository.
Und ein Release ist immer mit einem Git Commit getaggt.

Achso, ich dachte das würde immer überschrieben werden.

Das Grundproblem ist meiner Ansicht nacht immer noch, dass eure internen Prozesse mit einem modernen DevOps Prozess und den Mechanismen in einem Release System nicht im Einklang stehen.

Davon abgesehen, dass dies kein roter Faden durch DevOps wäre: das Ergebnis wäre aber kein deterministisches.
Das gilt es in DevOps zu vermeiden.

Ne, das ist nicht das Grundproblem.

Es geht hier ja rein um das Verständnis des vorgesehenen Prozesses und vorallem um die reale Umsetzung davon mit Git - von null. Was muss ich wo einstellen, was macht die Pipeline konkret und wie sieht der tatsächliche Release-Prozess aus. Der reale Prozess hat damit erstmal nichts zu tun.
Das Zusammentreffen mit der Realität folgt erst noch.

Ich finde die ganze Sache schon rein von den Begriffen verwirrend.
Der Hinweis mit den Tags war gut.

Ich muss jetzt mal Zeit finden und mein Gitlab nach den Prinzipien einstellen. Dann wieder im Kleinen testen.

Ich seh die Probleme bei der Pipeline schon - ich melde mich dann 😄.

23.11.2018 - 07:50 Uhr

Der Quellcode ist "neutral". Die Anpassung an die Environment passiert via
>
.

Drück es umgehrt aus: aus dem Masterbranch wird ein Artefakt (Komponente, Anwendung, ...) erstellt und dieses Artefakt wird an die Environments wie Dev, Test und Prod weitergereicht (ohne dabei verändert zu werden, siehe Konfig).

In dem Fall hätte man aber kein Backup des Codes, aus dem der aktuelle Prod-Stand erstellt wurde.

Hi Gimmick,

um es vielleicht mal mit einem anderen Ansatz zu erklären.

Die willst 3 Quellcode Branchen hab. (Dev, Main, Release)

[...]

Dann kannst (musst aber nicht) du für alle 3 ein Dev, Test und Release Environment haben.

[...]

Erstmal danke für den umfangreichen Post.

Wenn ich nicht jeweils drei eigene Environments hätte, müsste ich aber in der Pipeline prüfen, in welchem Branch ich gerade bin, damit das Main-Artifact nicht nach dem Prod/Release-Release-Prozedere veröffentlicht wird.

Und das meinte ich damit, dass die Environments ja quasi von den Branches wissen müssen.

Wenn ich hingegen drei Branches anlegen, würde ich ja doch mein Release über die Branches oragnisieren - und darf man doch nicht ^^.