Danke @Palladin007. Die kurze Variante mittels Linq .ToDictionary kannte ich noch nicht.
Hehe, mir gings auch eher um die verschachtelten foreach und das (mich störende) if im Original-Post. Zusätzlich dazu die Tatsache, dass erstmal jede Menge Instanzen allokiert werden, welche dann später erst genutzt werden.
Ich hab's jetzt so umgebaut, dass ich im Rahmen des Projektes damit leben kann.
Meine Frage zielte also eher auf Vereinfachung des ursprünglichen Codes ab bzw. wenn ich jetzt im Nachhinein darüber nachdenke, auch darauf, wie man mit (unbekannten?) Datenmengen umgeht bei einer Art Stapelverarbeitung. Der Code soll nichts anderes machen, als für alle Benutzer im System X eine Mail zu verschicken und sie über offene Aufgaben (Tasks) benachrichtigen. Bzw. war es die Vorarbeit dafür, nämlich das Finden der entsprechenden Benutzer und dazugehörigen offenen Aufgaben.
Ok um ehrlich zu sein kann ich noch nicht alle Tipps umsetzen. Der Code stammt aus einem Projekt (WindowsService) basierend auf Dot Net 4.5.2.
Ich habe den Code jetzt umgeschrieben und poste zur besseren Übersicht mal die gesamte Klasse:
internal class PeriodicOpenTasksMailSender
{
private static Logger logger = LogManager.GetCurrentClassLogger();
internal void Run()
{
if (!HasToRun())
{
return;
}
logger.LogMethodInvoke(this);
CheckAllUsers();
SetHasRunToday();
}
private bool HasToRun()
{
MailsenderPeriod period = DomainServiceLocator.applicationPropertyService.Get_PeriodicOpenTaskAndIssueSender_Period();
DateTime? timestamp = DomainServiceLocator.applicationPropertyService.Get_PeriodicOpenTaskAndIssueSender_LastRanTimestamp();
return period.IsOverdue(timestamp);
}
private void SetHasRunToday()
{
DomainServiceLocator.applicationPropertyService.Set_PeriodicOpenTaskAndIssueSender_LastRanTimestamp();
}
private void CheckAllUsers()
{
foreach (UserTO user in DomainServiceLocator.userService.GetAllUsers())
{
CheckSingleUser(user);
}
}
private void CheckSingleUser(UserTO user)
{
List<LPATaskTO> openTasks = DomainServiceLocator.lpaService.GetAssignedOpenTasksForUserID(user.ID);
if (openTasks.IsNullOrEmpty())
{
return;
}
SendMailToUser(user, openTasks);
}
private void SendMailToUser(UserTO user, IEnumerable<LPATaskTO> openTasks)
{
MailSendingOpenTasksInfo mailsending = new MailSendingOpenTasksInfo(user, openTasks);
DomainServiceLocator.mailSender.SendSingleMail(mailsending);
}
}
Wobei
DomainServiceLocator.mailSender.SendSingleMail(mailsending);
die Mailadresse des Benutzers holt und die Informationen über die offenen "Task"s in Mail-Text umwandelt sowie die Mail sendet.
Alle Properties von DomainServiceLocator sind Interfaces. Dort gibt es z.B. IOService, DBService, MailSender, UserService und so weiter. Die einzige Stelle, wo wir in dem Projekt bisher Service-Instanzen zur Laufzeit bestimmen, ist der DBMS-Typ (MySQL / MSSQL). Ansonsten haben alle Interfaces bisher genau 1 Implementierung.
Hallo,
kannst du diese 3 Punkte noch etwas genauer ausformulieren oder einen Alternativen Code vorschlagen?
Ziel dieser Methode ist es, eine Übersicht zu bekommen, für welchen "User" welche "Task"s offen sind. Dies wird im Nachgang benötigt, da je Task eine Mail verschickt werden soll. D.h. die Task- und User-Instanzen werden anschließend noch benötigt.
Hallo,
ich habe in einem DomainLayer eines Webservices folgende Methode so ähnlich mehrfach implementiert:
private Dictionary<long, List<TaskTO>> GetOpenTasksByUserIDs()
{
Dictionary<long, List<TaskTO>> result = new Dictionary<long, List<TaskTO>>();
var activeUsers = DomainServiceLocator.userService.GetAllActiveUsers();
foreach (UserTO user in activeUsers)
{
var openTasks = DomainServiceLocator.lpaService.GetAssignedOpenTasksForUserID(user.ID);
foreach (TaskTO openTask in openTasks)
{
if (!result.ContainsKey(user.ID))
{
result.Add(user.ID, new List<TaskTO>());
}
result[user.ID].Add(openTask);
}
}
return result;
}
Ich wüsste gern, ob man den Code vereinfachen kann. Insbesondere das if-Statement im inneren foreach stört mich (inkl. Klammersetzung 4 Zeilen Code um einen Eintrag hinzuzufügen falls er noch nicht existiert).
Ich bin dankbar für eure Ideen.
Ja, es müssen auf jedem Gerät alle 15 Mio Datensätze zur Verfügung stehen ... da es lediglich um das herausfinden eines Status' geht und nicht auszumachen ist, von welcher Nummer der Status benötigt wird, muss jedes Gerät "alles wissen".
@ Hajoseb:
Bei der Synchronisation von Gerät auf PC werde ich es jetzt so machen, dass nur alle geänderten Daten übertragen werden. Das passiert dann ca. 20x je Gerät am Abend, wahrscheinlich jeweils 1-5 MB.
Anschließend werden alle so gesammelten, neuen Daten in die lokale DB auf dem PC importiert.
Am Morgen erhält dann aber jedes Gerät ein komplett neues Datenpaket. Wahrscheinlich werde ich die Daten dazu 1x exportieren (MySQL -> SQL Server Compact / *.sdf-Datei) und diese Datei dann auf jedes Gerät kopieren. Wobei sich hier nach ersten Tests schon der nächste Flaschenhals anbahnt: Die Verbindung über das Cradle (ActiveSync oder per Software über rapi.dll) ist sehr langsam. Ich habe hier einen Durchsatz von ca. 250 KB/s gemessen. Bei großen Datenmengen muss ich wohl darüber nachdenken, die SD-Karten manuell per Kartenleser zu bespielen.
@ FZelle:
Per Transaction habe ich es bisher nicht versucht. Was ich aber gemacht habe ist folgendes:*Inserts/Updates per StringBuilder in Blöcken von 1000 Stück je Kommando abgesetzt
*auf dem Desktop (MySQL) das Tabellenformat auf MyISAM umgestellt (vorher: InnoDB)
Bei einem Test mit 1 Mio Datensätzen ist die Performance jetzt um das 20-fache gestiegen.
Yep, es ist genau 1 Tabelle!
Ok, ich komm dann wohl um eine embedded-DB nicht drum rum.
Wollte es erst mit SQLite machen, aber dann habe ich noch SQL Server Compact 3.5 entdeckt und werde es jetzt damit versuchen.
Ich habe mal eben ein paar Balstungstests (1 Mio Einträge) bzgl. der Synchronisation (updates, inserts) gemacht und bin doch recht erstaunt über die (geringe) Performance. Eventuell bediene ich aber auch das PreparedSTM falsch, dazu werde ich aber einen neuen Thread starten.
Danke für eure Anregungen!
Also WLAN wird es keins geben, auch haben die Geräte keinerlei andere (dauerhafte) Konnektivität um irgendwelche WebServices abzufragen. Sie werden lediglich alle morgens einmal mit aktuellen Daten aus der DB versorgt und schieben Nachmittags alle gesammelten / geänderten Daten wieder zurück in das System (jeweils per Docking-Station / Cradle über USB).
@herbivore:
Das mit dem Dictionary habe ich schon versuch, das wird bereits ab 1 Mio Datensätzen kritisch. Dictionary<int, enum> frißt da ca. 60 MB, bei <string, enum> kommen wir sogar auf 80 MB ... bei 15 Mio Datensätzen wird das also nichts, gleich gar nicht auf einem mobilen Gerät.
Ist korrekt, neben dem Zeitpunkt der Datenänderung muss ich später auch wissen, auf welchem Gerät die Änderung vorgenommen wurde. Diese Information kann ich aber beim Import in die Datenbank herausfinden (Über Desktop-Tool, Gerät-Anschluss per ActiveSync).
Vielleicht hat ja noch jemand eine zündende Idee.
--
Noch weitere Hintergrundinformationen: Die 15 Mio Datensätze stehen bereits auf einem Desktop-System parat, sollen auf alle Geräte kopiert werden um dort ausgewählte Datensätze zu manipulieren. Anschließend wird 1x täglich synchronisiert (Abends von Geräte auf DB, morgens von DB auf Geräte).
Hallo,
ich bin mir nicht ganz sicher, ob mein Thema hier rein gehört und weiß auch nicht so recht, wonach ich suchen könnte.
Fangen wir einfach Mal an, mein Problem ist schnell geschildert: Ich habe ca. 15 Mio Zahlen (4- bis 9-stellige, beliebige Werte). Weiterhin habe ich 5 verschiedene Stati, hier mal anonym "Status1" bis "Status5" genannt. Die Daten kommen aus einer MySQL-DB und sollen auf ein mobiles Gerät (Win CE) kopiert werden. Die Datenorganisation ist mir überlassen. Weiterhin soll eine Synchronisation in beide Richtungen möglich sein, die Geräte-Anzahl wird außerdem auf ca. 20-30 steigen.
Die eigentliche Anwendung ist folgende: Auf dem Gerät wird eine Nummer gescannt / eingegeben. Anhand dieser Nummer soll der Status herausgefunden, angezeigt sowie eventuell editiert werden. Am Ende des Tages werden alle Daten von allen Geräten in die DB synchronisiert, am nächsten Morgen von der DB auf alle Geräte synchronisiert.
Meine große Frage ist nun, wie ich diese Daten möglichst einfach auf dem Gerät organisieren, auch unter dem Aspekt, dass ich oft in beide Richtungen synchronisieren muss.
Hier mein erster Ansatz:
Leere Dateien - jeder Dateiname identifiziert eine Ziffer - angenordnet nach:
\\Status1\{num1}.txt
\\Status1\{num2}.txt
...
\\Status1\{numx}.txt
\\Status2\{num1}.txt
...
\\Status5\{numn}.txt
z.B.:
\\Status1\1012.txt
\\Status1\\1179.txt
\\Status1\\124147.txt
...
\\Status1\\9941.txt
\\Status2\\11111.txt
\\Status2\\11112.txt
usw.
**:::
Nachteil: Erstellen der (15 Mio) Dateien bei DB-Export dauert ewig ; Synchronisation sehr zeitaufwendig.**
--
Zweiter Ansatz:
Für jeden Status eine Datei (welche alle zugehörigen Nummern zu diesem Status enthalten). Änderungen werden in einem anderen Verzeichnis hinterlegt:
\\in\Status1.txt
\\in\Status2.txt
...
\\in\Status5.txt
---------------------------
\\out\Status1.txt
\\out\Status2.txt
...
\\out\Status5.txt
**:::
Nachteil: Um eine Nummer zu finden, müssen im worst case alle Dateien durchsucht werden, was sehr lange dauern kann.**
--
Dritter Ansatz:
Ähnlich wie Ansatz 2, mehr Dateien, dafür bessere Vorsortierung: Die erste Ziffer einer Nummer wird als Lookup im Verzeichnis codiert:
\\in\1\Status1.txt
\\in\1\Status2.txt
..
\\in\1\Status5.txt
\\in\2\Status1.txt
\\in\9\Status5.txt
---------------------------
\\out\1\Status1.txt
\\out\1\Status2.txt
..
\\out\9\Status5.txt
**:::
Nachteil: Ich kenne die Verteilung der Nummern nicht, im worst-case beginnen sehr viele Nummern mit der gleichen Ziffer und das System geht nicht auf.**
--
Den dritten Ansatz könnte man natürlich noch verfeinern indem man anstelle der ersten Ziffer die ersten beiden oder ersten drei Ziffern in Verzeichnisse codiert.
\\in\1\0\1\Status1.txt
\\in\1\0\1\Status2.txt
..
\\in\1\1\3\Status5.txt
\\in\1\4\7\Status1.txt
...
\\in\9\9\4\Status5.txt
---------------------------
\\out\1\7\2\Status1.txt
\\out\2\0\7\Status2.txt
..
\\out\9\5\0\Status5.txt
--
Ich würde gern auf eine lokale DB auf dem Gerät verzichten (u.a. aus Zeitdruck). Was fallen euch noch für Ansätze ein, die Informationen in Dateien zu organisieren?
Hallo,
Ich habe eine Frage bzgl. des PropertyGrid: Für die Editierung div. Werte habe ich aus mehreren Gründen (Lokalisierung, Validierung, corp. design, ...) Controls gebaut.
Beispielsweise habe ich zur Editierung einer Position einer Komponenten (auf einem Zeichenfeld) ein Control gebaut (Screenshot siehe unten), welches per DropDown aus dem PropertyGrid angezeigt wird.
Ich suche nun nach einer Möglichkeit, dem Nutzer die Möglichkeit zu geben, auch ohne Öffnen des Controls den Wert zu editieren. Sprich um die Position zu ändern, soll der Nutzer
X = 15 , Y = 100
editieren können (also den Text im PropertyGrid), z.B. in
X = 15 , Y = 200
Weiß jemand, wie man die Editierung auf beide Varianten ermöglicht?
Danke für die schnelle Antwort.
Ich habe es jetzt so gelöst:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Enter)
{
this.mOkClicked = true;
this.EditorService.CloseDropDown();
return true;
}
return false;
}
Das ganze habe ich in dem Control das beim PropertyGrid aufklappt gemacht, d.h. egal wo ich bin, wann immer Enter gedrückt wird, soll das Control geschlossen werden und der Status gemerkt werden, dass der Nutzer "auf ok geklickt" hat ( = Enter drücken ).
Geht ihr mit dem Code konform?
Hallo,
ich habe bereits die Forensuche sowie Google abgegrast, aber leider keine passende Antwort auf meine Frage gefunden. Um es euch einfach zu machen, habe ich soeben ein Minimalbeispiel aus meinem Projekt extrahiert (Code vereinfacht, auf 1 Problem reduziert).
Es geht um folgendes: In einem Projekt verwende ich das PropertyGrid um Objekt-Eigenschaften zu manipulieren. Aus div. Gründen (Lokalisierung, corp. design, Validierung, ...) habe ich eigene Controls für die Editierung von einigen Eigenschaften geschrieben. Nehmen wir beispielsweise die Position eines Elements. Da diese von meinem Zeichenfeld begrenzt ist und nicht kleiner als (0, 0) werden darf, kann ich durch die Editierung mittels eigenem Control die eingebene Position sehr einfach validieren (ich weiß, dass es auch über das PropertyGrid selbst geht).
Mein eigentliches Problem liegt darin, dass ich es nicht schaffe, die Enter-Taste als Bestätigung für die Änderung von Werten abzufangen. Es scheint so, dass diese automatisch dafür verwendet wird, das per DropDown angezeigte Control zu schließen.
Der Screenshot unten zeigt mein Control zur Editierung einer Position. Für das erste NumericUpDown (X-Koordinate) habe ich bereits folgendes versucht:
public LocationControl()
{
InitializeComponent();
this.numX.KeyDown += new KeyEventHandler(numX_KeyDown);
}
void numX_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
this.btnAccept.PerformClick();
}
}
Das ganze verhält sich wie folgt:*:::
*:::
*:::
Ich würde gern auf die Enter-Taste als solche reagieren. Gibt es die Möglichkeit, diese nicht automatisch zum Schließend des DropDown-Controls zu verwenden?
Auch PreviewKeyDown bringt keinen Erfolg. Beim Drücken der Enter-Taste kommt das Event gar nicht erst beim Control an.
Vielleicht kann man das Control auch anders anzeigen? Ich mache es derzeit mittels
editorService.DropDownControl(control);
.
Hinweis: Ich habe das Beispiel als Code (VS 2008 Projekt) und kompiliert vorliegen ; sämtlicher Code zur Validierung, Lokalisierung etc. wurde entfernt. Ich hänge es gern als Anhang in einen weiteren Post.
@ sp00k:
Super, der Einzeiler
protected override System.Drawing.Point ScrollToControl(Control activeControl)
{
return DisplayRectangle.Location;
}
erfüllt endlich die gewünschte Funktionalität, genau so etwas habe ich gesucht!!
Besten Dank!
Kennt noch jemand anderes eine Möglichkeit, das Problem zu umgehen?
Kann man die Scrollbalken irgendwie anders implementieren / nutzen?
Hallo Birne,
genau den Workaround bin ich nun auch erstmal gegangen. Leider äußert sich das bei mir allerdings so, dass die Scrollbalken danach nicht immer korrekt positioniert sind. Der Ausschnitt stimmt, aber die Scrollbalken scrollen teilweise nicht zum korrekten Offset.
Wenn ich es mit einer kurzen Verzögerung mache (Thread.Sleep() im Millisekundenbereich), habe ich ein unschönes Flackern, aber die Scrollbalken haben die korrekte Position.
Ich hoffe, es gibt noch eine bessre Lösung.
Anhang: Code-Example (Minimalbeispiel) zum experimentieren..
Hallo,
ich habe mein Problem anhand eines Minimalbeispiels nachgebaut: Ich habe ein UserControl, welchen Zweck auch immer das erfüllt (meins soll zum Zeichnen von irgendwelchen Objekten dienen). Dieses UserControl ist auf einem Panel untergebracht, bei dem das AutoScroll-Property auf true gesetzt ist.
Mein Problem äußert sich nun wie folgt: Ich selektiere mein UserControl, arbeite damit und verschiebe in diesem Zusammenhang die Scrollbalken des Panels, auf dem das UserControl untergebracht ist. Wechsle ich nun mit dem Fokus aus dem UserControl z.B. in eine Textbox außerhalb des Panels und kehre anschließend zurück, so wird der Scrollstatus nicht erhalten.
Das ganze resultiert darin, dass ich bei jedem Verlassen des UserControls und zurückkehren wieder ganz oben bin, also erneut nach unten scrollen muss. Drei Bilder sollen das Problem verdeutlichen, siehe Anhang.
Kann mir jemand erklären, woran das liegt und wie ich das springen der Scrollbalken bei Fokuswechsel verhindern kann?
Hallo,
nachdem ich nun ca. 30 min bei Google und hier im Forum gesucht aber nichts passendes gefunden habe, werde ich nun doch posten und hoffe nicht wieder mit einer "bitte Suche verwenden" Antwort abgeblockt zu werden.
Mein Problem ist schnell beschrieben: Ich benutze das PropertyGrid in einer WindowsForms-Anwendung um wahlweise eines oder mehrere Objekte zu editieren. Wähle ich nun ein Objekt an, so sollen alle mit Browsable(true) markierten Properties geändert werden dürfen.
Selektiere ich hingegen mehrere Elemente (des gleichen Typs), so binde ich sie als Array an das PropertyGrid und kann sie auch wunderbar bearbeiten. Ich möchte nun aber gern Einschränkungen machen, was die Editierung bei MultipleSelect angeht. So darf beispielsweise das Property "Name" meiner Objekte nicht gleich sein, über das PropertyGrid kann ich dies nach dem Binden mehrerer Objekte jedoch ändern.
Frage: Wie kann ich eine Einschränkung vornehmen, bei der ich Properties freigebe wenn nur 1 Objekt an das PropertyGrid gebunden ist, zur Editierung aber sperre wenn mehrere Objekte gebunden sind?
Beispiel:
public class MyElement
{
// Dieses Property soll nur editierbar sein, wenn 1 einziges
// Objekt an das PropertyGrid gebunden ist
[Browsable(true)]
public string Name { get; set; }
[Browsable(true)]
public int AnyValue { get; set; }
}
@ DaMoe80:
Das gefällt mir doch schon ganz gut! Ich kann die Vorteile von Enums nutzen und brauche keinen (speziellen) Code für die Lokalisierung zu schreiben.
Einzig verbleibendes Problem: Die penible Pflege der Resource-Datei 😉
@ herbivore:
Wenn ich einen WebService aufrufe, den Aufruf entsprechend absichere, reicht doch für den Benutzer eine einfache Meldung "Achtung, beim Webaufruf ist etwas schief gelaufen". Sicherlich könnte man hier eine eigene Exception-Klasse erstellen und die wirklich aufgetretene Exception als InnerException ablegen, aber mir geht es in diesem Fall rein um die Verwaltung von lokalisierten Fehlermeldungen, vielleicht gibt es da ja einen besseren Ansatz.
@ Mr Evil:
Die Lösung mittels xml-Datei ist ja im Prinzip die gleiche, als wenn ich die Resourcen-Dateien von Visual Studio nehme.
Fakt ist doch, dass ich bei beiden Lösungen sehr schnell auf die Nase fallen kann, wenn eine neue Nachricht dazukommt und ich in irgendeiner Sprache vergesse, diese hinzuzufügen. Dort habe ich dann keine Chance, das zur Compilzeit herauszufinden (außer natürlich pre- oder post-Buildscript).
Ich hätte gern eine Lösung bei der ich auch sicher gehen kann, dass wirklich alles übersetzt wurde.
Als Anmerkung ... in Java kann ich folgendes machen:
public class Errors {
public enum Error {
Unknown(1, "??", "??"),
WEBEXCEPTION(100, "Fehler bei Zugriff auf Internetverbindung", "Error during internet connection"),
WEBTIMEOUT(101, "Zeitüberschreitung der Internetverbindung", "Timeout error of internet connection"),
;
private int value;
private String de_De;
private String en_GB;
private Error(int value, String de_De, String en_GB) {
this.value = value;
this.de_De = de_De;
this.en_GB = en_GB;
}
public String getDe_De() {
return de_De;
}
public String getEn_GB() {
return en_GB;
}
public int getValue() {
return value;
}
public void setDe_De(String de_De) {
this.de_De = de_De;
}
public void setEn_GB(String en_GB) {
this.en_GB = en_GB;
}
public void setValue(int value) {
this.value = value;
}
}
private static Error findByValue(int value) {
for (final Error code : Error.values()) {
if (value == code.value) {
return code;
}
}
return null;
}
public static String getErrorCode(int value, String localeValue) {
final int locale = Locale.getLocale(localeValue);
switch (locale) {
default:
case Locale.LOCALE_DE_DE: {
final Error code = findByValue(value);
return code == null ? "???" : code.getDe_De();
}
case Locale.LOCALE_EN_GB: {
final Error code = findByValue(value);
return code == null ? "???" : code.getEn_GB();
}
}
}
}
So etwas in der Art hätte ich gern
Hallo,
ich bin auf der Suche nach einer geeigneten Struktur für Fehlercodes. Bisher habe ich das wie folgt gehandhabt:
public enum ErrorCodes
{
WEBEXCEPTION = 100,
WEBTIMEOUT = 101,
WEBURINOTFOUND = 102,
THREADEXCEPTION = 200,
FILENOTFOUND = 300,
DIRNOTFOUND = 301,
DIRNOTACCESSABLE = 303,
...
}
Nun brauche ich derzeit passend zu den jeweiligen Fehlercodes lokalisierte Fehlertexte. Ein Ansatz wäre folgender:
public string GetText(ErrorCodes code)
{
switch (code)
{
case ErrorCodes.WEBEXCEPTION:
return Properties.Resources.ERR_WEBEXCEPTION;
case ErrorCodes.WEBTIMEOUT:
return Properties.Resources.ERR_WEBTIMEOUT;
....
}
}
Die lokalisierten Texte liegen also in Resourcendateien, was ich sehr aufwändig in der Wartung finde (Texte können in Sprachen vergessen werden ohne dass man es merkt).
Ein anderer Ansatz wäre dieser:
public string GetText(ErrorCodes code)
{
string lang = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.ToLower();
switch (code)
{
case ErrorCodes.WEBEXCEPTION:
if (lang.Equals("de")) return "Unbekannter Fehler bei ...";
if (lang.Equals("en")) return "Unknown error during ...";
case ErrorCodes.WEBTIMEOUT:
if (lang.Equals("de")) return "Zeitüberschreitung der Internetverbindung";
if (lang.Equals("en")) return "Timeout error of internet connection");
....
}
}
Auch hier kann ich div. Texte vergessen.
Ich würde bei der Definition der Fehlercodes gern bei einem enum bleiben (da ich hier sichergehen kann, dass Fehlercodes nur einmal vergeben werden und der Zugriff sehr einfach von überall möglich ist).
Ich habe nun daran gedacht, das enum durch ein struct zu ersetzen und dort die entsprechenden Informationen abzulegen, was den Vorteil hätte, dass keine Informationen fehlen können und sämtliche Texte in einer Datei stehen. Mein Ansatz:
public struct ErrorCode
{
private int code;
private string langDE;
private string langEN;
public int Code { get { return this.code; } }
public string LangDE { get { return this.langDE; } }
public string LangEN { get { return this.LangEN; } }
public ErrorCode(int pCode, string pLangDE, string pLangEN)
{
this.code = pCode;
this.langDE = pLangDE;
this.langEN = pLangEN;
}
}
public static class ErrorCodes
{
public static ErrorCode WEBSERVICE_EXC
{
get { return new ErrorCode(100, "Fehler bei ..", "Error during .."); }
}
public static ErrorCode THREAD_EXC
{
get { return new ErrorCode(200, "Fehler bei ...", "Error during ..."); }
}
}
Nachteil hier: Ich kann (aus Versehen) Fehlercodes doppelt vergeben. Man stelle sich ein sehr lange Liste von Fehlern vor, wo ich durchaus die Zahl 300 mehrfach vergeben kann.
Kennt jemand eine elegantere Lösung zur Verwaltung von Fehlercodes und lokalisierten Fehlertexten?
Da es sich teilweise um Events von Timern oder Hardware-Ereignisse handelt, ist dies nicht möglich. Die Sprache meiner Oberfläche kann sich zudem jederzeit ändern.
Da hast du natürlich auch wieder Recht!
Mein Fehler ist vermutlich, dass ich meine Ressourcen zu früh hole, und zwar in den Hintergrundthreads. Vermutlich sollte ich darauf achten, sämtliche Ressourcen erst im Hauptthread (nach Invoke) abzurufen und von dort zu setzen.
Ich werde mal prüfen, ob das den gewünschten Effekt hervorruft.
Thx so far 😃
Ja, das ist mir mittlerweile klar, aber wie realisiere ich es, dass ich alle Threads benachrichtige? Ich habe es bisher nur geschafft, mit Thread.CurrentThread... die Culture zu setzen, weiß aber nicht, wie ich die anderen Threads "benachrichtige".
@ thomas.at:
Wie reichst du die Sprachänderung von der GUI an deinen Backgroundworker weiter?
Ich habe gerade ein ähnliches Problem mit mehreren Threads (und div. Timer, die Aktionen auslösen). Wenn ich in der GUI die Sprache ändere, so betrifft das nur den einen Thread. Mir fehlt eine Möglichkeit, für alle laufenden Threads die Sprache zu ändern.
Hallo,
ich benötige eine Lösung um einen PHP-WebService (incl. wsdl) mit NET (C#) zu konsumieren. Leider finde ich nicht ein einziges, vollständiges Beispiel zu diesem Thema. Ich schaffe es, einen NET - WebService mit C# zu konsumieren oder aber einen PHP-WebService mit PHP zu konsumieren. Weiterhin gelingt es mir, einen Java-WebService (Apache/Axis2) mit PHP und C# zu konsumieren.
Im VS 08 kann ich die URL (.php?wsdl oder .wsdl) angeben, der Service wird auch gefunden, entsprechende Klassen (Client-Klasse) incl. Methoden generiert. Aber immer, wenn ich auf den Service zugreifen will, gibt es Fehlermeldungen wie:
Der Server hat keine sinnvolle Antwort gegeben; dies kann durch einen nicht übereinstimmenden Vertrag, ein vorzeitiges Herunterfahren der Sitzung oder durch einen internen Serverfehler verursacht sein.
Hat jemand ein funktionierendes Beispiel für die Kommunikation von PHP und NET?
Mit den 3 von dir genannten Stichwörtern findet man die Beiträge schnell. Ich poste mal einen Sample-Code von mir:
private void loadACDSeeImage()
{
tryToLoadIcon(@"C:\Programme\Gemeinsame Dateien\ACD Systems\PlugIns2\IDE_ACDStd.apl", 2);
}
private void tryToLoadIcon(String pPath, int pIndex)
{
// HKEY_CLASSES_ROOT
// DEFAULTICON
uint iconNum = ExtractIconEx(
pPath, // filepath
-1, // start
null, // large icon out
null, // small icon out
0); // number of icons
if (iconNum > 0)
{
this.labelIconNum.Text = iconNum.ToString() + " Icon(s)";
if (pIndex < iconNum)
{
IntPtr[] largeIcons = new IntPtr[1];
IntPtr[] smallIcons = new IntPtr[1];
ExtractIconEx(
pPath, // filepath
pIndex, // start (index)
largeIcons, // large icon out
smallIcons, // small icon out
1); // number of icons
this.pictureBoxLarge.Image = Bitmap.FromHicon(largeIcons[0]);
this.pictureBoxSmall.Image = Bitmap.FromHicon(smallIcons[0]);
DestroyIcon(largeIcons[0]);
DestroyIcon(smallIcons[0]);
}
else
{
this.labelIconNum.Text = "wrong icon index";
}
}
else
{
this.labelIconNum.Text = "no icons found";
}
}
Danke für die Tipps, damit findet sich natürlich was 🙂
Der Thead hier könnte somit gelöscht werden..
Hallo,
ich versuche vergebens, das Icon aus einer Datei zu extrahieren, mit dem diese Datei verbunden ist.
Beispiel:
MP3-Dateien sind auf dem aktuellen Rechner mit Winamp verknüpft, also haben alle MP3s ein Winamp-Symbol.
Ich such nach einer Möglichkeit, die mir für die Dateiendung .mp3 (oder eine konkrete .mp3-Datei) das entsprechende Icon/Bild liefert, so wie es im Explorer angezeigt wird.
Habe leider mit der Forensuche nichts finden können 🙁
Grüße,
Mario
Warum rufst du dann nicht das 2. Fenster mit ShowDialog() auf?
Das macht in dem Anwendungsfall leider keinen Sinn.
Das ist die Implementierung von Hide:
public void Hide() { this.Visible = false; }
Das habe ich mir schon gedacht, war mir nur nicht sicher
Wie wärs denn, wenn du das 2. Fenster einfach im Closed-Event aufrufst...
Auch das ließe sich in der Anwendung z.Z. nicht realisieren, da die Form, die ausgeblendet werden soll, zu diesem Zeitpunkt nicht geschlossen werden darf. Sie soll wirklich nur unsichtbar für den Benutzer sein.
Ich verstehe es nicht, wie bei einem sichtbaren Fenster die .visible-Property auf false sein kann.
Ich habe ein kleines Verständnisproblem was Windows Forms mit C# angeht.
Bei einer Anwendung sorgt eine Form dafür, dass bei einem Button-Click eine andere Form angezeigt wird und die eigene Form versteckt werden soll.
this.Hide();
Mainform mf = new Mainform();
mf.Show();
Wenn ich das so geschrieben habe, kam es bei hoher CPU-Auslastung teilweise dazu, dass das zu verbergende Fenster sichtbar blieb, also nicht ausgeblendet wurde. Das hatte zur Folge, dass der Anwender beide Fenster bedienen kann, was nicht sein darf.
Spaßeshalber habe ich folgenden Code probiert:
this.Hide();
Application.DoEvents();
while(this.visible)
{
this.Hide();
Application.DoEvents();
}
Mainform mf = new Mainform();
/* debug */
mf.Show();
An der Stelle /* debug */ habe ich im Visual Studio einen Breakpoint gesetzt. Die Property .visible des zu versteckenden Fensters war nachweislich "false", obwohl das Fenster noch sichtbar war.
Folgender Code scheint das Problem zu lösen:
this.visible = false;
Mainform mf = new Mainform();
mf.Show();
Ich wüsste nun gern, warum die visilbe-Property von einem Fenster false sein kann, wenn es noch sichtbar ist und der Benutzer es bedienen kann.
Als zweites stellt sich mir die Frage, was genau der Unterschied zwischen .Hide() und .visible = false; ist.
Hallo,
ich habe folgendes Problem:
Meine UpateManagerGui.dll bietet die Möglichkeit, ein Update für ein Programm suchen zu lassen. Um dieses Update zu starten, habe ich dort eine Klasse "SilentUpdate "von ApplicationContext vererbt, damit das Update ohne Gui durchläuft.
Nun will ich aus einer anderen (Forms-)Anwendung heraus während der Laufzeit nach einem Update suchen.
Bisher habe ich versucht, das "SilentUpdate" folgendermaßen zu starten:
Application.Run(new UpateManagerGui.SilentUpdate(..Parameter..));
Das hat folgende Auswirkung: Die aktuelle Gui wird geschlossen, dafür die Anwendung mit dem SilentUpdate gestartet. Ist dies beendet, beendet sich die gesamte Anwendung.
Wie kann ich das "SilentUpdate" (vererbt von ApplicationContext da ohne Gui) aus meiner Forms-Anwendung heraus starten ohne dass sich meine Applikation schließt?
Info:
Zusätzlich zum "SilentUpdate" bietet meine UpdateManagerGui.dll auch eine Möglichkeit, das Update mit Gui laufen zu lassen. Dafür gibt es die Klasse "UpdateForm", vererbt von Form. Diese kann ich problemlos starten mittels:
new UpateManagerGui.UpdateForm(..Parameter..).ShowDialog();
Diese startet dann separat, ohne dass sich die eigentliche Anwendung schließt. Ist ja klar, ich erzeuge lediglich eine neue Form und zeige diese an.
Kewl darauf bin ich natürlich nicht gekommen. Im Gegenteil: Ich hab extra keinen Menüshortcut mit V gemacht und STRG + V nicht zu blockieren g
Danke, gute Idee 🙂
Ich benutze eine Richtextbox, in der nur Text eingefügt werden darf.
Im Kontextmenü rufe ich meine Methode:
private void pasteTextFromClipboard()
{
String text = Clipboard.GetText();
if (String.IsNullOrEmpty(text))
{
setStatusText(3000, "Kein Text in der Zwischenablage vorhanden!");
return;
}
richTextNotes.Paste();
dialogNewLoadSave.changed = true;
}
auf.
Wenn der Benutzer nun STRG + V drückt um etwas einzufügen, so will ich das kontrollieren. Mein Ansatz:
private void richTextNotes_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.V && e.Control)
{
pasteTextFromClipboard();
}
return;
}
Wie kann in der Methode hier:
private void richTextNotes_KeyDown(object sender, KeyEventArgs e)
{
// <<<
}
nun das eigentliche einfügen (Im Falle dass es ein Bild ist) unterbinden?
Es soll also kein Bild einfügbar sein!
Hypercam 2.0
Ich glaub Version 1.x ist mittlerweile Freeware.
( Eigentlich macht das Teil gestochen scharfe Videos, aber ich hab mir irgendwie meine Codecs zerballert )
Worauf genau möchtest du zugreifen? Auf eine Eigenschaft des TabelLayouts oder auf eine Eigenschaft der Komponenten die im TableLayout sind?
Ich glaube das war TableLayout.Rows[] bzw. TableLayout.Columns[] oder so ähnlich.
Edit:
Ok, so geht's offensichtlich nicht. Berechtigte Frage. Ich weiß gar nicht mehr, wie ich das damals gemacht habe. Bin dann aber auf Splitcontainer umgestiegen.
Ich habe eine kleine Anwendung geschrieben, in der ich einen vertikalen SplitContainer verwende. Beim Beenden des Programmes wird die Breite des Splitters (splitContainer.SplitterDistance) gespeichert:
if (mySettings.saveWindowPosition)
{
mySettings.splitterDistance = splitContainer.SplitterDistance;
MessageBox.Show("say good bye with " + splitContainer.SplitterDistance); // Ausgabe: xx pixel
mySettings.Save();
}
// Aufruf bei FormClosing()
Beim nächsten Programmstart wird die Einstellung wieder geladen, um das Programm wie gewohnt vorzufinden:
if (mySettings.saveWindowPosition)
{
splitContainer.SplitterDistance = mySettings.splitterDistance;
MessageBox.Show("say hello with " + mySettings.splitterDistance); // Ausgabe: xx + 20 pixel ???
}
// Aufruf bei MainForm() <- Konstruktur
Kurios: Die Einstellung ist nach jedem Start ca. 7-10 Pixel breiter.
Ich verstehe nicht, wo der Unterschied herkommt 🙁
Ein kleines Video zur Veranschauung befindet sich im Anhang!
Hallo!
Ich finde einfach nicht die richtige Stelle. Ich brauche von einer Richtextbox die Zeile, in der sich aktuell der Cursor befindet.
Die Cursorposition kann man mit richTextBox.Cursor auslesen, aber ich finde keine Möglihckeit, die aktuelle Zeile rauszubekommen.
Die Zeilen an sich bekomme ich mit richTextBox.Lines, und dann?
Helft mir mal auf die Sprünge 😉
Danke!
Thema Suche:
Habe natürlich nicht nach "Inputbox" gesucht. Unter "Query", "Input", "Dialog" etc. war nix zu finden 🙁
Hey!
Gibt es unter C# eine Möglichkeit, einen Input- oder QueryDialog aufpoppen zu lassen, um eine Benutzereingabe abzufragen?
Falls nicht: Hat jemand einen solchen Dialog vielleicht schon realisiert und ist er irgendwo als Klasse verfügbar?
MfG Mario
Besten Dank !!! 😮)
Super Antwort, kurz und knackig, alles erklärt und gleich mit Beispiel und Lösung! Wenn nur alle Antworten so toll wären 😉
Hi !!
Ich schreibe grad ein paar alte (Delphi-) Programme in C# neu, um mit der Sprache ein wenig vertraut zu werden. Nun haperts daran, die Nachkommastellen eines float- oder double-Wertes als String auszugeben:
private double returnTimeMin(int size, int rate)
{
return ( (size * 1024 / rate) / 60);
}
private float returnTimeHour(int size, int rate)
{
return ( (size * 1024 / rate) / (60 * 60) );
}
Ausgeben tu ich das ganze wie folgt:
double min = returnTimeHour(size, rate);
double hour = returnTimeMin(size, rate);
textBoxTimeMin.Text = min.ToString("N2");
textBoxTimeHour.Text = String.Concat(hour.ToString("N3"));
(size und rate sind int-Werte)
Woran liegt es, dass in den Textboxen nur die Vorkommastellen stehen? Die Anzahl der Nachkommastellen übernimmt er, die sind aber immer 0.
Hi Folks 8)
Ich habe eine Form mit einer ImageList sowie einem Treeview-Objekt. Die Treeview-Komponente will ich als File-Browser verwenden. Dazu hab ich mir in den Ressources Images angelegt (Folder, File, etc.)
Image folderIcon = new Bitmap(Properties.Resources.cp_icon_world5);
Image htmlIcon = new Bitmap(Properties.Resources.cp_icon_notepen6);
folgenden Code habe ich bereits im Konstruktor sowie Load-Ereignis der Form versucht:
treeView.ImageList = imageList1;
treeView.ImageList.Images.Add(folderIcon);
treeView.ImageList.Images.Add(htmlIcon);
System.Drawing.Size size = new Size(18, 18);
treeView.ImageList.ImageSize = size;
richTextBox1.AppendText("tada");
Wenn ich den Code im Konstruktor oder Load-Ereignis ausführe, werden die Bilder nicht angezeigt. Führe ich den gleichen Code nun "später" (z.B. einmalig bei einem Button-Click oder bei Form.Layout) aus, so erscheinen die Images in den TreeNodes.
Dort füge ich sie wie folgt zu (beim Füllen der TreeView):
node.ImageIndex = 1;
node..SelectedImageIndex = 2;
Woran liegt es, dass die Images nicht erscheinen, wenn ich den Code bei Form.Load oder direkt im Konstruktor aufrufe, sondern nur wenn er "später" ausgeführt wird?
Hallo!
Ich bin neu hier, habe die Suche nicht übersehen, aber leider auch nichts passendes gefunden.
Mein Problem: Ich bastel einen Editor, in dem ich eine Treeview zum Navigieren auf der Festplatte brauche. Ich benutze Visual Studio .NET 2005. Ich habe versucht, eine solche (siehe Anhang) Ansicht mit dem Element treeview zu realisieren. Allerdings ist das recht mühsam, da man den Pfad manuell angeben muss, die Struktur (Ordner + Files) einlesen muss und Icons fehlen ebenfalls noch. Außerdem geschieht das Navigieren nicht automatisch.
Meine Frage nun: Gibt es bei Visual Studio eine andere Komponente, die das besser kann? Oder hat jemand sowas vielleicht schon implementiert?
MfG Mario