Laden...

Forenbeiträge von Andreas.May Ingesamt 915 Beiträge

17.01.2008 - 10:15 Uhr

Hrm, schau mal in System.IO.DriveInfo bzw. DriveInfo.GetDrives 🙂


    foreach (System.IO.DriveInfo _dv in System.IO.DriveInfo.GetDrives())
            {
                Console.WriteLine("{0}, {1}", _dv.RootDirectory.FullName, _dv.DriveType.ToString());
            }

Sample:


A:\, Removable
C:\, Fixed
D:\, Fixed
E:\, CDRom
F:\, CDRom
L:\, Network
N:\, Network
S:\, Fixed
V:\, Network

17.01.2008 - 09:57 Uhr

Trotzdem, merkwürdig normal sollte das keine Probleme geben.
Schau mal nahc ob irgendwas mit dem Focus anstellst.

Wenn alles nichts hilft dann probier das mal.


    protected override void OnKeyUp(KeyEventArgs e)
            {
                if (e.KeyData == (Keys) (Keys.LButton | Keys.Back))
                {
                    if (base.CurrentCell != null)
                    {
                        base.CurrentCell.Selected = true;
                    }
                }
                
                base.OnKeyUp(e);
            }

16.01.2008 - 17:50 Uhr

... und dann der "blöde" Spruch:
Der Tag hat 24 Stunden, dann kommt noch die Nacht,

Ich kenn den Spruch etwas anders:"Der Tag hat 24 Stunden und wenn es sein muss nehmen wir die Nacht noch dazu.." 🙂

16.01.2008 - 17:35 Uhr

Hrm, normal sollte das gehen.
Da das Control beim Eintrag aktiv ist, werden die Keyboardeingaben auch dort verarbeitet. Sogar wenn den TabStop = false machst.

Mach mal ne neue Klasse, leite von DataGridView ab und schau mal in protected override void OnKeyPress nach.

16.01.2008 - 17:22 Uhr

Hrm, mach mal statt openFileDialog1.ShowDialog(this) nur openFileDialog1.ShowDialog() ohne den Owner zu übergeben... Normalerweise sollte das keinen "unterschied" machen. Aber evtl. hast ja noch etwas in deiner ImportForm Klasse drinnen was nicht mit reingepostet hast. Der Aufruf sollte normalerweise ohne Probleme geben und Dialoge kannst so oft ineinander verschachteln wie du Lust und Laune hast.

16.01.2008 - 16:49 Uhr

Hrm, du kannst SubClassing betreiben um das zu bewerkstelligen.

Hier nen BeispielCode dafür: Link

Oder eben PostThreadMessage über WIN32.

[EDIT.. nach 3 mal falschen Link reinkopieren...]
Hrm, da war wer schneller 😉

16.01.2008 - 15:12 Uhr

Hrm, also das "alle" auf einmal auf ReadOnly setzten kannst keine Ahnung. Aber einzelnd sollte das kein Problem sein, (fast) alle "Steuerelemente" haben als Propertie das DevExpress.XtraEditors.Repository.RepositoryItem implementiert und somit die Eigenschaft ReadOnly. Das Propertie davon heisst meistens "Properties.ReadOnly".

z.B in der Art:

 this.textEdit1.Properties.ReadOnly = true;

Das DataSourceUpdateMode.Never kannst dann ja weglassen, dachte nur man sollte schon etwas eingeben dürfen aber erst im Modus Editieren wird es dann wirklich zurückgeschrieben 🙂

Und wegen des DataNavigator, machs dir einfach.
Erstell ne neue Klasse, leite sie von TextEdit ab und setzt dann im Konstruktor über Controls.Add einfach deinen DataNavigator drüber. Nun radierst im Hintergrund einfach des TextEdit aus.

16.01.2008 - 15:00 Uhr

Hrm, leider habe ich nichts mehr dazu gefunden was funktiniert. Also wirst doch selbst ein GDI dafür schreiben müssen.

Das Ableiten von einer RichTextBox kann ich dir bei einem eigenen GDI Verhalten für die Textmarkierung nicht empfehlen.

Weil bei Lösung 1:


public CRTB()
        {
          base.SetStyle(ControlStyles.UserMouse, true);
        }

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetCursorPos(out Point lpPoint);
        private const int WM_PAINT = 0xF;

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == WM_PAINT)
            {
                using (Graphics _gfx = Graphics.FromHwnd(base.Handle))
                {
                    if (!string.IsNullOrEmpty(base.SelectedText))
                    {
                        SizeF emSize = _gfx.MeasureString(base.SelectedText, base.SelectionFont);

                        RectangleF rc = new RectangleF(new PointF(base.SelectionRightIndent, 0), emSize);
                        _gfx.FillRectangle(new SolidBrush(Color.FromArgb(150, 255, 0, 0)), rc);
                    }
                }
            }
        }

Hättest erstmal das Problem das dass komplette Selectet Textverhallten selbst gestallten müsstest. Ausserdem kommt es zu ungenauigkeiten beim markieren, wobei hier die Font schuld dran ist (MeasureString gibt keinesfalls den wirklichen gezeichneten Wert des Strings wieder). Zudem kann man imme rnoch mit Pfeiltasten usw. das "alte" makieren auslösen.

Auch Lösung 2 geht nicht, das wäre wenn base.SetStyle(ControlStyles.UserPaint, true); setzen würdest. Denn dann müsstest den string selbst Zeichnen und das geht an der Stelle schief da ebenfals der gezeichnete String mit dem darunterliegenden (nicht visuellen) tazächlichen String Probleme bereitet...

Also, mach ein neues UserControl und bau die RichTextBox nach. Denk dran, keine EditBoxen oder ähnliches Verwenden das absolut komplette Verhalten muss von deinem UserControl selbst gezeichnet werden! Sonst kämpft du wieder mit der Textmakierung. Sorry, was besseres fällt mir dazu nicht ein 🙁

Vielleicht fragst mal Talla nach (via PN) ob es unter WPF eine dafür vorgesehene Möglichkeit gibt, das evtl doch bequemer zu realisieren.

Evtl. hat noch wer eine bessere Idee.

16.01.2008 - 13:21 Uhr

Jup genau das hatte ich vor...
Bei dem Beispiel hätte ich erwartet das sich nun die Hintergrundfarbe ändert vom Control aber es tritt kein Effekt ein. Das merkwürdige ist nur das die Farbe wirklich geändert wird, so wie bei einem Out auch zu erwarten wäre. Irgendetwas fehlt evtl. um das ganze anzustoßen. Vielleicht Send Message CHANGESTYLE oder so etwas ähnliches.. Ich versuche das nochmal.

16.01.2008 - 12:31 Uhr

Hrm hatte gehofft das dass hier funktionieren würde, entweder mache ich noch was falsch oder es geht wirklich nicht so einfach:


   public class CRTB : RichTextBox
    {
        [DllImport("uxtheme.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
        private static extern IntPtr OpenThemeData(IntPtr hWnd, String classList);

        [DllImport("uxtheme", ExactSpelling = true)]
        public extern static Int32 GetThemeColor(IntPtr hTheme, int iPartId, int iStateId, int iPropId, out COLORREF pColor);

        [DllImport("uxtheme.dll", ExactSpelling = true)]
        private extern static Int32 CloseThemeData(IntPtr hTheme);


        [StructLayout(LayoutKind.Sequential)]
        public struct COLORREF
        {
            public uint ColorDWORD;

            public COLORREF(System.Drawing.Color color)
            {
                ColorDWORD = (uint)color.R + (((uint)color.G) << 8) + (((uint)color.B) << 16);
            }

            public System.Drawing.Color GetColor()
            {
                return System.Drawing.Color.FromArgb((int)(0x000000FFU & ColorDWORD),
               (int)(0x0000FF00U & ColorDWORD) >> 8, (int)(0x00FF0000U & ColorDWORD) >> 16);
            }

            public void SetColor(System.Drawing.Color color)
            {
                ColorDWORD = (uint)color.R + (((uint)color.G) << 8) + (((uint)color.B) << 16);
            }

            public static COLORREF Empty = new COLORREF();
        }

        private enum EDITTEXTSTATES
        {
            ETS_NORMAL = 1,
            ETS_HOT = 2,
            ETS_SELECTED = 3,
            ETS_DISABLED = 4,
            ETS_FOCUSED = 5,
            ETS_READONLY = 6,
            ETS_ASSIST = 7
        }

        private enum COLORS
        {
            TMT_BORDERCOLOR = 3801,
            TMT_FILLCOLOR = 3802,
            TMT_TEXTCOLOR = 3803,
            TMT_EDGELIGHTCOLOR = 3804,
            TMT_EDGEHIGHLIGHTCOLOR = 3805,
            TMT_EDGESHADOWCOLOR = 3806,
            TMT_EDGEDKSHADOWCOLOR = 3807,
            TMT_EDGEFILLCOLOR = 3808,
            TMT_TRANSPARENTCOLOR = 3809,
            TMT_GRADIENTCOLOR1 = 3810,
            TMT_GRADIENTCOLOR2 = 3811,
            TMT_GRADIENTCOLOR3 = 3812,
            TMT_GRADIENTCOLOR4 = 3813,
            TMT_GRADIENTCOLOR5 = 3814,
            TMT_SHADOWCOLOR = 3815,
            TMT_GLOWCOLOR = 3816,
            TMT_TEXTBORDERCOLOR = 3817,
            TMT_TEXTSHADOWCOLOR = 3818,
            TMT_GLYPHTEXTCOLOR = 3819,
            TMT_GLYPHTRANSPARENTCOLOR = 3820,
            TMT_FILLCOLORHINT = 3821,
            TMT_BORDERCOLORHINT = 3822,
            TMT_ACCENTCOLORHINT = 3823
        }
        
        private const int EDITPARTS = 1;

        protected override void OnHandleCreated(EventArgs e)
        {
            int nSucess = 0;

            IntPtr hTheme = OpenThemeData(base.Handle, "Edit");

            if (hTheme != IntPtr.Zero)
            {
                COLORREF ColRef = new COLORREF();
                nSucess = GetThemeColor(hTheme, EDITPARTS, (int)EDITTEXTSTATES.ETS_NORMAL, (int)COLORS.TMT_FILLCOLOR, out ColRef);
                Color OldColor = ColRef.GetColor();
                ColRef.SetColor(Color.Red);
            }

            nSucess = CloseThemeData(hTheme);

            base.OnHandleCreated(e);
        }

    }

15.01.2008 - 17:08 Uhr

da fällt mir nur eins zu ein: Natürliche Selektion ^^

Gemein 😁

15.01.2008 - 16:46 Uhr

Also, normalerweise solltest über Control.Add das ganze lösen können. Wenn es wirklich anders nicht geht (und da habe ich meine Zweifel) sollte das über Win API 32 Funktion SetParent möglich sein (geht immer). Wegen den DataBinding du kannst ja beim DataBinding DataSourceUpdateMode.Never angeben und im EditMode jeweils wieder umändern 🙂

15.01.2008 - 16:25 Uhr

Also irgendwas stimmt da nicht, wenn ich eine api-funktion aufrufe kriege ich die Fehlermeldung "System.Security.Permissions.SecurityPermission".
Der Debugger landet dann aber nicht bei dem funktionsaufruf der definitiv dafür verantwortlich ist, sondern bleibt jetzt bei Application.Run(new Form1()); stehen. Starten tut die Anwendung.

Der Fehler kommt wahrscheinlich von der .NET Access Security (CAS). Ich denke mal deine Assembly hat nicht die Berechtigung COM Interop zu verwenden.
Gib einfach deiner Assembly eine höhere Berechtigung in dem alles auf "FullTrust" stellst 🙂

Und brauchst dir gar keine Mühe mehr geben, hab mal flux in google reingeschaut und schon was gefunden 🙂


[DllImport("uxtheme", ExactSpelling=true)]
public extern static Int32 GetThemeBool(IntPtr hTheme, int iPartId, int iStateId, int iPropId, out int pfVal);

Damit kannst du die TMT_GLYPHTRANSPARENT deaktivieren und somit das makieren des Textes. Dann kannst das von mir oben gepostete mit Color.FromAGB(150,255,0,0) verwenden um z.B eine Halptransparente Textmarke hinzubekommen. Eigentlich echt einfach. (falls keine Win API SDK hast hier der Link) 🙂

Falls das Thema jemand anderen noch interessiert, für was man das eigentlich noch alles nutzen kann und nen Probeprojekt sehen möchte: Das hier fand ich im Netz.

15.01.2008 - 14:46 Uhr

Hrm, um ehrlich zu sein würde ich versuchen das ganze über WindowsThemes abzubilden. Das andere kostet zu viel Zeit ausserdem muss man dabei zu viel nachdenken. Da wären diese Markierungsumsprünge bei Texten über mehrere Zeilen, dieser Glyph Effekt usw. viel zu anstrengend - Also gar nicht mein Fall 🤔 Ausserdme kannst du ja das Theme des Controls bzw. auch des dazugehörigen Fensters explezit ändern also keine Angst das etwas global umstellen würdest. Solange keine WindowsMessage verschickst das global ein Themechange auslöst, sollte da auch nichts passieren.. Müsste man einfach mal nachlesen (ob es das auch überhaupt gibt).

Hier die Sachen die du brauchst:


[DllImport("uxtheme", ExactSpelling=true)]
public extern static Int32 GetThemeColor(IntPtr hTheme, int iPartId, int iStateId, int iPropId, out COLORREF pColor);


[StructLayout(LayoutKind.Sequential)]
struct COLORREF {
   public byte R;
   public byte G;
   public byte B;
}

// Alternate
[StructLayout(LayoutKind.Sequential)]
public struct COLORREF
{
   public uint ColorDWORD;

   public COLORREF(System.Drawing.Color color)
   {
      ColorDWORD = (uint) color.R + (((uint) color.G) << 8) + (((uint) color.B) << 16);
   }

   public System.Drawing.Color GetColor()
   {
      return System.Drawing.Color.FromArgb((int) (0x000000FFU & ColorDWORD),
     (int) (0x0000FF00U & ColorDWORD) >> 8, (int) (0x00FF0000U & ColorDWORD) >> 16);
   }

   public void SetColor(System.Drawing.Color color)
   {
      ColorDWORD = (uint) color.R + (((uint) color.G) << 8) + (((uint) color.B) << 16);
   }
}


Win32 API:
hTheme
[in] Handle to a window's specified theme data. Use OpenThemeData to create an HTHEME.
iPartId
[in] Value of type int that specifies the part that contains the color property. See Parts and States.
iStateId
[in] Value of type int that specifies the state of the part. See Parts and States.
iPropId
[in] Value of type int that specifies the property to retrieve. May be one of the following values.
TMT_BORDERCOLOR
The color of the border associated with this part and state.
TMT_FILLCOLOR
The color of the background fill associated with this part and state.
TMT_TEXTCOLOR
The color of the text associated with this part and state.
TMT_EDGELIGHTCOLOR
The light color of the edge associated with this part and state.
TMT_EDGEHIGHLIGHTCOLOR
The highlight color of the edge associated with this part and state.
TMT_EDGESHADOWCOLOR
The shadow color of the edge associated with this part and state.
TMT_EDGEDKSHADOWCOLOR
The dark shadow color of the edge associated with this part and state.
TMT_EDGEFILLCOLOR
The fill color of the edge associated with this part and state.
TMT_TRANSPARENTCOLOR
The transparent color associated with this part and state. If the TMT_TRANSPARENT value for this part and state is true (see GetThemeBool), parts of the graphic that use this color will not be drawn.
TMT_GRADIENTCOLOR1
The first color of the gradient associated with this part and state.
TMT_GRADIENTCOLOR2
The second color of the gradient.
TMT_GRADIENTCOLOR3
The third color of the gradient.
TMT_GRADIENTCOLOR4
The fourth color of the gradient.
TMT_GRADIENTCOLOR5
The fifth color of the gradient.
TMT_SHADOWCOLOR
The color of the shadow drawn underneath text associated with this part and state.
TMT_GLOWCOLOR
The color of the glow produced by calling DrawThemeIcon using this part and state.
TMT_TEXTBORDERCOLOR
The color of the text border associated with this part and state.
TMT_TEXTSHADOWCOLOR
The color of the text shadow associated with this part and state.
TMT_GLYPHTEXTCOLOR
The color that the font-based glyph associated with this part and state will use.
TMT_GLYPHTRANSPARENTCOLOR
The transparent glyph color associated with this part and state. If the TMT_GLYPHTRANSPARENT value for this part and state is true (see GetThemeBool), parts of the glyph that use this color will not be drawn.
TMT_FILLCOLORHINT
The color used as a fill color hint for custom controls.
TMT_BORDERCOLORHINT
The color used as a border color hint for custom controls.
TMT_ACCENTCOLORHINT
The color used as an accent color hint for custom controls.
TMT_BLENDCOLOR
The color used as a blend color.
pColor
[out] Pointer to a COLORREF structure that receives the color value.
Returns S_OK if successful, or an error value otherwise.

Such dir dann das richtige aus. Siehe LINK

Dann brauchst natürlich:


[DllImport("uxtheme.dll", ExactSpelling=true, CharSet=CharSet.Unicode)]
public static extern IntPtr OpenThemeData(IntPtr hWnd, String classList);

Und zum schluss dann nur noch:


    [DllImport("uxtheme.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        public static extern int SetWindowTheme(IntPtr hwnd, String pszSubAppName,
                                         String pszSubIdList);

Falls dir GDI doch lieber ist, lass die RichTextBox sein und mal dir dein eigenes UserControl. Kostet allerdings einiges an Zeit.

15.01.2008 - 13:32 Uhr

Hrm, mit der CAST Syntax klappt es auch nicht?
SELECT CAST ([Größe] AS varchar(MAX))....usw.

Also ob Format wirklich geht bei MSOffice Anwendungen?
T-SQL Syntax: FORMATMESSAGE ( msg_number , [ param_value [ ,...n ] ] )

15.01.2008 - 13:11 Uhr

Hrm, komisch normalerweise sollte da kein Fehler auftreten evtl. kann es auch an etwas anderen liegen.

Aber verusch dann mal das hier.


private bool selected = false;

        protected override void OnSelectionChanged(EventArgs e)
        {
            selected = true;
            base.Invalidate();
            base.OnSelectionChanged(e);

        }

        private const int WM_PAINT = 0xF;

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetCursorPos(out Point lpPoint);
        [DllImport("user32.dll")]
        private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == WM_PAINT)
            {
                if (selected)
                  {
                    Graphics _gfx = Graphics.FromHwnd(this.Handle)
                    
                        selected = false;

                        Point pt = Point.Empty;

                        GetCursorPos(out pt);
                        pt = PointToClient(pt);

                        RectangleF rc = new RectangleF(pt, new SizeF(base.SelectionLength, base.SelectionFont.Size));
                        _gfx.FillRectangle(new SolidBrush(Color.Red), rc);
                     }                 
            }
        }

Der Code ist wie gesagt nicht fertig, wichtig ist nur das erkennst das nicht die Makierungsfarbe setzt sondern über die makierungsfarbe drüber malst. Die Mouseposition für den makierten Text wird nicht stimmen. Evtl musst da auch an den DeviceContext ran (www.pinvoke.net nach GetDCEx suchen) wenn der wirklich gebuffert wird. Vielleicht gibt es auch eine bessere Methode um an die Mouseposition zu kommen, als die von mir dargestellte. Wichtig ist nur, das die WindowsNachrichten dabei verarbeitest.

Ein anderer Ansatz wäre das die Paint Methode überschreibst.
Für das überschreiben der PaintMethode müsstest du den Style auf UserPaint stellen. Danach müsstest du dich um Darstellung des Textes selbst kümmern. Was aber wiederum den Vorteil hätte, exakt und eigenständig die Markierungsfarbe vereinfacht darzustellen.

Was für einen Ansatz du noch versuchen könntest, schalt mal die Windows Themes um und schau dir die Systemsteuerung genau an, ob irgendwo die Markierungsfarbe verändern kannst. Wenn den Eintrag gefunden hast. So kannst diesen Eintrag auch über WMI, SystemQuerys oder über direkte zugriffe über WIN API ändern. Spontan würde ich halt mal vermuten, das es sich hierbei um einen WindowsTheme handelt der für die Makierungsfarbe zuständig ist.

Also wie du siehst es gibt viele Möglichkeiten, aber ich bezweifle das es ohne GDI Kentnisse leichter hinbekommst 😠 Vielleicht hat jemand noch eine bessere Idee.

15.01.2008 - 13:00 Uhr

Hrm, da war wer mit erklären schneller 😉


     protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (e.KeyChar == 44)
            {
                e.KeyChar = (Char)Keys.None;
                base.Text += ", ";
                base.Select(base.Text.Length, base.Text.Length);
            }
            base.OnKeyPress(e);
        }

15.01.2008 - 12:33 Uhr

Hrm, du hast den Code in deine abgeleitete RichTextBox Klasse importiert und dort auch using System.Runtime.InteropServices reingemacht? benutzt du vielleicht Windows CE ?

15.01.2008 - 11:14 Uhr

Okay, ich denke hab dir da evtl was.
Aber leicht wird es nicht und ist nur nen Billiger Ansatz, also erwarte nicht das der Code hier fertig ist.


private bool selected = false;

        protected override void OnSelectionChanged(EventArgs e)
        {
            selected = true;
            base.Invalidate();
            base.OnSelectionChanged(e);
           
        }

        private const int WM_PAINT = 0xF;

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetCursorPos(out Point lpPoint);
        [DllImport("user32.dll")]
        private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == WM_PAINT)
            {
                if (selected)
                    using (Graphics _gfx = Graphics.FromHwnd(this.Handle))
                    {
                        selected = false;

                        Point pt = Point.Empty;

                        GetCursorPos(out pt);
                        pt = PointToClient(pt);

                        RectangleF rc = new RectangleF(pt, new SizeF(base.SelectionLength, base.SelectionFont.Size));
                        _gfx.FillRectangle(new SolidBrush(Color.Red), rc);
                    }
            }
        }

Viel mehr möglichkeiten wirst wahrscheinlich auch nicht haben, da die Cursor Markierungsfarbe Systemintern vorgegeben ist. Und Systemweit diese zu ändern, hrm.. keine Ahnung ob das eine gute Idee wäre.

10.01.2008 - 16:53 Uhr

Hrm.. probier mal

SELECT convert(varchar(MAX), [Sorte] , 101) as [Sorte], convert(varchar(MAX), [Größe], 101) as [Größe] usw..

Ob das evtl. geht.

08.01.2008 - 16:50 Uhr

Hrm, nur um die Frage zu beantworten: System.Windows.Forms.Timer

Aber ich glaube brauchst das ganze nicht so kompliziert zu machen. Damit deine GUI nicht blockiert während der Datenbankabfrage. Startest MyThreadFunction als Thread Und da die Datenbankabfrage in eine do-while schleife steckt und nach dieser eh der Thread beendet wird.


        private bool m_bAbort = false;

        // startet deien Datenbankabfrage
        private void FillDataFromDatabase()
        {
            new System.Threading.Thread(new ThreadStart(MyThreadFunction)).Start();
        }

        private void MyThreadFunction()
        {
            // hier dein code... z.B. öffne Datenbankverbindung
            do
            {

               // wurde die Abbruchtaste gedrückt?
                if(this.m_bAbort)
                {
                    this.m_bAbort = false;
                    break;
                }

               // hier dein code... hole Datensätze und fülle eine Liste mit den Daten.
            }
            while (<Boolscher Ausdruck>);
            // hier dein code... z.B. schließe Datenbankverbindung

        }

        protected override void BtnAbbruchClick(object sender, EventArgs e)
        {
            this.m_bAbort = true;
        }


08.01.2008 - 16:40 Uhr

Muh ! 😉

Ich dachte die ganze Zeit willst nur nen Bild also sowas wie nen Bitmap haben um das evtl. (bitte nicht lachen) auszudrucken oder irgendwem zu senden. Und nicht um es darzustellen innerhalb deiner Anwendung.

Naja dann brauchst nur Schitt 1 beachten von dem was ich schrieb - Also das malen auf ein UserControl. Du brauchst kein Bild, sondern malst immer nur relevante sichtbare Bereiche.

Stell es dir so vor wie eine PictureBox mit einen Bild und einer Scollleiste. Du bewegst die leiste nach vorne und das Bild geht mit.

In wirklichkeit ist das aber ein UserControl, in dem malst du nur den aktuell sichtbaren Bereich für den Benutzer hin. Siehe dazu diesen Link wenn für das Zeichnen doch noch was unklar sein sollte, evtl ist das leichter zu verstehen worauf ich hinaus will.

08.01.2008 - 16:29 Uhr

Hrm, hatte das vor einiger Zeit auch mal gebraucht der Link half mir prima weiter 🙂

08.01.2008 - 16:26 Uhr

Hrm, da schon einige Beiträge geschrieben hast wundert mich die Frage etwas 🙂
Aber hier der Link.

08.01.2008 - 16:17 Uhr

Da dein Endergebniss ja ein Bild und kein Control sein soll, geht wohl nichts anderes 😠
Es sei jemand hätte ne geniale Idee wie man aus nen int was größeres zaubert.

The maximum height and width of an image is 216 pixels at 32 bits per channel * 4 channels. The maximum size of a BitmapSource is 232 bytes (64 gigabytes) and the maximum image size is four gigapixels. The minimum image size is 1x1.

Aber mich wundert es schon dass das Bild diesen Rahmen sprengt.
Bzw. was ist eigentlich der Zweck eines solch großen Bildes?

08.01.2008 - 15:40 Uhr

Hrm, okay meinte das wie folgt:

Statt direkt ein BitmapBild zu malen machst du verschiedene Teilsegmente, das Problem an der Geschichte du hast nicht 1 Bitmap sondern evtl 5 oder 10 usw. Aber ich würde im ersten Schritt noch nicht so weit gehen ein Bitmap zu erstellen darauf einen Teil zu malen um dann das nächste zu malen.

Erstmal würde ich ein ganz normales Steuerlement verwenden von dem ich nichts anderes als Screenshots mache. Wenn das Klappt hast bereits die Basis geschaffen um das Steuerlement abzulösen.

Und für eben diese Basis brauchst ersteinmal bestimmte Hilfsklassen, wie das Koordinatensyste, das Rechteck und eine Liste für Rechtecke. Erstellen würde ich das ganze daher auf einen eigenen Steuerelement. Auf dem ich auch eine Scollbar drauflege und indem ich die Scrolbar nach vorne schiebe bewege ich das Koordinatensystem um die Breite des Steuerelements nach X. Dann würde ich auch erstmal nur nen Button drauf machen wenn ich auf diesen Klicke mache ich eben einen ScreenShoot von nur dem gezeichneten Bereich.

Wenn das reibungslos klappt, gehst den zweiten Schritt an. Du nimmst das Steuerelement weg. Dann erstellst dir eine Liste an Bitmaps mit new Bitmap machst immer ein neues Bitmap immer einer Festen größe. Global merkst du dir dann die X Achse um die verschoben wurde. Zu beginn ist diese bei 0, jedesmal zeichnest dann nur einen Teilbereich bevor eben wieder ein neues Bitmap erstellst indem dann von X > 0 an einen weiteren Abschnitt zeichnest.

Bitmaps wirst du einfach nicht größer bekommen als sie sind, du kannst aber wie gesagt mehrere Bitmaps machen.

Lass aber den ersten Schritt wie gesagt nicht weg, mir (und ich denke auch jeden anderen) würde das sonst extrem schwer fallen fehlerfrei zu arbeiten.

08.01.2008 - 15:12 Uhr

Hrm, weis nicht, macht es da keinen Sinn stattdessen lieber Arrays draus zu bilden und diese "gegeneinander" laufen zu lassen. Also Iterieren in einer Liste von Klassen-Pointer? Weil ich denke zwar nicht das in TreeNode node in nodes performance verlierst aber spätestens beim Abruf der Node Inhalten oder Atributen usw. beim vergleichen.

Wenn aber nur vergleichst ob die Node überhaupt exestiert hrm... dann muss irgendetwas schief gehen.

08.01.2008 - 15:04 Uhr

Hrm, normal sollte RegEx relativ gut durchlaufen benutze es sogar in einer Datenbank zur Telefonnummernnormalisierung von über 60.000 Datensätze. Allerdings hatte ich das für BB-Code soweit ich mich noch an meine Internetseiten-Programmierkentnisse erinnere (wers glaubt..) als JavaScript verpakt - es hatte irgend einen Grund...

Lies dir das mal dazu durch.

08.01.2008 - 14:54 Uhr

Also zumindest bei uns in der Firma hatte das viel mit Antipatterns in der Software-Entwicklung zu tun

(
>
)

eigentlich alles was falsch gemacht werden konnte (von der Projektleitung bzw. Chef-Etage) wurde falsch gemacht.

EDIT: keine Ahnung, wie das inzwischen bewertet wird. Wäre mal interessant zu wissen.

Wie war das mit JDK: "Der Horizont vieler Menschen ist ein Kreis mit Radius Null -
und das nennen sie ihren Standpunkt." 🤔

08.01.2008 - 14:23 Uhr

Huch, irgenwie hatte ich das so verstanden das "spezielle Fonts" verwendest. Dabei möchtest die Liste nur einschränken 😉

Da lohnt es sich wie folgt vorzugehen:

Mach eine neue Klasse Namens CustomFontDialog , leite von Form ab.
Erstelle eine statische Methode namens ShowDialog ca. wie folgt:


       private Font m_clFont;

        private static Font ShowDialog()
        {
            WMsg wnd = new WMsg();
            wnd.ShowDialog();
            return wnd.m_clFont;
        }

Erstelle dann alle notwendigen Elemente von dem FontDialog in deiner CustomFontDialog. Zum Anzeigen der Fonts läufst einfach alle verfügbaren Fonts durch und sortierst die aus die nicht verwendet werden sollen.


 foreach (FontFamily ft in FontFamily.Families)
                if(ft.Name == "Arial" || "Arial Black" ...)
                    this.Combobox.Add(ft.Name);

Das wars 😉

08.01.2008 - 14:10 Uhr

Hrm,
also würde das ganze recht faul angehen und via GDI lösen .-)

Zuerst erstellst dir eine Klasse für das Grafische Object des Koordinaten Systems.
Danach erstellst du eine Klasse für die Grafische Object eines Rechtecks.
Anschließend erstellst du eine Liste der Grafischen Objecte vom Typ Rechteck.

Soo, dann nimmst nen Panel hängst ne Vertikale Scrollbar dran.
Die Steps beim verschieben gibst du dann vor und löst dabei ein Invalidate aus.
Die grafischen Objecte sind an den virtuellen Koordinaten des Koordinatensystems gebunden so das Quasi gen unendlcih nach rechts Scrollen kannst. Die X Achse bestimmt also daher immer den virtuellen Punkt der darstellung von Grafischen Object 1,2,3... usw.

Ein Bild würde ich dann vom Panel erstellen. Z.B wie folgt:


     private void SaveAsBitmap()
        {
            Bitmap bmp = new Bitmap(base.Height, base.Width);
            using (Graphics _bgfx = Graphics.FromImage(bmp))
            {
                _bgfx.CopyFromScreen(base.Location, new Point(0, 0), base.Size);
                bmp.Save("");
            }
        }

08.01.2008 - 13:32 Uhr

Hürm... Okay.

Dann Schritt für Schritt 🙂

Also dein Problem besteht ja darin: Du besitzt ein paar super Schriftarten auf deinem Rechner. Die Schrift möchtest du z.B. für ein eigenes kleines Schreibprogramm nutzen. So wie in Word sollen nun diese Schriften auswählbar sein und auch dargestellt werden wenn der Endanwender diese verwendet.

Das Problem ist nun folgendes, nur weil du vielleicht den FontDialog sagst, haye ich habe da 5 neue Schriften die ich die wie ganz simple ausgedrückt (nur als Beispiel anzusehen) als Dialog.NeueTexte.AddRange(new object[] {„NeuerText1“, „NeuerText2“, „NeuerTExt3“,}) übergebe wird zwar die Liste der Auswählbaren Schriften erweitert. Und wie man das macht geht via ein paar Tricks. Aber bringen tut es rein gar nichts.

Denn sobald der Endanwender diese Schrift auswählt, käme ein Fehler. Den der Rechner des Endanwenders kennt diese Schrift nicht. Also, kann man folgendes machen. Entweder muss der Endanwender diese Schrift besitzen und bekommt sie dann sowieso in dem Dialog angezeigt oder er besitzt sie nicht und muss sie erst einmal installieren.

Der Code den ich gepostet habe, zeigt dir einen Weg ohne eine Installationsroutine schreiben zu müssen. Oder über System.IO.File.Copy() die Schrift hin und her zu kopieren das dann evtl. aufgrund der Systemberechtigung nicht einmal geht (weis ich grade nicht).

Der Code zeigt die eine Implementation die von Windows im GDI (Graphic Device Interface) "Framework" mitgeliefert wird. Diese erleichtert es dir eine Schrift innerhalb deines Programms auf einen Endanwender Rechner zu installieren. Dann brauchst auch nicht mehr den FontDialog anzufassen.

Dir reicht es also vollkommen aus, einfach aus deinem FONT Verzeichniss die Schrift herauszukopieren und diese dann via des Funktionsaufrufes AddFontResource(<FileName>) einzubinden und fertig.

08.01.2008 - 13:02 Uhr

Hrm, wüsste grade nichts schnelleres.. solange es nur darum geht den kompletten Baum durchzugehen.

08.01.2008 - 12:49 Uhr

Hrm, du wirst immer die Fonts Clientseitig installiert haben müssen um sie darzustellen.
Dazu machst nichts anderes als die Font aus dem Ordner zu kopieren sie als Resource in dein Projekt einzubinden und dir dann diesen Link anzusehen 😉

Was du brauchst:


 [DllImport("gdi32.dll")]
    static extern int AddFontResource(string lpFilename);

Sample Code:
Quasi wird hier das FontFile.fon auf die Anwendung gezogen, der Pfad wird als args[0] übergeben. Die Anweisung ob Hinzugefügt (add) oder Gelöscht (rem) werden soll gibt dann args[1] an. SendMessage gibt nur wieder das sich in den Fonts etwas getan hat, daher eine BROADCAST mitteilung:


 using System;
  using System.Collections.Generic;
  using System.Text;
  using System.IO;
  using System.Runtime.InteropServices;

  namespace FontResource
  {
    class Program
    {
    private static IntPtr HWND_BROADCAST = new IntPtr(0xffff);
    private static IntPtr HWND_TOP = new IntPtr(0);
    private static IntPtr HWND_BOTTOM = new IntPtr(1);
    private static IntPtr HWND_TOPMOST = new IntPtr(-1);
    private static IntPtr HWND_NOTOPMOST = new IntPtr(-2);
    private static IntPtr HWND_MESSAGE = new IntPtr(-3);

    [DllImport("gdi32.dll")]
    static extern int AddFontResource(string lpFilename);

    [DllImport("gdi32.dll")]
    static extern bool RemoveFontResource(string lpFileName);

    [DllImport("user32.dll",CharSet=CharSet.Auto)]
    private static extern int SendMessage(IntPtr hWnd, WindowsMessages wMsg, IntPtr wParam, IntPtr lParam);

    static void Main(string[] args)
    {
        if (args.Length < 2) { Usage(); return; }

        FileInfo fontFile = new FileInfo(args[1]);

        if (!fontFile.Exists)
        {
        Console.WriteLine("Font file not found.\n");
        Usage();
        return;
        }

        switch (args[0]) {
        case "add" :
            AddFontResource(args[1]);
            break;
        case "rem" :
            RemoveFontResource(args[1]);
            break;
        default :
            Usage();
            return;
        }

        //This version of SendMessage is a blocking call until all windows respond.
        long result = SendMessage(HWND_BROADCAST, WindowsMessages.WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero);

        Console.WriteLine(String.Format("WM_FONTCHANGE broadcast returned {0}", result));
    }

    public static void Usage()
    {
        Console.WriteLine("FontResource [add|rem] <font>");
        Console.WriteLine("\nAny changes will not persist a reboot - to do so, remove the font entry from the registry.");
    }

    public enum WindowsMessages
    {
        //Snipped for length - see the list of WM_ calls on this site.
    }

08.01.2008 - 12:43 Uhr

Richtig, darum nutzt mal zusätzlich einen Obfuscator . Dennoch verschlüsselt man zusätzlich die strings da etliche Resourcen oder leider auch strings nicht (bzw. nicht bei allen dieser Programme) Obfuscated werden.

08.01.2008 - 12:28 Uhr

Na ja, indem erst statische Methoden verwendest innerhalb eines Threads. Machen die meisten sowieso schon.

Sprich bei dem Beispiel :


static void Main()
        {
            Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
            Application.Run(new MainForm());
        }

public class MainForm: Form
    {
            public MainForm()
            {
                Class1.StaticFunction();
            }

    }

Und das hier eben nicht tust:


static void Main()
        {
             Class1.StaticFunction();
            Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
            Application.Run(new MainForm());
        }

08.01.2008 - 11:34 Uhr

Hallo Andreas.May,

naja, gerade statische Konstruktoren und Initialisierung werden u.U. eben nicht (direkt oder indirekt) aus dem Main heraus aufgerufen. Insofern ist Application.ThreadException zumindest zusätzlich nicht schlecht.

herbivore

Hrm, stimmt 🙂

08.01.2008 - 11:28 Uhr

Hrm, es gibt glaube ich Obfuscatoren (google: Obfuscator C#) die auch String Verschlüsseln sogar jene in Resourcen. Aber JuyJuka hat recht, das ist die gängigste Methode so etwas zu realisieren.

08.01.2008 - 11:22 Uhr

Hallo, danke für deine Antwort.

Ich habe eine Klasse mit statischen Membern, dazu gehört auch soetwas wie

  
public static meineKlasse dbWrapper = new meineKlasse();  
  

Diese Klasse wird ja nicht innerhalb der Main Methode aufgerufen.

Muss ich nun bei dem "statischen Instanziieren" ein try-catch Block in dem Constructor durchführen?

Nein musst gar nichts in der Richtung machen nur das beachten was herbivore schrieb. In Application.Run wird dein Thread innerhalb des Prozesses gestartet. Ergo egal an welcher stelle innerhalb "eines" Threads ein Fehler auftritt, landet dieser innerhalb des Trheadaufrufes.


static void Main(string[] args)
{
    Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
    if (VisualStyleRenderer.IsSupported && Application.RenderWithVisualStyles) Application.EnableVisualStyles();
    Application.Run(new winHauptmenue(args));
}

Wäre das nun immer bei Application.Run(new winHauptmenue(args)); Das was BerndFfm schrieb reicht also vollkommen aus.

Was ich meinte ist ein Loggin System. Sprich dein Programm bricht dann nicht ab und wird beendet beim auflaufen eines Fehlers sondern Dokumentiert diesen, der Benutzer ist gezwungen den Fehler zu senden aber das Programm läuft weiter. Inwiefern das Sinn macht ist unterschiedlich - die Frage muss man sich selbst beantworten.

08.01.2008 - 11:05 Uhr

Hrm,
würde zuerstmal eine Klasse erstellen die ich von Form ableite. Anschließend würde ich innerhalb dieser Klasse den Konstruktor private machen. Danach dann eine statische Methode wie ShowDialog schreiben die ca. so aussähe:


public static void ShowDialog(string _sErrMsg)
        {
            MyDialogClass wnd = new MyDialogClass ();
            wnd.m_sErrMsg = _sErrMsg;
            wnd.ShowDialog();
        }

Nun würde ich die Klasse dann so gestallten das sie wie der gewünschte Dialog aussieht und auch dort beim Senden ButtonEvent die Funktion aufrufen für den Emailverkehr. Soweit könntest du es dann wie herbivore schrieb abbilden.

Allerdings, solltest diesen auch fürs Loggin verwenden wollen, so würde ich mir diesen Artikel zusätzlich ansehen und versuchen das noch weiter über Aspektorientierte Programmierung abzubilden.

08.01.2008 - 10:19 Uhr

Hallo winSharp93 unter folgenden Link siehst du weitere Ansätze zu CustomBorders. Wichtig ist das SetWindowTheme mit einbindest, bei Dragons post solltest noch bedenken das noch ein paar Dinge rund machen musst aber der Großteil steht bereits.

Wichtig ist es jedesmal mit WindowMessages.WM_NCCALCSIZE die Größe des NonClientArea BEreichs neu zu berechnen. Und eben über WindowMessages.WM_NCPAINT den DeviceContect abzufragen um eben an den sichtbaren Bereich heran zu kommen (DCX_INTERSECTRGN) inklusive dem Rahmen (DCX_CLIPSIBLINGS) des Fensters (DCX_WINDOW) den Cache brauchst du dafür nicht zwangsläufig (also DCX_CACHE).

08.01.2008 - 10:07 Uhr

EDIT: ich? ich mußte leider (*grins) trotzdem ein eigenes entwickeln. das sollte ursprünglich mal weiterverkauft werden.

Pff...das Ding war doch gut 🙂

08.01.2008 - 10:00 Uhr

Hrm, okay ich denke an der stelle verlierst du keine Performance.

if (Objektliste.Count > 0) kannst dir spaaren da die foreach Schleife das schon übernimmt. Denk dran, je weniger Abfragen und Aufrufe desto mehr Performance bekommst du rein - Aber das ist nicht der Zeitkiller. Kannst du bitte vom Grafischen Object die Funktion DoYourJob() noch reinmachen - evtl ist dort ein Aufruf der zu viel Zeit kostet.

Ansonsten, egrath hat nicht unrecht aber eigentlich sollte das nicht nötig sein - zumindest nicht wenn mehrer tausende von Objecten darstellst.

07.01.2008 - 11:37 Uhr

Hrm,
ich würde das ganze erst einmal in einen Probeprojekt abhandeln indem ich erstmal keinerlei Berechnungen anstelle sondern nur ein Grafisches- Objekt gerade bewegen lasse indem x erhöhst. Anschließen würde ich die Formel nach für nach implementieren bis die Stelle gefunden hast in der mehr Zeit als 40ms verbrauchst.

Normal sollte die Berechnung von deinen vorangegangenen Thread nicht wirklich belastent sein. So das ich eher andere Fehlerquellen vermute - nur dazu brauche ich die Zeichenroutine von dir + Aufruf als Code zum sichten.

07.01.2008 - 11:17 Uhr

Hrm,
ich denke als Hobbyprogrammierer Fragen zu stellen ist kein Verbrechen.

Schlussendlich hat jeder erstmal Hobby mäßig mit dem Programmieren angefangen bevor er sich dazu entschlossen hat überhaupt den Beruf als Programmierer anzustreben.

Ich denke eher dass der Ton die Musik macht. Wie viele Vorposter schon meinten, solange man höflich und mit Interesse an der Sache nachfragt, ist keine Frage zu blöd um nicht gestellt zu werden.

Und was den Punkt angeht sich wissen anzulernen, ich denke Bücher sind sicher eine gute Hilfe aber die Praxis ist beweiten lehrreicher. Ich habe meistens Codestiele, Schreibweisen und Lösungen von Kollegen übernommen und versucht zu vereinfachen oder auf andere Problemstellungen anzuwenden um dazu zu lernen.

Angefangen habe ich mit dem Buch „Windows-Programmierung mit Visual C#“ von Charles Petzold. Und war danach auch kaum schlauer, erst nach etwas Praxis habe ich überhaupt verstanden von was so ungefähr die Rede ist 😉

07.01.2008 - 10:58 Uhr

Hrm, ich glaube das es nicht unbedingt nur am delegate liegt.

Die Frage die ich mir stelle wie lange braucht dieser Abschnitt?


PortSeriell.Write(position, 0, 6);

Und was macht befehl[4],befehl[5] usw..?
Führt das Kommandos aus?

04.01.2008 - 16:06 Uhr

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.start_game)
            {
                System.Drawing.Point l_Point = e.Location;
                this.bat_player1.Top = l_Point.Y - mouse_pos.Y;
                this.bat_player1.Left = l_Point.X - mouse_pos.X;
            }
        }

Versuch das mal 😉

PointToClient gibt dir die Mausposition innerhalb des Clientsbereichs des Steuerelemts (in deinen fall der Form) vom Bildschirm an. Und so wie ich das sehe, malst ja nur innerhalb des Clientsbereichs herum, also reichen dir die Mausposition vom Clientbereich aus. Wenn dem nicht so sein sollte, weil mich der Abschnitt Form1.MousePosition irritiert, bitte reinschreiben.

04.01.2008 - 13:51 Uhr

Hrm, am besten wäre hierfür das CommandPattern (Forum Suche: Action) Prinzip.

Wenn versuchst innerhalb eines MDI Containers Events von verschieden vielen Formularen abzuarbeiten wird das viel zu kompliziert.

Wichtiger ist das die Formulare vorgeben was der MDI Container überhaupt an Controls besitzen darf, wenn dieses den Focus besitzt. Mach deinen MDI Container zur Singleton, gebe z.B die Menüs nach aus. Wenn ein Form den zustand aktiviert besitzt lade die Menüs rein, wenn ein Form den Zustand deaktiviert besitzt dann lade dessen Menüs wieder heraus.

Die CommandPattern (Actions) machen nun Sinn da sich manche Menüaktionen wiederholen.

04.01.2008 - 13:36 Uhr

Hrm, versuche erstmal folgendes:


this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
//this.SetStyle(ControlStyles.UserPaint, true);

Lass das UserPaint zuerstmal weg und wenn es immer noch flackert machs mal rein.
Bzw. wieso sollte wegen this.DoubleBuffered = true; die Zeichenroutine nicht mehr gehen.

Vielleicht ist es besser etwas Code reinzuposten.

03.01.2008 - 22:30 Uhr

Hrm...


 public class MyTabControl : TabControl
    {

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetCursorPos(out Point lpPoint);

        private const int WM_MOUSEMOVE = 0x200;
        public event MouseEventHandler MouseMoveEx;

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == WM_MOUSEMOVE)
            {
                if (this.MouseMoveEx)
                {
                    // war zu faul sonst lparam oder wparam in nen mousestruct überführen
                    Point pt = Point.Empty;
                    GetCursorPos(out pt);
                    this.MouseMoveEx(this, new MouseEventArgs(MouseButtons.None, 0, pt.X, pt.Y, 0));
                }
            }
        }
    }


List<myGraphObj> myGraphics = new List<myGraphObj>();

private class myGraphObj
        {
            public Rectangle Rect;
            public Color Color;

            public bool IsAtPoint(Point pt)
            {
                return new Region(this.Rect).IsVisible(pt);
            }
        }

        public Form1()
        {
            InitializeComponent();
            this.tabControl1.MouseMoveEx += new MouseEventHandler(tabControl1_MouseMoveEx);
        }

        void tabControl1_MouseMoveEx(object sender, MouseEventArgs e)
        {
            // sollte die Suche beschleunigen... Ansonsten, es gibt noch viele andere Methoden dafür.
            myGraphObj obj = myGraphics.Find(delegate(myGraphObj _myObj) { return _myObj.IsAtPoint(e.Location); });

            if (obj != null)
            {
                obj.Color = Color.Blue;
                this.Invalidate(obj.Rect);
            }
        }

/ps
Habs nur rumkopiert, kann sein das evtl. noch Fehler drinnen sind. Aber die meckert dir dann der Compiler eh an. Aber schlussendlich, nach dem Grafischen Element musst soweiso suchen.

Du könntest dir auch ein Koordinatensystem aufbauen das dann Schachtelst in 2 Dimensionale Arrays, danach kannst du innerhalb eines Bereichs suchen.

Stell dir dazu einfach nen Gitternetz vor, hast du ein Object angelegt merkst du dir die Koordinaten des Gitternetzes. anhand der Position der Maus kannst du mit wenig Aufwand nun das Gitternetz bestimmen. Nun brauchst du nur noch die Liste für das entsprechende Gitternetz durchgehen in dem sich die Objecte befinden. Du machst quasi einen Index auf die Grafischen elemente. Statt nun 1000 Objecte durchzugehen brauchst dann evtl. nur noch 100 durchzugehen.

Hatte das z.B. mal gemacht kostet auch nicht so viel Zeit... 2-4 Tage ca.
Ausserdem war ich da ziemlich gut betrunken und schrieb den quatsch auf nen Bierdeckel (also ist es wenig). Nüchtern sollte das noch einfacher sein. Hat aber zur folge das evtl. ne menge umschreiben müsstest.

Ansonsten unter Artikel schauen, es gibt immer noch fiesere Typen hier im Forum 😉