Laden...
Avatar #avatar-4122.png
LaTino myCSharp.de - Experte
Softwareentwickler Thüringen Dabei seit 03.04.2006 3.003 Beiträge
Benutzerbeschreibung

Forenbeiträge von LaTino Ingesamt 3.003 Beiträge

30.08.2017 - 07:11 Uhr

Bei Rakuten wäre ich vorsichtig.

Ich auch, aber mehr aus so einem unwohlen Bauchgefühl heraus. Hast du da Konkreteres?

LaTino

29.08.2017 - 14:32 Uhr

@Latino - woher willst du das denn wissen? Sobald in dem Unternehmen mehr als 1 Mio Umsatz erwirtschaftet wird (oder eher uninteressant 250 PC's eingesetzt werden) wäre die Firma ja nach Lizenzbedingung ein Unternehmen und entsprechend verpflichtet zu kaufen.

Nein, verstehst du richtig. Ich hatte wohl mehr reingelesen, als drin stand, und es so verstanden, dass die Firma aus zwei Entwicklern besteht, die Plugins entwickeln, und das war's. Steht natürlich so nicht da 😃.

@pinki: mit meinem sehr begrenzten Wissen: da es in Deutschland ein paar gerichtliche Entscheidungen in der Richtung gab, ist es möglich, Lizenzen zu erwerben und anderen zur Nutzung zu überlassen, auch wenn die anderen die ursprünglichen Lizenzbedingungen nicht erfüllen. Man kann sich also ein paar tausend Lizenzen in einem sehr günstigen Modell besorgen und die mit geringerem Aufschlag gegen eine Gebühr anderen zur Nutzung überlassen (daher: Überlassungsgebühr). Eigentümer der Lizenz bleibt der Erwerber.

Vermutlich würde sich jemand, der eine juristische Ausbildung genossen hat, über meine Erklärung scheckig lachen, aber das ist in etwa, was da passiert. Soweit ich weiß, hat man ggü der vollen Lizenz eben ein paar Nachteile, bezahlt dafür aber auch weniger. Wer das genau wissen will, sollte auf jeden Fall jemanden fragen, der sich damit auskennt.

LaTino

29.08.2017 - 13:45 Uhr

Man muss schon genauer hinschaun. Die 180 Euro sind eine Überlassungsgebühr, kein Kaufpreis.

Im übrigen könnt ihr die Community Edition nehmen, die kostet genau gar nix und darf in dem von dir beschriebenen Szenario eingesetzt werden.

LaTino

28.08.2017 - 15:55 Uhr

var firstTabPage = tabControl1.TabPages[0];
var secondTabPage = tabControl1.TabPages[1];

28.08.2017 - 12:28 Uhr

@mfe: Gegen XSS war das nicht gedacht wenn ich mich recht entsinne...

Nein. Wer Schadcode auf eine Webseite schleusen kann, kriegt auch einen Server aufgesetzt, der mit scheinbar korrektem CORS-Header antwortet.

LaTino

27.08.2017 - 11:27 Uhr

war am tablet geschrieben, daher die von th69 zu Recht bemängelten Stellen...sry.

LaTino

26.08.2017 - 15:33 Uhr

Hallo MarsStein,
vielen Dank für deine Antwort - das bringt mich jetzt eine ganze Ecke weiter!

Zunächstmal: das mit dem Single Responsibility-Prinzip saß mir die ganze Zeit schon im Nacken! Ich hatte genau diese Frage hier schon mal gepostet, bezüglich dessen, ob ich eine Form für 2 Aufgaben nutzen kann, wenn sie von der GUI her genau gleich daherkommt, lediglich einmal für das Editieren und einmal für das Neuerstellen benutzt wird.

Als Denkanstoß:


interface IModifySchoolClassPresenter
{
     public string AcceptButtonText { get; }
     public string InfoText { get; }
}
abstract class SchoolClassPresenterBase : INotifyPropertyChanged
{
     public string AcceptButtonText { get; protected set;}
     public string InfoText { get; protected set;}

    //INPC implementieren und hierfür anwenden:
     public string ShortName { get; set; }
     public string Leader { get; set; }
     public string PartnerClass { get; set; }

    protected abstract void OnSubmit();
}

class EditSchoolClassPresenter : SchoolClassPresenterBase
{
    public EditSchoolClassPresenter() 
    {
        AcceptButtonText = "Bearbeiten";
        Infotext = "Bearbeiten Sie die Klasse und klicken Sie dann auf \"Bearbeiten\"";
    }
}

class CreateSchoolClassPresenter : SchoolClassPresenterBase
{
    public CreateSchoolClassPresenter() 
    {
        AcceptButtonText = "Erstellen";
        Infotext = "Füllen Sie die Felder aus und bestätigen Sie die neue Klasse";
    }
}

//MainForm

private void CreateOrEdit()
{
   var presenter = create 
        ? new CreateSchoolClassPresenter() 
        : new EditSchoolClassPresenter(selectedSchoolClass);

    var dialog = new CreateOrEditDialog(presenter);
    if(DialogResult.Ok = dialog.ShowDialog()) presenter.OnSubmit();
}

Nur ganz grob, das wird hinten und vorn noch nicht funktionieren. Der Punkt ist einfach: abhängig vom Anwendungsfall übergibt man einfach einen leicht unterschiedlichen Presenter und kann dieselbe Form wieder verwenden. (Du könntest mit einem dritten Presenter dieselbe Form benutzen, um eine eventuelle Löschung noch einmal überprüfen zu lassen, zum Beispiel)

Das geht aber nur, wenn die Form nichts von ihrer Bedeutung weiß: Single Responsibility (nämlich, Daten darstellen und eine User-Aktion entgegennehmen). DRY hat damit gar nichts zu tun, und die zwei Prinzipien widersprechen sich auch nicht.

Die Datenbindungen kannst du dir übrigens im Designer zusammenklicken. Insgesamt dürfte sehr, sehr wenig wirkliche Programmierarbeit nötig sein.

LaTino

26.08.2017 - 00:58 Uhr

Vorab: bitte enums nicht Enumerable nennen, auch wenn es das bedeutet. Enumerable ist in .net wieder was anderes.

Zum zweiten: du überlässt der Form (classNewOrEdit) der Kontrolle über ihren Zustand. Der ist aber Anwendungslogik: wird gerade editiert oder neu erstellt, und wenn editiert, was wird editiert?

Trenn das sauber auf ( [Artikel] Drei-Schichten-Architektur ) und dein Problem erledigt sich ganz von alleine.

LaTino

24.08.2017 - 12:34 Uhr

Ist bei mir Schritt eins.

Ich würde dann aber lieber die richtige Regex nehmen und ohne replace arbeiten:


matchStrings = Regex.Matches(example, @"<.+?>|.+?").OfType<Match>().Select(p => p.Value);

LaTino

24.08.2017 - 11:06 Uhr
  1. falsches Forum 😃


//Pseudocode
1. Trenne Zeile auf in Bestandteile, die in <> stehen, und alle anderen Bestandteile
2. Erstelle eine Liste aus diesen Bestandteilen
3. für jedes Listenelement
3.1. steht es in <> ? 
3.1.1 ja - endet der Wert auf d? 
3.1.1.1 ja - nimm den Bestandteil vor dem d, interpretiere ihn dezimal, und rechne in Hex um
3.1.1.2 nein - interpretiere den Wert anhand einer Tabelle von Steuerzeichen (ESC = 0x1B, CR = 0x0D)
3.1.2 nein - interpretiere den Wert als ASCII und suche den hex-Wert
3.2 packe das Ergebnis in eine Ergebnisliste vom Typ byte[]
4. Gib das Byte-Array als Ergebnis aus.

LaTino

24.08.2017 - 07:39 Uhr

Du bist mit MeasureString schon auf der richtigen Fährte. Berechne die zu erwartende gerenderte Länge inkl. Tabs und umbrich[1] den Text so lange, bis die Länge nicht mehr zu lang ist.

Anders wird's nichts, weil die Breite eines Tabs - ebenso wie die Breite der Schrift - von der Schriftart abhängig ist.

LaTino
[1] Partizip II von umbrechen i.S.v. "Text umbrechen" ist übrigens "umbrochen", nicht "umgebrochen" - letzteres würde man mit einem Feld machen. Deutsches Sprach, schweres Sprach 😉.

23.08.2017 - 13:56 Uhr

Du missverstehst da was. Der IIS unterscheidet bei den Compression-Options zwischen static files und dynamic content. Das sind zwei paar Schuhe, die friedlich beide nebeneinander laufen können.

LaTino

23.08.2017 - 07:43 Uhr

Vielleicht bei der Deserialisierung dem entsprechenden Feld einen leeren Wert zuweisen wenn in der XML Datei kein Wert vorhanden ist ?

Andersrum wird ein Schuh draus. Du könntest im Schema zum XML festlegen, dass die Werte nicht null (== vorhanden) sein müssen.

LaTino

18.08.2017 - 14:51 Uhr

Wenn du einen Überblick über alle Instanzen eines Objekts haben willst, musst du dir eine Liste aller Instanzen eines Objekts anlegen. Eigentlich logisch 😉.


class Example
{
    private List<Stopwatch> _stopwatches = new List<Stopwatch>();
    

    private Stopwatch StartNewStopwatch()
    {
        var result = Stopwatch.StartNew();
        _stopwatches.Add(result);
        return result;
    }

    private IEnumerable<TimeSpan> GetAllElapsed() => _stopwatches.Select(p => p.Elapsed);
}

Im Prinzip braucht man aber nie mehr als eine Stopuhr. Was du tust, ist jemand, der zu einem 100-Meter-Lauf, einem 200-Meter-Lauf und einem 400-Meter-Lauf drei verschiedne Stoppuhren mitbringt.

LaTino

16.08.2017 - 16:07 Uhr

Wie emuuu sagt: das Zählen, wie oft die Methode aufgerufen wird, gehört nicht in die deklarierende Klasse, sondern in den aufrufenden Kontext.

Kurz gesagt, MaWo80: zähl dort hoch, wo die Methode aufgerufen wird, und nicht in der Methode.

LaTino

(Und da wir in .NET und nicht in TurboPascal sind, würd' ich es per Event machen...)


class Example
{
    public void ExampleMethod()
    {
        OnExampleMethodCalled();
        DoStuff();
    }

    private void DoStuff() => Console.WriteLine("Hello, world.");
    public event EventHandler ExampleMethodCalled;
    private void OnExampleMethodCalled() => ExampleMethodCalled?.Invoke(this, EventArgs.Empty);
}

class Program
{
    public static void Main()
    {
        int counter = 0;

        var example = new Example();
        example.ExampleMethodCalled += (s, e) => counter++;

        while (counter < 10) example.ExampleMethod();
    }
}


15.08.2017 - 07:35 Uhr

Testweise einige Services auf den Pi3 (win-arm) umgezogen...funktioniert super. Langsam wird's brauchbarer 😃.

LaTino

10.08.2017 - 12:32 Uhr

Das erklärt noch nicht, wozu du ein 24Bit-Bild brauchst. Was hindert dich denn, mit Graustufen zu arbeiten, anstatt das umständlich umzurechnen?

LaTino

10.08.2017 - 08:50 Uhr

Niemals Felder als public kennzeichnen, das ist ganz schlechter Stil. Ich sehe hier auch gar keine Notwendigkeit, sie überhaupt öffentlich zugreifbar zu machen.


private double _xMin;
private double _xMax;

[Artikel] C#: Richtlinien für die Namensvergabe beachten, du tust uns beim Lesen, und dir selbst, wenn du in einem halben Jahr das Projekt nochmal durchschaust, einen großen Gefallen.

Zweitens: der Codebehind einer Form ist ausschließlich zur Implementierung von Oberflächenlogik gedacht. Man könnte zwar bei dem von dir geposteten Code argumentieren, dass das alles tatsächlich noch UI ist, aber ich habe da so meine Zweifel, dass das auch beim kompletten Code so ist.

LaTino

09.08.2017 - 14:31 Uhr

Die zitierte Stelle ist nicht die Stelle, wo der Fehler verursacht wird, sondern nur die Stelle, wo er ausgegeben wird. Grab also mal ein bisschen in der js-Console, dann solltest du den Verursacher finden.

LaTino

04.08.2017 - 09:18 Uhr

Du missverstehst. Das sind nicht zwei Varianten, wie man dein Problem verstehen könnte, sondern zwei Lösungen zu deinem Problem.

XPath lernen
Alle Elemente ermitteln
Element per Pfad auswählen

Das müsste dann alles sein, was du brauchst.

LaTino

04.08.2017 - 07:53 Uhr

Ich nehm mal willkürlich ein paar Kritikpunkte heraus.

Zum einen ist diese exzessive Benutzung von Codebehind tödlich. Code-Behind dient - im besten Fall -
zur Steuerung von UI-Logik: wenn eine Taste in Textbox xy gedrückt wird, ändere deren Hintergrundfarbe auf rot. Solche oder ähnliche Sachen.
Du allerdings hast da fröhlich deine Anwendungslogik verteilt. Auch in WinForms sollte aber nach Möglichkeit ein Schichtenmodell verwendet werden: [Artikel] Drei-Schichten-Architektur

Das zieht gleich Kritikpunkt zwei nach sich. Lerne, was Databinding ist, und benutze es. Du sparst dir schätzungsweise 50% deines Spaghetticodes. Kein Mensch füllt Daten einer Oberfläche von Hand, wenn er seine geistige Gesundheit länger behalten möchte.

Soweit Kritik zur Struktur. Zu Inhalt und Form:

a) [Artikel] C#: Richtlinien für die Namensvergabe
b) du baust öfter mal eine Zeichenkette zusammen und führst dafür teilweise 3-4 temporäre Hilfsvariablen ein. Dabei benutzt du auch noch diese grässliche Angewohnheit aus der Java-Welt, Zeichenketten mit Hilfe von leeren Strings zu verketten. Vielleicht sehe nur ich das so, aber ich finde diese Notation schon mehr als hässlich.

Schau dir mal string.Format oder (ab Visual Studio 2017) Zeichenketteninterpolation an:

Du:


string appdata = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string pdir = appdata + "" + "\\Opera Software\\Opera Stable\\Profile";
bool exists = System.IO.Directory.Exists(pdir);

if (exists)

Die Variable maindir wird nie benutzt. (Übrigens: Namensvergabe. Wofür steht pDir? Clean Code, Leute.)

string.format:


var profileDir = string.Format(@"{0}\Opera Software\Opera Stable\Profile", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
if (Directory.Exists(profileDir))

string interpolation:


var profileDir = $@"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\Opera Software\Opera Stable\Profile";

if (Directory.Exists(profileDir))

Lass den Code reden. if(Directory.Exists(directoryName)) ist viel deutlicher als if(exists). Schieb nur in Fällen, wo es der Übersicht dient, Werte in zusätzliche Variable.

c) Deine catches machen IMMER ein Console.Write(). Wenn du Ausnahmen nicht behandeln möchtest, dann fang sie auch nicht. Und wieso Console.Write in einem WinForms-Program irgendwie nicht so sinnvoll ist, sollte auf der Hand liegen. Die einzige Stelle, wo du nicht Console.Write in einem catch machst, ist ein leerer catch, und der ist noch übler.

d) alle Code-Behind-Methoden geben dir einen Sender mit. Es ist eine Unart, die zu ignorieren und stattdessen auf benannten Controls zu arbeiten: immerhin kannst du das nur weil du als Programmierer in dem Moment weisst, dass dies die richtigen Controls sind. Andere Programmierer - auch du selbst, in der Zukunft - haben dieses Wissen nicht und laufen unnötig in Schwierigkeiten, deinen Code nachzuvollziehen.

e)


if (rbStable.Checked == true)

Nein. [Tipp] Anfängerhinweis == true / == false

Die Prozess-Starterei sieht auch seltsam aus - hab' ich mir jetzt aber nicht näher angeschaut, vielleicht möchte das jemand anderes tun.

Alles in allem für den ersten Versuch nicht so übel, wie mein Posting klingt. Dennoch stark verbesserungswürdig. Ich müsste mich sehr täuschen, wenn man dieselbe Funktion nicht mit <100 Zeilen Code hinkriegen könnte.

Grüße,

LaTino

04.08.2017 - 07:20 Uhr

Das leere Protokoll gibt also die Umformung vor, nach der die Daten in das Endprodukt umgeformt werden[1]. Was ich machen würde, wäre, mit einer xsl-Transformation das leere Protokoll in ein XSL umzuwandeln, und das dann auf die ursprünglichen Daten loszulassen. Aber vermutlich nur, um zu sehen, ob das geht.

Die pragmatischere Variante ist, alle Elemente im leeren Protokoll durchzugehen, und mit Hilfe ihres XPaths den Wert aus den Input-Daten auszulesen und im leeren Protkoll einzutragen. Am Ende hat man dann ein Dokument in der Form des leeren Protokolls, mit den Daten aus dem Input.

Das sind so die zwei Möglichkeiten, die mir einfallen.

LaTino
[1] klingt irgendwie, als hätte der Erfinder des Vorgangs XML in der Abendschule gelernt. Nichts gegen Abendschulen.

03.08.2017 - 15:00 Uhr

Es kann Leider kein XSL benutzt werden. Nicht weil ich dies nicht Realisiert hätte, sondern da der Anwender Immer eine XML Datei erstellt. Gibt es noch Vorschläge zur Lösung nur über XML?

Sorry, aber die Antwort ergibt nicht so richtig Sinn. Ein XSL ist eine Vorschrift, mit deren Hilfe man aus vorliegenden XML-Daten bestimmte Werte extrahiert und in einer anderen Form zusammenstellt. Man kann also auch aus vorliegenden XML-Daten (Messdaten) eine neue XML-Datei (Protokoll) erzeugen.

Das klingt schon genau so, als sei es dein Anwendungsfall.

LaTino

02.08.2017 - 07:43 Uhr

Was MrSparkle meint:
Implementierungen von GetHashCode() sollten für die gesamte Lebenszeit eines Objekts dasselbe Ergebnis liefern, unabhängig von seinem Inhalt. Du hast die Methode quasi missbraucht, damit eine andere Mechanik (das Binding) schnell funktioniert. Falsche Herangehensweise.

LaTino

02.08.2017 - 07:32 Uhr

@LaTino: Die Grauwerte werden sicherlich durch deinen Image Viewer erzeugt. Bei mir sind die Pixel entweder schwarz, weiß, rot, grün, blau, cyan oder gelb 😃

Whoops, da hast du sowas von Recht. Auch wegen des Schwellwerts (dass man keinen angeben kann, wenn man einfach 'ne 1Bit-Palette setzt), weshalb der vollständige Code eben noch die Transformation mittels ColorMatrix vorweg hat. Ich benutz das für die Optimierung von erzeugten QR-Barcodes, die als 32Bit-PNG mit Skalierung hier ankommen.

LaTino

31.07.2017 - 14:41 Uhr

Dass du eine Exception bekommst könnte jetzt daran liegen, dass du IMMER eine Exception wirfst. Nur so ein Verdacht.


 private void ExtMethode_OnNewData(object sender, byte[] data)
 {
    lbl_DevTime.Text = System.Text.Encoding.UTF8.GetString(data);
    throw new NotImplementedException(); //bee-doo bee-doo bee-doo!
}

Ansonsten würde ich meinen Zeigefinger ein wenig erheben und damit auf das Wort "Databinding" zeigen. Soll heissen: mach es doch bitte gleich richtig.

LaTino

31.07.2017 - 07:50 Uhr

Der Code, den du gepostet hast, produziert nur schwarz oder weiß. Das Bild, das du gepostet hast, enthält (mal von den Artefakten abgesehen, die dich stören) auch Graustufen, also Informationen, die in den Bilddaten nicht vorkommen. Dein Problem liegt also nicht an den Bilddaten, sondern an der Art und Weise, wie du sie darstellst (nämlich mit weichgezeichneten Übergängen: das geht mit ausschließlich schwarz und weiß nicht).

Der Punkt, an dem es bei dir hängt, ist der hier:


newBitmap.Clone(new RectangleF(0.0f, 0.0f, bm.Width, bm.Height), PixelFormat.Format1bppIndexed);

, dh du solltest die benutzte Palette auf die Farben einschränken, die du darzustellen gedenkst.

Ich persönlich finde ja den Umgang mit Colormatrix schöner als den Marshal-Voodoo, den du da veranstaltest; ich würde auch kaum Performanceunterschiede erwarten, aber das musst du wissen.

LaTino

28.07.2017 - 07:37 Uhr

Also entweder entfernt WinForms jetzt schon automatisch Personen aus dem Vordergrund eines Bildes - vermutlich eine neue Datenschutzinitiative! - oder was eigentlich passiert, ist: das Bild ist zu groß für die PictureBox und wird nicht skaliert, und deshalb ist nur ein Teil des Bildes zu sehen, und DER zeigt "Gestrüpp".

Wenn es das ist - wir können da mangels Beschreibung nur raten - spiel mal mit der "SizeMode"-Eigenschaft deiner PictureBox rum. "StretchImage" sollte tun, was du möchtest. WENN ich richtig geraten habe und das dein Problem ist.

LaTino

28.07.2017 - 07:32 Uhr

Was zum Teufel treibst du da eigentlich?

Ist dir klar, dass du das Dokument zweimal öffnest und mit verschiedenen Methoden beackerst, wovon die eine einfach mal copy&paste ist, ohne verstanden zu haben, was da passiert?

Um dein Problem zu lösen, solltest du dich erst einmal auf eine Methode festlegen. Dann sehen wir weiter.

LaTino

20.07.2017 - 10:47 Uhr

PS: Du weißt, dass WebForms nicht mehr weiterentwickelt wird und bereits seit 3 Jahren abgekündigt ist?

Nochmal dazu: ich kann irgendwie nirgends etwas finden, dass deine Aussage bestätigen würde. 👶

Das ist eine hässliche Marotte von Microsoft. Produkte werden still und heimlich beerdigt. Hat auch 'ne Weile gebraucht, um mitzubekommen, dass Silverlight tot ist.

LaTino

20.07.2017 - 08:22 Uhr

Bin nicht hundertpro sicher, dass die Antwort zur Frage passt, aber:

  • setz die Eigenschaft "AutoScroll" der Form auf true.
  • füg ein Panel / LayoutPanel hinzu (da gibt's verschiedene, welches, muss du selbst wissen)
  • setz "AutoSize" des Panels auf false.
  • setz die Eigenschaft "Location" des neuen Panels auf "0;0"
  • setz die Größe des Panels auf deine gewünschte Größe (Eigenschaft "Size")
  • Setz die Property "Locked" des Panels auf True

Einen guten Überblick verschaffst du dir mit Ansicht -> weitere Fenster -> Dokumentengliederung.

Fertig. Du hast jetzt ein großes Panel in einem Form, das so eingestellt ist, dass es Scrollbalken zeigt, wenn der Inhalt größer ist als die eigene Größe.

LaTino

19.07.2017 - 14:47 Uhr

LaTino, bitte spar dir die Kommentare:

Dunning-Kruger usw. Behalt es einfach für dich, interessiert mich wirklich nicht was du denkst, ist mir auch zu dumm und zu kindisch weiter drauf einzugehen. Ich komm schon ganz gut klar 😉

Du hast bestimmt schon einmal
>>
besucht, nicht wahr?

erstes Posting oben, da du es aber vermutlich gar nicht gelesen hast...

Ja, so etwas dachte ich mir. Lass mich dir helfen.

  1. Besuche www.nuget.org
  2. Gib oben in das Suchfeld ein: "Reactive Extensions"
  3. Klick den ersten Link "System.Threading.Tasks.Extensions" an.
  4. Klicke unten links "Download" an.
  5. Ändere die Erweiterung der heruntergeladenen Datei in ".zip".
  6. Entpacke die Datei.
  7. Profit.

Glückwunsch. Bist du sicher, dass diese Computer-Sache das Richtige für dich ist?

LaTino
EDIT: hängt an. (rx-main für 3.5)

19.07.2017 - 11:47 Uhr

Wow, also wirklich wow. Die Nonchalance, mit der du fundiertes und angebrachte Hinweise zur Seite wischst, ist schon eine Liga für sich. Vielleicht zur Einordnung: ich glaube du bist hier im Thread der einzige, der das Programmieren als Hobby betreibt. Ist schön zu sehen, dass du dennoch überzeugt bist, keine Hinweise beachten zu müssen. Dunning-Kruger, nehme ich an.

Die Lösung deiner Situation ist schon mehrfach erwähnt worden: nimm einfach Lehrbücher, die zu dem passen, was du lernst. Gebrauchte Ausgaben zu VS 2008 und .net 3.5 gibt's für einen Appel und ein Ei.

Es geht also um diese Windowsoberflächen dabei. Das bedeutet schon mal für Consolen C# keine Probleme - gut. Und mit diesem Satz: über einen anderen Thread läuft und so den Hauptthread deiner Anwendung nicht blockiert. Meinst du damit das beim starten von Windows-Fenster Anwenden da im Grunde 2 Programme ablaufen, einmal die Console im Hintergrund und das Fenster eigenständig?
Und mit "schlicht einfriert" meinst du CPU überlastet?

Du verstehst da etwas, was Taipi88 nicht geschrieben hat. Es geht bei Tasks nicht um eine Oberfläche. Das ist nur ein Gebiet, wo die Dinger sehr brauchbar sind, ein Beispiel, das Taipi88 gegeben hat. Und nein, ein Thread ist kein Programm. (Sondern das hier.) Einfrieren bedeutet einfrieren. Eine Benutzerschnittstelle, die mit einer langwierigen BErechnung beschäftigt ist und deshalb keine Eingaben entgegennimmt. Das hat mit der CPU nichts zu tun.

Danke MarsStein für deine Antwort. Diese Reactive Extensions für 3.5 kennst du da ein download-link? Und diese nuget console (die ich nicht zum starten bekomme), brauch ich die dann überhaupt?

Du hast bestimmt schon einmal http://www.nuget.org besucht, nicht wahr?

LaTino

19.07.2017 - 07:41 Uhr

Im Grunde dürfte mir 2008 zum lernen locker ausreichen.

Natürlich. Und zwar lernst du dann etwas, das vor fast genau 10 Jahren aktuell war. Das ist in der IT ein sehr, sehr langer Zeitraum.

Konsequenterweise solltest du deine Lehrbücher wegwerfen und dir welche von 2007 schießen, denn die passen dann auch zu deiner Entwicklungsumgebung. Du hast dir einen Ford T gekauft und beschwerst dich, das keins der Handbücher erwähnt, wie man die Anlasser-Handkurbel bedient.

Es gibt gute Gründe, noch VS 2008 zu verwenden. Weil man's billig auf Ebay bekommen hat, ist keiner, zumal dir die Community Editions bekannt sind.

To add insult to injury: Du verwendest ein Betriebssystem, das offiziell seit drei Jahren (!!!) nicht mehr supportet wird. Nostalgie ist ja schön und gut, aber das überschreitet auch im privaten Bereich die Grenze zur Fahrlässigkeit.

Kopfschüttelnd,

LaTino

18.07.2017 - 15:53 Uhr

Interessant, offenbar habe ich, was TDD angeht, einen Tunnelblick.

@palin:

Arbeitgeber: "Wie lange brauchst du für die und die Anforderung?"
Entwickler: "4 Stunden für die Implementierung und UnitTests."
Arbeitgeber: "Und nur für die Implementierung?"

Entwickler: "4 Stunden".

Bei Arbeitsanweisung dieselbe schriftlich festhalten. Das ist nach meiner Auffassung eine direkte Anweisung, auf die grundlegenden Qualitätssicherungsmaßnahmen zu verzichten. Also absichern, damit mangelnde Qualität dann nicht dir zugeschoben wird. Und mittelfristig anderen Job suchen.

(Das ist genau das, was ich ganz oben meinte. Solche Arbeitgeber sind besser heute als morgen aus dem Geschäft. Wenn man auf die Qualität seiner Produkte einen Haufen setzen möchte, kann man immer noch am BER anfangen. grrr)

@Wasabi: das ist bei der breiten Masse der Recruiter leider noch nicht angekommen. Die Suche nach einem "full stack" developer sollte mittlerweile ein rotes Warnschild sein: hier wird ein Mädchen für alles gesucht, weil man eigentlich keine richtige Stellenbeschreibung hat.

LaTino

18.07.2017 - 14:37 Uhr

Und wenn das Argument id null ist oder gar keine Id darstellen kann, dann gibt es eine ArgumentNullException bzw. ArgumentException. Auch das dokumentiert man (logisch) im <exception> Abschnitt und schreibt dazu auch UnitTests.

Eigentlich ist das genau anders herum, denn der Test existiert vor der Methode. Die Testcases definieren das Verhalten der Methode, und die Dokumentation hält das so fest, dass die Information auch außerhalb des Codes verfügbar ist/sein könnte, wenn man wollte.

LaTino

18.07.2017 - 11:25 Uhr

Aber disposed das auch die entfernten Controls?
Weil sonst hätte man ja leicht ein schönes Memory-Leak.

Nein tut's nicht und ja, hätte man. MSDN hat extra ne dicke fette Warnung: Control.ControlCollection.Clear-Methode

Also Obacht 😉.

LaTino

18.07.2017 - 11:21 Uhr

...und wenn die Regressionstests durchlaufen, hat man darüber hinaus keine bereits vorhandenen Funktionen in ihrer Arbeitsweise ungewollt verändert. Die ganze Testerei NACH den Unit Tests darf je nach Komplexität auch ein paar Tage in Anspruch nehmen oder kann weggelassen werden.
Das ist eine Entscheidung, die im QM festgehalten werden muss.

18.07.2017 - 08:44 Uhr

Die Google-Ergebnisse für "Unturned plugin" sind eigentlich ziemlich umfangreich. Allerdings kann ich zugegebenermaßen nicht gut beurteilen, wie gut die Treffer sind. Ein bisschen herumgeklicke brachte mich jedenfalls zu einem Tutorial für ein Plugin für RocketMod(?) für Unturned und ein weiteres Tutorial, wie man das dann zu installieren hat. Das müsste doch reichen, nicht?

LaTino

18.07.2017 - 08:29 Uhr

Ich habe lange überlegt, ob ich mich hier beteiligen sollte, oder nicht. Die Feindseligkeit gegenüber anders arbeitenden ist schon bedrückend. Aber lassen wir das, führt zu nix.

Du missverstehst. Die Feindseligkeiten sind nicht den Leuten gegenüber, die so arbeiten, sondern den Leuten gegenüber, denen ihre Entwickler und ihr eigenes Produkt so egal sind, dass sie nicht einmal vernünftige Arbeitsgrundlagen schaffen. Mein erster Arbeitsplatz als angestellter Entwickler entsprach ziemlich genau deiner Beschreibung: kleines Unternehmen (~5 Entwickler) unstrukturierter Code, VSS als Quellcodeverwaltung (immerhin). Allerdings war das 1999, und das Konzept Quellcodeverwaltung war mir, der ich davor lange selbstständig war, völlig unbekannt. Aus heutiger Sicht würde ich diese Umstände als Bestrafung ansehen. Die Werkzeuge haben sich weiterentwickelt, die Methoden haben sich weiterentwickelt, der Begriff Softwarequalität ist ein anderer. Softwareentwicklung ist wesentlich effizienter geworden, und DevOps ist ein weiterer Baustein im Werkzeugkasten, um die Effizienz zu erhöhen. Ein Lebewesen, das nicht mehr zuckt, ist genauso tot wie das Unternehmen, das sich nicht mehr weiter entwickelt[1]. Sich im Rahmen der Unternehmenstrategie mit Werkzeugen zu befassen, die die Arbeitsleistung und -qualität der Entwickler erhöhen, sollte selbstverständlich sein. Nebenbei macht man den Entwicklern das Leben leichter, und auch das ist nach meiner Meinung eine Aufgabe der Unternehmensführung, wenn sie gute Entwickler halten und noch bessere anlocken wollen.

Mir ist da z.B. völlig schleierhaft, welchen Vorteil ich aus einem über Nacht erzeugten Kompilat haben soll. Ist es tatsächlich inzwischen üblich, das man am Code Änderungen vornimmt und diese einfach nur eincheckt, ohne das ganze wenigstens einmal durch den Compiler zu schubsen ? Wenn ja, bleibe ich Oldschool...

Habt ihr nur ein Projekt? Bestehen keine Abhängigkeiten zwischen euren Projekten? Könnte ihr alle eure Produkte lokal innerhalb von 2 Minuten kompilieren? Wie lange laufen eure Unit Tests? Auf welchen Softwareständen laufen Regressionstests?

Selbst meine Hobbyprojekte zu Hause sind über die Jahre so miteinander verflochten (gemeinsame Bibliotheken) und so komplex, dass ich zugegeben den Überblick verloren habe, welche Änderung in welchen Projekten Auswirkungen haben könnte. Und ich baue sicher nicht von Hand alle Projekte jedesmal durch, das kann auch ein trainierter Affe oder gleich ein Buildsystem (das nebenbei nicht nur die Projekte erstellt, sondern auch gleich die Unit Tests laufen lässt). Und da reden wir von maximal 5 Stunden die Woche, die ich dran sitze. Mir kann keiner erzählen, dass das selbst bei kleinen und kleinsten Unternehmen besser ist.

Bei größeren Unternehmen sind natürlich die Dimensionen ganz anders. Wenn mein Team was eincheckt, sind potenziell immer rund 100 andere Entwickler von den Änderungen betroffen. Man kann zwar im eigenen Projekt sicherstellen, dass es kompiliert, aber nicht in abhängigen Projekten (wenn man nicht mal weiss, welche Projekte davon abhängen). Um ganz sicher zu gehen, müsste man also alle Projektmappen zumindest der wichtigsten Produkte durchkompilieren. Das dauert auf dem Buildserver ~30 Minuten, bei mir lokal gern mal 45 Minuten. Ich kann also entweder meine Entwickler pro Checkin 45 Minuten Däumchen drehen lassen, oder ich nutze ein Buildsystem. Das baut nebenbei noch alle Branches zB für einen Release oder ein spezielles Projekt mit.

Der Sinn daran, zu jeder Zeit ein funktionierendes Produkt zu haben, das auf einem beinah aktuellen Stand der Entwicklung ist, leuchtet dir nicht ein? Sagen wir, es ist bei euch wie bei uns damals: die Regressionstests bestehen aus dem Chef, der in der fertigen Software wild herumklickt und versucht, die neu eingebauten Features irgendwie zum Absturz zu bringen. (wir haben das gefürchtet. Irgendwie hat er immer einen Fehler gefunden.) Dann stellt sich die Frage: auf welchem Softwarestand probiert er das eigentlich? Findet er gerade Fehler, die eigentlich schon behoben sind?
Unter anderem dafür ist eine Software, von der immer ein funktionierendes Setup auf einem definierten Softwarestand existiert, unbezahlbar. Mal abgesehen davon, dass der Kunde neue Funktionen viel schneller erhält, weil das Zusammenstellen eines Setups kein eher seltener Vorgang ist, den ein Senior-Entwickler mit seinen Erfahrungen von Hand begleitet, sondern weil eine Setuperstellung ein alltäglicher Vorgang ist. Nimm dir den letzten Build, lass ihn durch die QS laufen, wenn du sowas hast, und raus damit an den Kunden. Bei kleinen Systemen hat man zwischen dem Checkin und dem fertigen Setup nicht mal eine Stunde. Bei großen fällt immer noch jeden Tag ein Setup aus dem Server (wohlgemerkt, da sind schon alle Unit Tests gelaufen).

Und das hat auch absolut gar nichts mit mobile apps oder Webentwicklung zu tun. Unser Hauptprodukt ist - neben Infrastruktursoftware - eine monolithische Desktop-Anwendung, sehr altmodisch vom Look&Feel, für einen sehr altmodischen Kundenkreis. Ich würde mich mit Händen und Füßen wehren, wenn man für diese Anwendung die Buildserver abschalten würde.

Wozu also Releases, ergo wozu ein Release-System ?

Äh, was? Wenn ihr euren Kunden keine Updates/Patches/Hotfixes/neue Versionen zur Verfügung stellt, dann gestatte die Frage: was macht ihr eigentlich, wenn niemand je ein Produkt von euch bekommt?

Ja, die Umsetzung von modernen Softwareentwicklungs-Prozessen (DevOps) ist eine Investition. Kostet Zeit, Geld, Ressourcen. Gar keine Frage. Aber es lohnt sich, und zwar nach meiner Erfahrung immer.

Aber - gute Nachricht - man muss nicht alles auf einmal umsetzen. Man kann klein anfangen und immer weiter dazu bauen. Das geht los mit einer vernünftigen Quellcodeverwaltung (da zähle ich VSS nicht mehr dazu), geht dann weiter mit einem rudimentären Buildsystem. Hat man das, kann man die Testdurchdringung deutlich erhöhen - guter Zeitpunkt, über TDD nachzudenken. Soweit mag es für kleine Unternehmen schon reichen, die Investition ist überschaubar[2] - aber man muss, gerade was die Testabdeckung angeht, möglicherweise seine Entwickler weiterbilden.

Wenn man das selbst trotzdem nicht stemmen kann: es gibt Dienstleister, die einem dabei helfen. Ja, klar kostet das was, wie gesagt: es ist eine Investition in die Zukunft.

Lies bitte einmal diesen Artikel aus dem Jahre 2000: das war quasi state-of-the-art zu dieser Zeit und ist weitgehend immer noch gültig. Und der Autor begründet das auch viel besser, als ich das könnte (Passend dazu diesen 11 Jahre alten Thread.)

LaTino

[1] in irgendwelchen Marktnischen kann man trotzdem noch jahrelang existieren, schon klar. Aber ein Unternehmen, egal wie groß oder klein, das sich nicht permanent zu verbessern versucht, ist auf lange Sicht Geschichte.
[2] Das ist das, was ich privat bei mir zu Hause gemacht habe. Zum einen, weil es nötig war, zum anderen, weil ich was darüber lernen wollte.

17.07.2017 - 13:06 Uhr

Kannst du bitte noch Verteilung der benutzten Build/RM-Systeme aufschlüsseln? Bin einigermaßen erschüttert, dass die so wenig verbreitet sind. Nach meiner Erfahrung ist das der Faktor, der den Teams das nötige Selbstvertrauen und die Sicherheit bietet, um auch mal Mut beim Entwickeln haben zu können.

Was die Delphi-Adepten angeht: Gott, wie süß, v.a. auch die Überzeugung, dass Delphi eine Rolle spielen würde. Ich stelle lieber jemanden ein, der zwei Jahre Rust/Haskell/Go programmiert hat, als jemanden, der 15 Jahre Delphi gemacht hat. Bei dem weiß ich wenigstens, dass er sich für Neues interessiert, anstatt ein totes Pferd zu reiten.

LaTino

14.07.2017 - 08:44 Uhr

Habe außerdem keine Ahnung, wo ich diese ServiceBehaviorAttribute finden kann...mfg

Ach, komm schon. Erster Treffer Google-Suche nach "ServiceBehaviorAttribute": ServiceBehaviorAttribute-Klasse

Da ist unten sogar ein Codebeispiel.

LaTino

13.07.2017 - 13:42 Uhr

Es gibt außerdem noch Spezifikationen, die bestimmte Bytefolgen vereinbaren. Ich mach mal ein einfaches Beispiel:

Tag: 0xDBFAFA
Tagformat: Tag, Länge, Inhalt
ByteArray: AC 44 5F 84 DB FA FA 01 CC A0 CB 64 7A

--> Tag beginnt bei Index 4, Länge ist 01 --> gesuchter Inhalt ist also 0xCC (0d204)

Du kannst also einfach lesen, sobald ein bekanntes Tag kommt, wertest du es aus und liest immer weiter. Der deutsche Standard für eTickets basiert auf so etwas ähnlichem.

LaTino
EDIT: musst natürlich sicherstellen, dass die Daten von einer Art sind, dass das Tag nicht durch Zufall durch die Daten gebildet wird.

12.07.2017 - 12:47 Uhr

Das ist XML. Da ist genau dieses Feature schon bei der Definition mit eingebaut (wie mfe schon richtig gesagt hat). Wenn du Daten als XML hast, solltest du auch die Vorteile von XML benutzen.


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
    <xsl:template match="/">
TYPE "CZI_CalcDec"
VERSION : 0.1
//TITLE = CZI_CalcDec
//
// UDT-Struct for the data handling 
//
//EDITOR:     Robin Newitsch
   STRUCT
        <xsl:apply-templates select="/Section/Member" />
   END_STRUCT;
END_TYPE
	</xsl:template>

    <xsl:template match="Member[not(@Datatype='Struct')]">
        <xsl:value-of select="@Name" /> : <xsl:value-of select="@Datatype" />;
    </xsl:template>

    
    <xsl:template match="Member[@Datatype='Struct']">
        <xsl:value-of select="@Name" /> : Struct
        <xsl:apply-templates select="Member" />
        END_STRUCT
	</xsl:template>
</xsl:stylesheet>

...und fertig. Serialisierung/Deserialisierung ist hier einfach das falsche Tool.

LaTino

10.07.2017 - 08:00 Uhr

Auch wenn's von Taipi gut gemeint war: kopier bitte niemals Code, den du nicht verstehst. Nicht hier im Forum, und auch sonst nicht.

Alles Wissen, was du benötigst, steckt in der allerersten Antwort, wenn du dir nur mal die Mühe machst, den Artikel vollständig durchzuarbeiten (und damit ist nicht nur lesen gemeint).

LaTino

10.07.2017 - 07:54 Uhr

Die Antwort ist in deiner Frage enthalten:


dass ich den Tagesüberlauf nicht mit bekomme und anstatt (ca) 3h eben 20h berechnet werden

Klar kriegst du den mit: wenn der Abstand größer als ein halber Tag ist, dann ist der Abstand mit "Tagesüberlauf" geringer und das gewünschte Ergebnis.

Zieh die beiden voneinander ab, wenn das Ergebnis > 12 ist, ziehst du noch einmal 24 ab.


var diff = (first.TimeOfDay - second.TimeOfDay).TotalHours;
var result = 3600 * (diff > 12 ? 24-diff : diff);

LaTino

07.07.2017 - 11:12 Uhr

Du hast Recht, der Umstieg ist alles andere als einfach. Am Anfang taumelt man von Stolperfalle zu Stolperfalle, bis man an den Punkt kommt, wo man "f*** it, ich mache einfach weiter Windows Forms" sagen möchte. Für mich war das die Stelle, an der ich mir ein Buch (eigentlich mehrere) gekauft hab und ein paar Wochenenden mit Schmökern verbracht habe. Definitiv kein verschwendetes Geld, wenn ich bedenke, wieviele graue Haare mir das erspart hat.

https://www.amazon.de/Developing-Windows-10-Applications-C/dp/1522894918

Würde ich als komplettestes Buch zum Thema ansehen.

Viel Erfolg,

LaTino

06.07.2017 - 11:06 Uhr

Mach einen Wrapper für dein Application-Objekt und übergib den stattdessen.

Oh, und [Artikel] C#: Richtlinien für die Namensvergabe

LaTino

03.07.2017 - 07:56 Uhr

Lässt sich anhand der Bruchstücke ganz schwer einschätzen, aber eventuell hilft dir so ein Konstrukt hier:


//init
var conditionalSelector = new ConditionalSelector<Action<MyClass>, Func<int,int,int,bool>>();
conditionalSelector.Register(obj => obj.ListA(new A()).For((a, b, c) => a > b && c % a > 1);

//später irgendwo:
foreach(var action in conditionalSelector.Where(a, b, c)
    action(obj)

Der ConditionalSelector ist eine Klasse, die beliebige Paare von Delegaten speichert (den auszuführenden Code und eine Bedingung, unter der er auszuführen ist. So etwas kann helfen, wenn man sehr viele strukturell ähnliche Aktionen zu je einer oder wenigen Zeilen Code für verschiedene Bedingungen ausführen will. Ist natürlich bei der Implementierung des ConditionalSelectors erst einmal etwas mehr Aufwand (dafür mMn wesentlich aufgeräumterer Code).

Insgesamt ist das auch nicht weniger Code dann, aber ich teile herbivores Auffassung nicht, dass nur reduzierte Codemenge es leichter macht, Code zu verstehen.

LaTino