Laden...

Forenbeiträge von wcseller Ingesamt 196 Beiträge

06.03.2017 - 08:13 Uhr

Neben den schon beschriebenen Lösungen wäre auch folgendes denkbar (ist aber eher aus der Sparte 'quick and Dirty' 😉 ):

for (int i = 0; i < myLabel.Length; i++)
{
      myLabel[i] = this.Controls["lbl"+(i+1).ToString())]; 
}
06.03.2017 - 08:03 Uhr

Pack den relevanten Teil in einen try-catch Block. Kombiniert mit einer ForEach-Schleife probierts Du dann die alternativen Adressen einfach durch, bis es entweder geklappt hat oder eben das Ende der 'Adressliste' erreicht ist.

Deine Datei 'link.txt' sollte dann mehrere Adressen enthalten (einfech eine Adresse pro Zeile) und z.B. via String.Split ermittelst Du dann aus dieser Liste der der Adressen die einzelnen Zeilen, die jweiels eine Adresse darstellen.

etwa so:

string address1 = "http://seite.de/link.txt"; //Datei enthält nur eine ZielIP
string[] ips = new StreamReader(webClient.OpenRead(address1)).ReadToEnd().Split(new char[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntrys);

foreach (string ip in ips)
{
      try {
           //Das ist eine weitere Textdatei mit dem 2. Teil der Adresse:
           string address2 = "http://" + ip + "/nextcloud/index.php/s/xxxxxxxx/download";  
           string str7 = webClient.DownloadString(address2);

          //Ziel Datei
          string address3 = "http://" + ip + str7;
          string fileName = str4;
          webClient.DownloadFile(address3, fileName); 
          // hier prüfen, ob die Datei i.O. ist....
          break; }
     catch {
          // hier ggf. loggen, dass die ADresse nicht funktioniert hat...}
}

Um das ganze Konstrukt herum gehört natürlich noch eine vernünftige Fehlerprüfung - auch der Download der Datei link.txt kann ja scheitern...

03.03.2017 - 08:03 Uhr

Eine einzige Icon-Datei erstellen, die alle benötigten Größen enthält. Das ist schon der ganze Zauber...

01.03.2017 - 14:56 Uhr

Schon mal im Ereignisprotokoll von Windows nachgeschaut, ob sich dort ggf. detailliertere Informationen zum Fehler finden?

28.02.2017 - 08:52 Uhr

Mit meinem Hinweis, dass Du falsch liegst bezog ich mich primär auf Deine Aussage, dass das Icon eines Forms 16/256 Farben haben sollte/darf - das ist falsch.

Für sog. HighDPI Bildschirme sollte das Icon ausserdem auch höhere Auflösungen als 16/32 unterstützen.

28.02.2017 - 08:42 Uhr

Versuchs mal so:

Dauertest[0].RuntimeThread = new System.Threading.Thread(() => Runtime(0));
Dauertest[0].RuntimeThread.Start();

Die GUI-Aktualkisierungen dann in etwa so:

BeginInvoke(new Action(() =>
{
     Error_Anzeige.Text = Convert.ToString(exp.Message);
     Error_Anzeige.Refresh();
}));
28.02.2017 - 08:32 Uhr

Anscheinend ist das wirklich ein Bug von Windows 7. Bei meiner Recherche im Internet bin ich darauf gestoßen. Ich habe das Problem jetzt so gelöst, dass ich die 256er Icons aus dem Hauptfenster entfernt und durch 32er Icons ersetzt habe. Damit past das im Audio-Mixer von Windows 7, der die Icons leider nicht skaliert. Das Programmsymbol hat dennoch eine 256er Auflösung, damit man auch große Symbole anzeigen kann.

Du solltest das Icon in meheren Auflösungen anbieten (wurde ja schon erwähnt). Jetzt nur ein Icon mit 32 Pixel zu verwenden ist auch keine Lösung, dass sieht z.B. auf Bildschirmen mit hoher Pixeldichte sehr schnell unschön aus.

Für das Erstellen der Icons kann ich Axialis IconWorkshop empfehlen.

28.02.2017 - 08:26 Uhr

> Nach meinen Informationen muss ein Icon für ein Fenster entweder 16x16 und/oder 32x32 Pixel groß sein mit 16/256 Farben.
> Also maximal 32x32 Pixel und dann ist es wohl kein Bug von Windows Augenzwinkern

Du bist definitiv falsch informiert:
Icons

15.02.2017 - 18:09 Uhr

Ohne das jetzt getestet zu haben fällt mir doch einiges auf...


        private void btnFindSource_Click(object sender, EventArgs e)
        {
            { <--
                lstAgent.Clear();
                FindSourceFolder();
                lstAgent.Select();
            } <--
        }

Was sind das für überflüssige Klammern?


        private string FindSourceFolder()
        {
            
            FolderBrowserDialog ZipSourceFolder = new FolderBrowserDialog();
            var folder = String.Empty;
            var foldersToZip = String.Empty;
            try
            {
                if (ZipSourceFolder.ShowDialog() == DialogResult.OK)
                {
                    folder = Path.GetFullPath(ZipSourceFolder.SelectedPath);
                    lblPath.Text = ($"Actual Path: " + folder);
                    actualPath = folder;
                    
                    foreach (var item in folder)
                    {
                        foldersToZip += Path.GetDirectoryName(folder).ToString();
                    }
                }
                ShowFolderSelection(folder);
                return folder;

            }
            catch (System.IO.DirectoryNotFoundException)
            {
                MessageBox.Show("The selected directory could not be found!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (UnauthorizedAccessException)
            {
                MessageBox.Show("Access to the selected directory is denied!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (Exception e)
            {
                MessageBox.Show("Unexpected error: " + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

FolderBrowserDialog sollte immer mit using verwendet werden (wie alle Dialoge).


using(FolderBrowserDialog ZipSourceFolder = new FolderBrowserDialog())
{ 
     ... dein Code ...
}


                if (ZipSourceFolder.ShowDialog() == DialogResult.OK)

Beim Aufruf von ShowDialog solltest Du den Owner mitgeben (in diesem Falle 'this'). Das ist wahrscheinlich die Ursache Deines Problems...


                if (ZipSourceFolder.ShowDialog(this) == DialogResult.OK)

Da gibt es noch vieles mehr am Code auszusetzen (leere Methode, wildes mischen von var und konkreter Typangabe usw.).

Nur weil es 'irgendwie' funktioniert muss es nicht richtig/sinnvoll sein...

25.01.2017 - 09:16 Uhr

Wenn es fürs Hobby und/oder kostenlos sein muss: Was spricht gegen die Verwendung des CellPainting-Events des DataGridViews? Beispiele dafür gibt es zu Hauf im Netz.

Wenn es auch was kosten darf: https://www.devexpress.com/Products/NET/Controls/WinForms/

Bei DevExpress gibt es die Klasse SparkLineEdit, die sich sehr einfach in einem Grid darstellen lässt. Das Grid und die anderen Controls sind aussserdem DEUTLICH mächtiger als das DataGridView...

12.01.2017 - 10:34 Uhr

Beschäftige Dich mal mit dem Thema Debugging/Debugger - damit solltest Du den/die Fehler finden können. Ich denke nicht, dass Dir hier jemand diese Arbeit abnehmen möchte/wird...

05.01.2017 - 08:36 Uhr

Wenn es auch was kosten darf, schau Dir mal www.devexpress.com oder www.devcomponents.com an. Das gibt es solche (und noch viele weitere Controls). Ansonsten such mal nach 'Outlookbar' oder 'Navbar'...

27.12.2016 - 22:48 Uhr

Abseits aller Anmerkungen über Sinn und Unsinn der Abbildung von derlei Dingen in den UI-Elementen kannst Du natürlich immer eine eigene Button-Klasse erstellen, die von der Klasse Button erbt, diese dann um weitere Eigenschaften/Methoden ergänzen und anschließend im Designer verwenden:

public class MyButton : Button
{
     public int PosX { get; set; }
     public int PosY { get; set; }
     ...
}
09.11.2016 - 09:46 Uhr

Die Länge von Wörtern ist in den verschiedenen Sprachen wirklich sehr verschieden...

Und genau deshalb sind - möchte man eine mehrsprachige Anwendung vernünftig gestalten - viel mehr Maßnahmen und Überlegungen notwendig als nur die Texte zu übersetzen.

Neben der Empfehlung mit den automatischen Layoutfunktionen wie Docking, Anchoring zu arbeiten muss man die Masken von vornherein so planen/gestalten, dass dieser Umstand später nicht zu Problemen führt. Das betrifft vor allem die Anordnung der Controls aber auch die Verwendung von Layoutcontainern wie z.B. dem TableLayout-Control (hier könnte man z.B. die Spaltenbreite und/oder die Zahlenhöhe von der verwendeten Sprache abhängig machen). An der einen oder anderen Stelle wird man sicher auch komplett sprachabhängige Controls/Dialoge erstellen müssen (hier bietet sich z.B. die Verwendung von austauschbaren Usercontrols an). Wohl dem, der dann Logik und UI konsequent voneinander getrennt hat...

04.11.2016 - 12:15 Uhr

Vielleicht noch ein kleiner Tipp:

Wenn Du Probleme in einer Software hast und/oder tiefer in das Thema einsteigen möchtest, empfehle ich Dir den .NET Memory Profiler (http://memprofiler.com/). Der hat mir schon oft 'aus der Patsche' geholfen. Ein sehr beliebter Fehler ist ja das binden von Ereignissen in übergeordneten Instanzen und das Vergessen der Freigabe dieser Bindungen wenn die untergeordnete Instanz 'geschlossen' wird - wodurch Referenzen auf die untergeordnete Instanz erhalten bleiben und der GC diese nicht mehr 'abräumen' kann. Gerade solche Dinge kannst Du mit dem Profiler sehr gut erkennen...

14.09.2016 - 17:02 Uhr

Zeig mal, was Du schon gemacht hast und wo es hängt...

@MrChangeLog
Splitten etc. ist bei der Konstellation und vorausgesetzt die Dateinamen sehen alle gleich aus (_guid.) zu umständlich. Mit dem Wissen, das eine Guid immer 36 Zeichen hat reichen Substring und LastIndex vollkommen aus ('dateiname'.Substring('dateiname'.LastIndexOf('.') - 36, 36))). Allerdings bin ich mir nicht sicher, ob das was wwAlex da als Beispielname gepostet hat korrekt war - das wäre dann nämlich keine Guid (zu kurz)...

14.09.2016 - 16:25 Uhr

LastIndexOf
Substring

und was String noch so alles an Methoden zu bieten hat...

16.08.2016 - 13:26 Uhr

Vielleicht hilft Dir das hier weiter:

https://atapi.codeplex.com/

09.08.2016 - 08:49 Uhr

FirebirdSQL kann das. Dort musst Du nur den vollständigen Namen der Datei im Connectstring angeben. Wenn Du nicht die Embedded-Version (letztendlich nur ein paar DLLs die sich in Deinem Programmverzeichnis befinden) verwenden möchtest, muss der FirebirdSQL-Server auf dem Rechner installiert werden, auf dem die Datenbank physisch liegt. Dort ist es dann aber egal, auf welchem lokalen Laufwerk und in welchem Verzeichnis die Datei abgelegt ist. Um die Datei verschieben zu können, darf keine Anwendung diese geöffnet haben/verwenden - kopieren geht aber immer (auch wenn gerade eine Anwendung mit der DB arbeitet). Falls Du später vom Embedded- auf den 'echten' FirebirdSQL-Server wechseln möchtest (oder umgekehrt), muss nur ein Parameter im Connectstring geändert werden - das ist also sehr einfach.

Weitere Informationen und alle Downloads dazu findest Du auf www.firebirdsql.org...

02.08.2016 - 12:12 Uhr

Neben den bereits durch 'Papst' erwähnten Dingen, kannst Du Dir die Xml... Attribute sparen.


    [Serializable]
    public class Car
    {
        public string Model { get; set; }
    }


    [Serializable]
    public class CarCollection
    {
        public Car[] Car { get; set; }
    }

reicht völlig aus...

02.08.2016 - 12:05 Uhr

Also ich weiß nicht, ob IoC /DI in diesem Falle nicht 'mit Kanonen auf Spatzen schießen' ist. Da das Userobjekt nur einmal gesetzt und dann an vielen Stellen verwendet wird, spricht IMHO nichts gegen eine pragmatische Lösung mit einer statischen Klasse. Ich handhabe das in der Regel so, dass es eine statische Klasse die den gleichen Namen wie meine Anwendung trägt gibt, in der ich derartiges dann ablege. Ganz vereinfacht etwa so:

public static class MyApp
{
      public static User User { get; set; }
}

und dann an beleibiger Stelle z.B. soetwas:

if (MyApp.User != null)
   MyApp.User.DokumentiereWas();
21.07.2016 - 08:07 Uhr

Wie ErfinderDesRades bereits schrieb kannst Du die Eigenschaft Font in Deiner BaseUserControl überschreiben und mit dem DesignerSerializationVisibility Attribute versehen (Hidden).

Allerdings erzeugst Du ja zur Laufzeit auch weiterhin für jedes Deiner Controls ein neues Font-Objekt. Wäre es nicht besser den Font einmal zu erzeugen und dann in allen Deinen Controls diesen zu verwenden?

So in etwa könnte das aussehen:

public static class GuiLayer
{
   private static bool _designmode;
   private static bool _initialized;
   private static Font _baseFont;

   public Font BaseFont {
      get { 
         if (!_initialized)
         {
            _initialize();
         }

         return _baseFont;
      }

   public bool DesignMode [
      get { 
         if (!_initialized)
         {
            _initialize();
         }

         return _designMode;
      }

   private void _initialize() {
      _baseFont = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
      _designmode = (Process.GetCurrentProcess().ProcessName == "devenv");
   }
}

protected BaseUserControl()
{
    if (!GuiLayer.DesignMode)
    {
        Font = GuiLayer.BaseFont;
    }
    InitializeComponent();
}

Einziger Nachteil - der Font steht zur Designzeit nicht zur Verfügung...

20.07.2016 - 10:24 Uhr

Tu Dir selbst einen gefallen und verwende einen versionsunabhängigen Wrapper für den Zugriff auf Office...

NetOffice

18.07.2016 - 08:27 Uhr

Wenn 'ThermometerRoom 1' keine sichtbaren Einträge mehr enthält, halte ich es für sinnvoller, den Eintrag selbst (also 'ThermometerRoom 1') zu 'disablen'. Sonst sieht der Benutzer einen Menüeintrag, der schienbar komplett ohne Funktion ist...

12.07.2016 - 13:57 Uhr

Das get/set in Deinem Property User_Types ist ebenfalls falsch. Richtig wäre:


private List<User_Type_T> user_type;

public List<User_Type_T> User_Types
{
     get { return this.user_Types; } // das 'this' kannst Du Dir eigentlich sparen
     set { this.user_Types= value; }
}

und wenn Du es noch 'richtiger' machen möchtest:


private List<User_Type_T> user_type;

public List<User_Type_T> User_Types
{
     get { if (user_Types == null) user_Types = new List<User_Type_T>(); return user_Types; }
     set { user_Types= value; }
}

30.05.2016 - 13:21 Uhr

Da Du nicht genau schreibst, welches das jenige ist, was Du gesucht hast und ich 'befürchte' das Du den Tipp von P!lle meinst, möchte ich Dich nochmal ausdrücklich davor warnen, das Layout Deines Fensters auf diese Art und Weise zu gestalten. Das fliegt Dir spätestens dann 'um die Ohren', wenn ein User mal nicht mit der Standardauflösung von 96 dpi arbeitet.

Besser wäre es die von mir vorgeschlagenen Layoutmechanismen zu verwenden, welche Windows von Haus aus mitbringt - insbesondere das TableLayoutPanel eignet sich wunderbar zur Darstellung solcher Interfaces...

27.05.2016 - 08:07 Uhr

Wie wäre es mit 'anchor', 'dock' und/oder TableLayout?

26.04.2016 - 09:36 Uhr

Das hört sich alles andere als eine robuste Lösung an. Warum wird das PDF in einem externen Prozess angezeigt? Es gibt zahlreiche Lösungen die PDF-Datei direkt im Programm anzuzeigen - warum verwendest Du nicht eine davon?

26.04.2016 - 09:29 Uhr

@Darty1971

Wieso machst Du Dir denn das Leben so schwer? XML Serialisierung ist eine gängige, gut funktionierende Sache - kein Grund das Rad neu zu erfinden. Dein ganzes Gefrickel zeigt eher, dass Du schon Probleme beim Entwurf der Struktur der Daten hast (also dem übertragen der benötigten Informationen in ein entsprechendes Model). Schau Dir den Post von trib nochmal genau an und berücksichtige seine Hinweise (Entwurf einer vernünftige Daten-/Klassenstruktur usw.).

Damit hättest Du Dein Problem längst gelöst...

15.04.2016 - 22:22 Uhr

Was Du suchst, ist ein sog. Netzwerk Scanner. Das sind Geräte, die auch komplett ohne PC funktionieren und wie die schon beschriebenen Multifunktionsgeräte direkt ins Netz eingebunden werden können. Im Prinzip sind das Multifunktionsgeräte ohne Druckereinheit.

Die Teile gibt es von vielen Anbietern. Ein paar Beispiele:

HP ScanJet Pro 4500 fn1
Xerox DocuMate 3920
Plustek eScan A150
CANON ScanFront 330

15.04.2016 - 22:01 Uhr

Ich persönlich finde es ist der komplett falsche Ansatz....

Naja, das ganze ist ja sicher nur ein Beispiel und man muss nicht immer mit Kanonen auf die kleinen Spatzen schießen. Ich finde nichts verwerfliches an einer Prüfung von Werten im setter - was die Exception angeht sind wir aber d'accord, das ist sicher keine sehr geschickte Lösung...

@IamTheBug:
Zuerst einmal gibt es keinen sealed setter. Einen setter kann man nur als sealed markieren, wenn man gleichzeitig override verwendet. Was aber gänge, wäre soetwas:


    public abstract class BaseClass
    {
        public virtual string Name { get; set; }
    }
    
    public abstract class ObjectWithName : BaseClass
    {
        private string _name;

        public sealed override string Name
        {
            get { return _name; }
            set
            {
                if (value == "Max Mustermann") throw new Exception();
                    _name = value;
            }
        }
    }

Ok. Also entweder den anderen meine Implementierung aufzwingen oder damit leben, wenn sie es überschreiben selber noch base aufzurufen?

Vielleicht solltest Du Dich mal mit Interfaces und dem Facade-Pattern auseinandersetzen...

06.04.2016 - 18:31 Uhr

Nur mal so als Anregung vielleicht:

Wenn Du nur wissen musst, dass in einem definierten Bereich der sonst leer/einfarbig ist ETWAS enthalten ist, kannst Du auch einfach ermitteln ob eine ausreichende Menge Pixel im definierten Bereich sich deutlich vom Rest der Pixel unterscheidet (Farbe und/oder Kontrast/Helligkeit). Das wäre sicher deutlich einfacher zu realisieren...

04.03.2016 - 16:21 Uhr

Was Du suchst ist ein ORM. Zum Beispiel dieses hier: https://sqliteorm.codeplex.com/

04.03.2016 - 12:28 Uhr

Ich denke, dass STRG+O ein Hotkey ist, den Deine Komponente ebenfalls verwendet. Versuche mal Deinem Menüpunkt einen anderen HotKey zuzuweisen...

18.02.2016 - 11:52 Uhr

Du kannst ein Form auch ohne .designer-Datei erstellen. Füge Deinem Projekt eine neue Klasse hinzu und erbe im Quelltext von Form. Speichern, schließen und dopplet anklicken öffnet den Designer - dieser schreibt seine EInstellungen nun aber nicht mehr in eine separate Datei, sondern direkt in die von Dir angelegte Klasse/Quellcode-Datei.

BTW: Sehr sauber ist das aber nicht und ich würde es so nicht machen...

Du kennst https://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider.compileassemblyfromfile.aspx ?

15.12.2015 - 22:52 Uhr

Hast Du schon mal die Windows-Ereignisprotokolle durchgesehen - oftmals erscheint dort eine Fehlermeldung, die Du sonst so nicht zu sehen bekommst.

Meine erste Vermutung ist aber, dass das Visual Studio unter einem anderen Account installiert wurde und/oder etwas an der Installation nicht in Ordnung ist. Ich würde es nochmal deinstallieren und dann von Deinem eigenen Account aus nochmal neu installieren (gleiches vllt. auch noch mit der dem .NET-Framework...).

Ist zumindest einen Versuch wert...

11.12.2015 - 22:12 Uhr

funktioniert leider nicht. 😦

Das kann natürlich nur funkionieren, wenn Deine Textbox nicht ganz oder teilweise von der Tastatur verdeckt wird. Eventuell kommst Du besser, wenn Du Deine eigene 'Tastatur' als UserControl implementierst...

09.12.2015 - 08:35 Uhr

Habe soetwas schon ein paar mal gesehen, wenn man mit zwei Bildschirmen arbeitet. Vor allem dann, wenn die Bildschirme über 'Drittanbieter' angesteuert werden (oft bei Dockinstations und ähnlichem der Fall).

18.11.2015 - 20:43 Uhr

Das Zeichnen des Rectangles in Deiner OnPaint-Methode ist nicht korrekt. Statt

e.Graphics.FillRectangle(Brushes.Brown,new Rectangle(this.Location,this.Size));

solltest Du

e.Graphics.FillRectangle(Brushes.Brown,new Rectangle(new Point(0,0),this.Size));

verwenden.

Der Canvas auf dem Du zeichnest bezieht sich ausschließlich auf das Button-Control, this.Location stellt aber die Position des Buttons im übergeordneten Container da. Im Canvas Deines Buttons ist die Position oben links immer 0:0...

29.10.2015 - 20:10 Uhr

Meinst du damit, dass ich das Control nochmal von grund auf neu implementieren soll?

Nein, es sollte ausreichen, statt e.DrawBackground mittels ControlPaint einen 'Button' zu zeichnen...

27.10.2015 - 14:35 Uhr

Schau Dir mal die Klasse System.Windows.Forms.ControlPaint an. Damit kannst Du Standard-GUI-Elemente zeichnen (in Deinem Fall könnte DrawButton funktionieren).

22.10.2015 - 12:59 Uhr

Du solltest versuchen, mit dem Debugger genauer einzugrenzen, wo das Problem auftritt. So ist es ziemlich schwierig, was konstruktives beizutragen...

12.10.2015 - 19:57 Uhr

Ohne wirklich genau verstanden zu haben, was Du da treibst:

Schau Dir mal Control.DrawToBitmap an - damit zeichnest Du den Inhalt eines Controls/Fensters in ein Bitmap, dass Du dann an anderer Stelle darstellen kannst...

08.10.2015 - 16:57 Uhr

Ich nutze zum Auffinden vom Memory-Leaks das hier:

http://memprofiler.com/

Gerade das Auffinden von Referenzen, die ein finalisieren der Objekte verhindern (wie von Palin beschrieben) IMHO sehr gut geeignet...

05.10.2015 - 20:40 Uhr

Solltest Du doch mit zwei Tabellen weiterarbeiten wollen und die 'nervigen' joins vermeiden wollen, solltest Du Dir vllt. ein View anlegen, in dem Du die beiden Tabellen zusammenfasst.

01.10.2015 - 17:07 Uhr

Um einer WinForms-Anwendung einen eigenen Look zu geben, gibt es diverse kommerzielle und freie Frameworks. Hier ein paar Anregungen:

frei verfügbar:
http://thielj.github.io/MetroFramework/
https://github.com/IgnaceMaes/MaterialSkin

kommerziell
http://www.devexpress.com
http://www.devcomponents.com
http://www.telerik.com

Stell dir mal folgendes vor: Du hast ein Buch mit 400 Seiten. Auf Seite 351 ist plötzlich eine ganz andere Farbe und Schriftart. Seite 352 entspricht dann wieder allen anderen Seiten. Ist nicht schön oder?

Das ist ein IMHO ziemlich dämlicher Vergleich: Sieht denn jedes Buch in Deinem Regal gleich aus? Eine moderne UI kann heute den Erfolg/Misserfolg einer Anwendung entscheidend beeinflussen und den Unterschied zwischen 'mir' und 'meiner Konkurrenz' ausmachen. Ideal sind abei natürlich Lösungen, die es dem User überlassen, was er bevorzugt...

17.09.2015 - 17:15 Uhr

Vielen Dank für die 'Anteilnahme'.

Für das Schreiben der Daten war/ist eine ältere, in VB6 geschriebene Anwendung verantwortlich. Ich greife auf die Datenbank nur lesend zu (Quelltext steht mir leider nicht zur Verfügung).

Zum Testen meiner Anwendung habe ich die Datenbank aus einem bestehenden MS SQL Server 2012 (mit dem auch die Anwendung arbeitet und die Daten schreiben UND lesen kann). Dort habe ich die Datenbank mittels detach 'abgehängt', dann auf meinen Rechner (MS SQL 2014) kopiert und mit attach eingebunden. Versuche ich nun die Daten auf meinem Rechner zu lesen erhalte ich immer ein byte[] in dem die Daten UTF8 codiert vorliegen (16bit pro 'Byte' - immer das 'richtige' Byte gefolgt von einem Byte mit dem Wert 0x00). Mittels Encoding kann ich diese Daten problemlos verarbeiten und die ursprüngliche Datei wiederherstellen).

Verwende ich nun mein Programm gegen den ursprünglichen SQL Server 2012, erhalte ich das beschriebene Verhalten - also immer 'O_L_E_-O_b_j_e_k_t' wobei der Unterstrich für 0x00 steht. Schaue ich mir die Tabelle mit dem SQL Manager an, kann ich die korrekten Daten lesen.

Meine Vermutung ging nun in die Richtung, dass ich auf dem MS SQL Server noch irgendwas einstellen muss/kann, dass er die tatsächlichen 'Binärdaten' liefert - allerdings finde ich nichts dazu.

@BerndFfm
Den Artikel in Deinem Link kannt ich shcon - auch mit dem Code dort scheitert es immer wieder an der Zeile:

      byte[] bData = (byte[])cmdQuery.ExecuteScalar();

die bereits die falschen 'Rohdaten' liefert.

Ich werde morgen nochmal versuchen mit einer anderen Framework-Version als der derzeit genutzten 4.5 zu arbeiten - vllt. ist es ja auch ein 'Bug' im .NET-Framework.

16.09.2015 - 22:37 Uhr

verwendetes Datenbanksystem: MS SQL (2012 und 2014)

Hallo,

ich stehe vor einem Problem, bei dem ich mir nicht mehr zu helfen weiß, auch Google etc. konnte mir leider nicht helfen.

Ich habe eine Tabelle Notizen, in der es eine Spalte des Typs 'Image' (die Datenbank ist schon älter, deshalb wurde hier noch mit 'Image' gearbeitet) mit dem Namen 'Datenfeld' gibt. In diesem Datenfeld sind Blobs/Streams/Binärdaten beliebiger Dateien gespeichert (PDF, DOC etc.). Dieses Datenfeld möchte ich auslesen um den Inhalt wieder als Datei speichern zu können. Der Inhalt von Datenfeld ist ein UTF8 codierter Stream. Soweit so gut.

Ich habe nun folgende Varianten ausprobiert, die auf einem MS SQL Server 2014 auch alle problemlos funktionieren:

Variante 1:

using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
     connection.Open();
     using (SqlCommand command = new SqlCommand("select Notiznr, Datenfeld from Notizen where Notiznr = 1000", connection))
     {
          using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
          {
              while (reader.Read())
              {
                   int fieldpos = reader.GetOrdinal("Datenfeld");
                   if (reader.IsDBNull(fieldpos))
                         break;

                   byte[] daten = new byte[]{};
                   using (MemoryStream mem = new MemoryStream())
                   {
                       using (Stream output = reader.GetStream(fieldpos))
                       {
                           output.CopyTo(mem);
                           daten = mem.ToArray();
                       }
                   }
              }
          }
      }

      connection.Close();
}

Variante 2:

using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
     connection.Open();
     using (SqlCommand command = new SqlCommand("select Notiz, Datenfeld from Notizen where Notiznr = 1000", connection))
     {
          using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
          {
              while (reader.Read())
              {
                   int fieldpos = reader.GetOrdinal("Datenfeld");
                   if (reader.IsDBNull(fieldpos))
                         break;

                   long totalbytes = reader.GetBytes(fieldpos, 0, null, 0, 0);
                   if (totalbytes < 1)
                       break;

                   long bytesgelesen = 0;
                   byte[] daten = new byte[totalbytes];
                   long startpos = 0;
                   while (bytesgelesen < totalbytes)
                   {
                       bytesgelesen += reader.GetBytes(fieldpos, startpos, daten, (int)startpos, 1024);  // tried with several block sizes...
                       startpos += 1024;
                   }
               }
          }
      }

      connection.Close();
}

Variante 3:

using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
     connection.Open();
     using (SqlCommand command = new SqlCommand("select Datenfeld from Notizen where Notiznr = 1000", connection))
     {
         byte[] daten = (byte[])command.ExecuteScalar();
     }
     connection.Close();
}

und Variante 4:

using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
     connection.Open();
     using (SqlCommand command = new SqlCommand("select Notiznr, Datenfeld from Notizen where Notiznr = 1000", connection))
     {
          using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
          {
              while (reader.Read())
              {
                   int fieldpos = reader.GetOrdinal("Datenfeld");
                   if (reader.IsDBNull(fieldpos))
                         break;

                   byte[] daten = (byte[])reader[fieldpos];
              }
          }
      }
      connection.Close();
}

Nun habe ich die exakt gleiche Datenbank mit zwei verschiedenen MS SQL Server 2012 Installationen ausprobiert und erhalte dort statt der erwünschten Daten immer 20 Bytes, die den Text 'OLE-Objekt' repräsentieren (UTF8, deswegen 20 Bytes). Ich habe auch schon versucht statt der Sql-Klassen mit OleDB zu arbeiten (funktioniert auf dem MS SQL Server 2014 wieder problemlos) aber bekomme immer das gleiche Ergebnis.

Weiß jemand Rat?

Gruß,
wcseller

10.08.2015 - 21:48 Uhr

Schau Dir mal den Quellcode von MaterialSingleLineTextField an. Dort wird ähnlich wie in den von Dir im erstn Post angegeben Varianten eine Textbox in ein Control eingebettet. Dort könntest Du ansetzen um Dir ein eigenes Control abzuleiten und die entsprechenden Zeichenroutine zu überschreiben (OnPaint).