Das liest sich eher so, als ob es an dem verwendeten ZIP-Dateiformat: Packalgorithmen liegt. Der Standard ist Deflate, aber vllt. sind .padfx-Dateien anders komprimiert? Schau mal in How to determine compression method of a ZIP/RAR file, wie man die Kompressionsmethode auslesen kann.
Schau dir mal Workflow Core an, besonders das Parallel sample.
Du hast anscheinend nur den Verzeichnisnamen angegeben, es fehlt aber der Ressourcename, d.h.
var rm = new ResourceManager("CalendarApp.i18n.resources", typeof(CalendarForm).Assembly);
Du kannst dir auch mal das Beispielprojekt .NET 5 Windows Forms localized app anschauen.
Aber warum hast du die Ressourcendateien (sowie den Resource-Manager) nicht von VS erstellen lassen? → Exemplarische Vorgehensweise: Lokalisieren von Windows Forms
PS: i18n
als Verzeichnisname, sowie insbesondere als Namensbereich, halte ich persönlich für nicht so gut.
Schau mal in die Antworten von How to receive ICMP response "Port unreachable" to UDP message in C#. Evtl. brauchst du einen eigenen Socket
für das Icmp
-Protokoll?
Wenn ich dich richtig verstehe, dann möchtest du den gerenderten HTML-Code der angezeigten Formeln als externe Datei (DOCX oder PDF) speichern?
Dies sollte direkt aus JavaScript mit der Bibliothek jsPDF (mittels doc.html()
) möglich sein, s.a. die Antworten bzgl. jsPDF
in Generate pdf from HTML in div using Javascript. Du müßtest aber mal einen Test machen, ob auch MathJax damit unterstützt wird.
Für DOC/DOCX habe ich den Artikel Export HTML to MS Word Document using JavaScript gefunden. Auf dieser Webseite gibt es auch einen Artikel zur Benutzung von jsPDF
: Convert HTML to PDF using JavaScript (Edit: Im Beispiel ist nur ein kleiner Schreibfehler bzgl. content
<->contnet
)
Mathematisch erscheint mir deine Formel aber fehlerhaft, denn ein Abstand sollte ja eine Addition sein, keine Multiplikation. Außerdem mußt du je x
und y
sowohl sin
als auch cos
verwenden.
Richtige Rotationsformel s. Drehmatrix der Ebene ℝ² und Transformationen in 2D mit Matrizen.
Und eine Rotation berechnet sich üblicherweise aus: -Translation → Rotation → +Translation (wobei Translation zum Rotationsmittelpunkt gemeint ist).
Auf englisch habe ich dazu auch Revised Right End Point of rotated rectangle in C# gefunden (beachte besonders die Berechnung des Radius
in der 1. Lösung, d.h. den Abstand des Eckpunktes zum Mittelpunkt).
Hallo und willkommen,
zuersteinmal ein paar Fragen zu deinem Code:
Warum willst du überhaupt nachträglich eine Linie zeichnen anstatt schon beim Platzieren des Rechtecks? Und ist dieses per XAML oder per Code gesetzt, d.h. warum übergibst du den Namen anstatt eine Objektreferenz?
Und mathematisch: welches ist der Rotationspunkt, um den das Rechteck gedreht ist (z.B. Links oben oder Mittelpunkt)?
PS: Bzgl. "NaN" s. WPF Canvas.GetLeft() always receive NaN value.
Die Assembly ist aber wohl eingebunden (wie man im Bild beim Projektmappen-Explorer sieht).
Außerdem ist es eigenartig, daß nur diese Methode nicht gefunden wird, aber z.B. kein Fehler bei der Open
-Methode eine Zeile vorher.
@chilli1981: Bewege mal die Maus über Runspace
und wähle dann per Kontextmenü "Gehe zu Deklaration" und schau dir dort dann mal die Klasse an, ob die Methode CreatePipeline
dort aufgelistet ist. Evtl. verwendest du eine ältere Version - auch wenn das aus der Doku nicht hervorgeht, daß es Versionsunterschiede bei den Methoden gibt).
Verwendest du denn .NET 5 (oder höher) oder noch .NET Framework 4.x?
PS: Evtl. kannst du dir auch mal RoboSharp anschauen.
Das kann aber so nicht funktionieren, denn IUserRepository
muß ja in beiden Schichten bekannt sein (denn in der Datenschicht muß es ja eine konkrete Klasse geben, welche dieses Interface implementiert), also darf es nicht in der Logikschicht definiert sein, sondern zwingend im DAL.
Das Interface sollte ja relativ stabil (über die Zeit) sein, aber wenn sich etwas ändert (z.B. neue Methoden oder Parameter ändern sich), dann müssen beide Schichten angepaßt und neu kompiliert werden.
Sicherlich kann man noch ein extra Projekt nur für die Schnittstellen machen, dies lohnt sich aber erst bei größerem Projekten (vor allem wenn man mit Fremdbibliotheken bzw. eigenen Teams arbeitet, die eine komplette Schicht umsetzen bzw. es alternative Implementierungen gibt, welche in verschiedenen Anwendungen genutzt werden z.B. für Kunden mit verschiedenen Datenbanksystemen).
Evtl. fehlt noch range.Select()
sowie die Verwendung von End - 1
, s.a. How to paste table to the end of a Ms-Word document using C#.
Hallo und willkommen,
mit Content.Paste()
wird das gesamte Dokument ersetzt. Ähnlich wie beim Öffnen mußt du einen Range
definieren, in den dann die Daten eingefügt werden, s.a. Programmgesteuertes Definieren und Auswählen von Bereichen in Dokumenten sowie Programmgesteuertes Suchen und Ersetzen von Text in Dokumenten.
Probiere mal
Range range = ZielDokument.Range(ZielDokument.Content.End, ZielDokument.Content.End);
range.Paste();
PS: Du solltest das Zieldokument auch noch abspeichern.
OK, also als eigenes Control (z.B. Panel
) könntest du dies auch umsetzen. Dazu dann bei jedem AfterCollapse/AfterExpand-Ereignis ein Neuzeichnen, z.B. per Invalidate()
, anstoßen.
Und dann (abhängig von der Scrollbar) bei TopNode beginnen und durch die Knoten des TreeView
iterieren (entsprechend IsExpanded ), und mit gleichem Font die Zeilennummern zeichnen, damit die Höhe paßt - s.a. [Tutorial] Zeichnen in Windows-Forms-Programmen (Paint/OnPaint, PictureBox).
Du kannst dies auch als ein UserControl
umsetzen, das beide Controls beinhaltet (und z.B. bei Größenveränderung korrekt reagiert).
Insgesamt ist dies etwas langsamer als direkt im TreeView zu zeichnen, da 2x iteriert wird, aber dafür muß man nicht selber das Zeichnen des TreeViews übernehmen (bzw. anstoßen).
Edit: Es gibt kein OnScroll
-Ereignis beim TreeView
, daher müßtest du mit einem Timer
überprüfen, ob sich TopNode
geändert hat (und dann ebenfalls ein Neuzeichnen veranlassen).
Edit2: Wenn man von TreeView
ableitet, kann man auf das Scrollen reagieren: [RESOLVED] Trapping TreeView's Scroll Events?
So mußt du jetzt selber entscheiden, welcher Ansatz für dich einfacher umzusetzen ist.
Eine andere Möglichkeit, anstatt große Liste mit Scrollbar, wäre Paging (also nur eine begrenzte Anzahl anzeigen, dann aber "vor" und "zurück"-Buttons).
(Deutsche) Bücher kenne ich keine, welche detailierter die WinForms-Interna beschreiben.
Das hatte ich bei deinem Code auch noch gesehen, aber vergessen zu schreiben.
Du darfst das Graphics
-Objekt nicht 'disposen', da es ja intern von Windows Forms verwaltet wird und über die PaintEventArgs
zur Verfügung gestellt wird.
Und ich denke auch, daß bei dir dann bei mehr als 1000 Picture-Controls dann die Anzahl der verfügbaren Handles überschritten wurde (du hast ja pro Bild mehrere Labels, die auch jeweils ein Handle benötigen). Ich hatte auch nicht gedacht, daß du so viele Bilder gleichzeitig anzeigen möchtest (darum hatte ich ja Caching erwähnt).
PS: So sieht dein Projekt schon viel besser aus.
Ich meinte das gesamte Testprojekt als ZIP-Datei, aber auch aus deinem bisherigen Code kann ich schon einiges lesen.
Bist du in der Zeit stehengeblieben, denn die Klassen ArrayList
und Hashtable
sind aus .NET 1 (also mehr als 20 Jahre alt) und benutzt man schon seit .NET 2 (2005) nicht mehr? Und du brauchst dann auch keine eigene Collection
-Klasse zu entwickeln. Benutze einfach List<T> und HashSet<T>.
Und für das Scrollen brauchst du auch keine eigene Scrollbar, denn die Panel-Klasse (welche von ScrollableControl abgeleitet ist), unterstützt dies schon automatisch, einfach die Eigenschaft AutoScrollMinSize passend setzen (also die Größe, ab der Scrollbars angezeigt werden sollen) - dies geht auch dynamisch z.B. in OnPaint
.
Und um dort dann passend zur Scrollposition zu zeichnen, einfach
e.Graphics.TranslateTransform(AutoScrollPosition.X, AutoScrollPosition.Y);
vor dem eigentlichen Zeichnen der eigenen Objekte aufrufen.
PS: Meinst du "Dimensions" (anstatt "Dimentions")?
Jetzt verstehe ich, du meinst diesen Spezialfall Potenzfunktion: Ungerade Wurzeln aus negativen Zahlen.
So funktioniert weder die Fließkommadarstellung (float
, double
) noch die Pow
-Funktion:
1/3
wird direkt der ausgerechnete Wert 0.33333...
übergeben (aus dem nicht direkt zurückgerechnet werden kann, um welche ganzzahligen Werte einer natürlichen Division es sich handelt)Pow(x, y)
-Funktion berechnet intern den Wert aus e^(y * ln(x))
und ln(x)
ist für negative x nicht definiertMein Parser hat jedoch schon in FormulaParser
die Methode Root
(Zeile 88), die du dann anpassen kannst:
static double Root(double x, double y)
{
if (x < 0)
return -Math.Pow(-x, (double)1/y);
else
return Math.Pow(x, (double)1/y);
}
Nun sollte auch x#3
für negative x-Werte funktionieren.
Falls du diese im Parser auch als Funktion aufrufen möchtest, anstatt nur über (den von mir selbst gewählten Operator #
), so mußt du diese in FormulaParser
dem statischen Functions
-Array hinzufügen:
new Function("root", Root)
Aufruf dann z.B. mit root(x,3)
bei der Parser-Eingabe.
PS: Dein Code erscheint mir noch verbesserungswürdig. Was soll z.B. Loeschen_Clicked(...)
innerhalb der Schleife?
Das ist ja einfach mathematisch (für reelle Zahlen) unbestimmt, d.h. für negative x sind die beiden Funktionen Potenz und Wurzel nicht definiert, s. a. Potenzfunktion (auch dort sind im rechten Bild die Graphen bei diesen Funktionen nur für positive x dargestellt, z.B. bei der Wurzelfunktion x^(1/2) der schwarze Graph).
Die Wurzel aus negativen Zahlen ist ja nur bei Komplexen Zahlen definiert.
PS: Beruht dein C#-Programm auf meinem Graph-Programm (Graph.zip) aus dem Beitrag oder hast du ein komplett Neues erstellt?
Dein Design paßt nicht: dein MainWindowViewModel
hast du von Node
abgeleitet, so daß nur dessen CurrentNodeName
gebunden ist, jeder Node
setzt jedoch in IsSelected
nur seine eigene CurrentNodeName
-Eigenschaft.
Du solltest also die Ableitung von Node
entfernen (und stattdessen ein ViewModelBase
benutzen). Und dann hat nur MainWindowViewModel
die CurrentNodeName
-Eigenschaft. Und die einzelnen Node
-Objekte müssen dann über eine Referenz (oder per Ereignis) die eine MainWindowViewModel.CurrentNodeName
-Eigenschaft setzen.
PS. Warum hast du sowohl Nodes
als auch, durch die Ableitung von Node
,Children
in deinem MainWindowViewModel
?
Hallo CSharpNewbie2022,
der Name Datenzugriffsschicht (Data Access Layer) bezieht sich ja gerade auf das Kommunizieren mit externen Komponenten, um Daten zu erhalten (lesen) und zu senden (schreiben). Der Geschäftslogik ist es dann egal, woher genau und mit welcher technologischen Umsetzung diese Daten kommen (bzw. gesendet werden), so daß diese Komponenten einfach(er) ausgetauscht werden können (für das gleiche Projekt, falls sich die Anforderungen oder Infrastruktur geändert hat oder auch für andere, ähnliche auf der Geschäftslogik aufgebaute Projekte).
Du kannst dir auch mal die Zwiebel-Architektur anschauen, z.B. DDD mit Onion Architecture. Dort fallen dann alle externen Zugriffe unter die Infrastruktur, d.h. der äußere Kreis. Und der innere Kreis ist dann die, auf Zeit langlebig gedachte, stabile Geschäftslogik.
Theoretisch gibt es keine Grenze bei den Controls, jedoch sollten nicht mehr als einige Hundert pro Anwendung gleichzeitig dargestellt werden.
Und für alle aktiven Programme zusammen gibt es (standardmäßig) eine Grenze von ca. 32.000 (oder 64.000)-Objekten (jedes Control benutzt intern ein Windows-Handle).
Lies auch mal [FAQ] Flackernde Controls vermeiden / Schnelles, flackerfreies Zeichnen (sowie die weiteren dort verlinkten Artikel).
Generell werden aber bei einer scrollbaren Liste (oder Grid) nur die Controls gezeichnet, die auch gerade im sichtbaren Ausschnitt sind. Bei virtuellen Containern geht es eher darum, daß nicht alle untergeordneten Controls gleichzeitig im Speicher liegen müssen (sondern evtl. nachgeladen sowie die nicht mehr sichtbaren gelöscht werden).
Es gibt aber sicherlich weitere Performanceverbesserungsmöglichkeiten. Gerade bei Bildern sollte man Caching in Betracht ziehen, damit die Skalierung nicht jedesmal on-the-fly beim Zeichnen passiert.
Kannst du evtl. ein Testprogramm erzeugen und als Anhang hier hochladen?
Schau dir mal den Code in github.com/OPCFoundation/UA-.NETStandard/blob/master/Applications/ConsoleReferenceClient/Program.cs an - dort wird in Zeile 206 ein UserIdentity
-Objekt mit UserName
und Password
erstellt.
Hallo und willkommen,
welchen OPC UA Client verwendest du denn genau und wie erzeugst du bisher die Verbindung?
Edit:
Für UA-.NETStandard s. Connect to OPC UA Server with UserName/Password.
Ja, mit Container-Control meinte ich z.B. das TableLayoutPanel
oder ein Eigenerstelltes (für ein eigenes Projekt hatte ich dafür selber ein einfaches erstellt, s. Anhang). Beide unterstützen aber keine Selection
, aber wie oben schon geschrieben, kann man dies mit den entsprechenden Ereignissen erweitern.
Vermutlich bin ich dann auch für das Zeichnen oder Darstellen der Element Verantwortlich?
Nein, sobald ein Control zu Controls hinzugefügt wird, wird es automatisch angezeigt (sofern Visible = true
ist).
Was genau meinst du mit TabLayout
(ich finde nur Links zu Android)? Oder meinst du das TableLayoutPanel?
Von welcher UI-Technologie (WinForms, WPF) sprichst du denn?
XnView und z.B. auch IrfanView sind mit C++ und der WinAPI erstellt. Dabei werden die Bilder mittels GDI+ gezeichnet.
Bei .NET entspricht dies WinForms mit einem Panel
und der Verwendung der Graphics-Klasse, s.a. [Tutorial] Zeichnen in Windows-Forms-Programmen (Paint/OnPaint, PictureBox).
Üblicherweise erstellt man dazu dann ein UserControl
, welche das Bild darstellt (ähnlich wie PictureBox
, nur evtl. mit weiteren Darstellungsmöglichkeiten und der Anzeige des Dateinamens etc.).
Und das Selektieren wird dann per MouseDown
und KeyChar
-Ereignissen gesteuert, evtl. ist aber auch ein eigenes Container-Control dafür intern erstellt.
Ähnliches ist aber auch bei anderen UI-Technologien, wie WPF (Stichworte: Grid
, ItemsControl
, Image
), möglich.
PS: Das ListView
wurde für den Windows Explorer und den Desktop entwickelt (und bei Windows 95 zuerst eingesetzt) und hat (bis heute) leider nur die vorgefertigten Darstellungsmöglichkeiten und ist daher in vielen Anwendungen nur begrenzt einsetzbar.
Hallo und willkommen,
stehen die neuen Werte auch in Environment.GetEnvironmentVariables? Ansonsten müssen die geänderten Umgebungsvariablen mittels Environment.SetEnvironmentVariable gesetzt werden. Diese Liste wird dann beim Process.Start
an den neuen Prozess übergeben.
Ansonsten kann man auch explizit die Umgebungsvariablen mittels einem ProcessStartInfo-Objekt übergeben: ProcessStartInfo.EnvironmentVariables
Das verstehe ich auch nicht, da ein OnPropertyChanged(nameof(...))
die UI antriggert, die ObservableCollection
wieder neu einzulesen (d.h. den Getter der Eigenschaft aufzurufen).
Persönlich lösche ich aber auch immer diese Collection und fülle sie dann. Dafür habe ich extra folgende Extension-Methoden erzeugt:
namespace MVVM_Library
{
public static class Extensions
{
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
collection.Add(item);
}
public static void SetRange<T>(this ICollection<T> collection, IEnumerable<T> items)
{
collection.Clear();
collection.AddRange(items);
}
}
}
Hallo CSharpNewbie2022,
in MVVM - Woher bekommt ein ViewModel übergreifende Daten? Von parallelen ViewModellen oder von darunterliegenden Modellen? wurde diese Frage auch schon mal behandelt (auch mit Code-Beispielen).
Ja, da stimmt - direkt ist das nicht möglich, aber schau dir mal die Antworten in How to populate a WPF grid based on a 2-dimensional array (auch wenn der Ersteller etwas anderes wollte) an.
Oder suche mal nach "high precision/resolution timer", z.B. PrecisionTimer.NET.
Für UI-Interaktionen sollte man diese aber nur mit Bedacht nutzen, da man bei zu hoher Frequenz den UI-Thread lahmlegt, s.a. [FAQ] Warum blockiert mein GUI?
Und speichere den aktuellen Status in einer Membervariablen, so daß du nur bei Änderung das UserControl austauschst.
Hallo,
m.E. wäre es dann besser, nur eine Form zu haben und zur Laufzeit 2 verschiedene UserControls zu verwenden, die dann abwechselnd angezeigt werden (und evtl. den Titel anpassen).
So brauchst du auch nur einen Timer in der einen Form zu verwenden.
PS: Falsches Unterforum - evtl. verschiebt ein Mod dieses Thema nach "GUI: Windows-Forms"?!
Könntest du evtl. ein Testprojekt (d.h. auf das Wesentliche reduziert) erzeugen und hier als Anhang hinzufügen?
Das einfachste wäre das Erstellen einer CSV-Datei (mit entsprechend leeren Einträgen für die Leerzeilen bzw. Leerspalten).
Tipp: CsvHelper
Zitat von DanHue
Wenn ich aber einen Wert über die Buttons geändert habe und dann "ViewmodelData" ändere, wird der neue Wert nicht mehr im Textfeld des "NumInput" aktualisiert (die anderen Textboxen aber schon).
Dann hatte ich dies evtl. falsch verstanden - du tauschst also das ViewmodelData
-Objekt aus (und änderst nicht nur die Value
-Eigenschaft)?
Dann zeige auch dazu mal den Code.
Hast du 2 verschiedenen Value
-Eigenschaften, einmal in ViewmodelData
und zusätzlich in NumInput
? Wie sind diese denn verknüpft bzgl.
Value="{Binding Path=FfuListItem.Speed1, ElementName=root, Mode=OneWay}"
?
Und was hast du denn als DataContext
(jeweils) gesetzt?
Du solltest mal den Debugger dazu benutzen: [Artikel] Debugger: Wie verwende ich den von Visual Studio? (d.h. Haltepunkte in den Eigenschaften setzen und überprüfen, welche Werte dort gesetzt bzw. gelesen werden).
Edit:
Oder alternativ per Logging: .NET logging and tracing
Läuft evtl. der Timer noch und überschreibt immer wieder den von Hand geänderten Wert?
Dann zeige mal den Code für die Buttons.
Dies ist aber kein reines MVVM, wenn du im Codebehind Daten änderst - hier solltest du Commands benutzen, s. [Artikel] MVVM und DataBinding ("3. Commands").
Du kannst ja auch nicht das obj
aus der Children
-Collection löschen, wenn es kein direktes Child
davon ist.
Du müßtest es also direkt aus parent
löschen oder aber den gesamten Tree, d.h. parent5
aus parent6
löschen.
Schreiben die Buttons direkt in die Text
-Eigenschaft (d.h. im Codebehind) oder aber änderst du den Wert von Value
? Bei ersterem löscht du ja das Binding
darauf.
Dann überprüfe mal im Debugger, ob die Variable canvas
diese Eigenschaften gesetzt hat.
Hallo,
wie schauen denn die XAML-Codes der TextBoxen aus?
Und hat diese eine TextBox gerade den Tastatur-Fokus?
Schau mal, ob TemplatedParent das richtige Objekt ist?
Wenn das klappt, dann kannst du ja nacheinander beide abfragen - und somit normale und Template
-Objekte behandeln.
Hallo,
entweder obj
oder obj.Parent
ist null
. Überprüfe das mit dem [Artikel] Debugger: Wie verwende ich den von Visual Studio?
Das ist doch der Sinn der ComboBox.
Jedoch scheinst du nicht zu verstehen, daß die jetzt angezeigten Werte (7778888
sowie 8889999
) zwingend in der ComboBox-Liste vorhanden sein müssen, um dann überhaupt angezeigt werden zu können!
Ansonsten funktioniert es so, wie du es dir in deinem vorletzten Absatz wünscht.
Nur als Info noch: es fehlt jetzt noch die Einbindung der Commands in die ViewModels (statt der Button_Click
-Methoden im Codebehind), um vollständig MVVM-konform zu sein.
Hallo und willkommen,
entweder du übergibst der Cross Cutting Schicht (bzw. den dortigen Klassen bzw. Methoden) eine Referenz auf die DB-Klasse (bzw. als Interface), aber dann hast du eine Abhängigkeit davon drin - oder aber du erzeugst in einer übergeordneten Schicht (Business Logic) eine Klasse, welche dann die Datenspeicherungsmethoden aufruft (da sie auf beide Komponenten Zugriff hat).
So, wie BlonderHans und ich schon geschrieben haben, funktioniert es, solange die Daten der Haupttabellenspalte auch in der ComboBox.ItemSource
vorhanden sind. Und wenn noch kein Wert dort vorhanden ist (oder nicht in der Liste existiert), dann wird ein Leerstring angezeigt und der Anwender kann aus der Liste einen anderen Wert auswählen.
Was ist jetzt noch dein konkretes Problem?
Da hast du jetzt meine beiden Vorschläge vermischt.
Also entweder mit der List<T>
testen:
ItemsSource = new List<string>{"0815", "0816", "4711" },
SelectedItemBinding = new Binding("Anschnittscheibe"), // <-- der Name der Spalte in "VereinteDatentabelle"
Oder aber mit der DataView
:
dgColBox.ItemsSource = Datenabfrage.Tbl_Schleifscheiben.AsEnumerable()
.Where(x => x["Anwendung"].ToString().StartsWith("anschnitt", StringComparison.CurrentCultureIgnoreCase)).AsDataView();
DisplayMemberPath = "SAP-Nummer",
SelectedValueBinding = new Binding("Anschnittscheibe"), // <-- der Name der Spalte in "VereinteDatentabelle"
SelectedValuePath = "SAP-Nummer",
Überprüfe aber mal mit dem Debugger, ob die DataView
die richtigen Daten (und Spalten) enthält (evtl. gehen die durch die Linq-Methoden verloren).
Funktioniert denn der Code jetzt ohne MVVM (also entsprechend meines letzten Code-Auschnitts)?
Und mit MVVM würdest du ja nur das Binding im Code (d.h. im ViewModel) behandeln, der Rest wäre im XAML.