Laden...
Avatar #avatar-3271.jpg
rollerfreak2 myCSharp.de - Member
Software Architekt Dabei seit 14.07.2008 916 Beiträge
Benutzerbeschreibung
Man lernt nie aus...

Forenbeiträge von rollerfreak2 Ingesamt 916 Beiträge

14.05.2009 - 10:28 Uhr

Die habe ich benutzt, nur sagen manche mit Abort den Thread abbrechen, und manche durch ein Flag....

14.05.2009 - 10:08 Uhr

Hallo zusammen, folgendes Scenario.
Ein Tool welche aus eine DB Daten ausliest, und die in der GUI auf DGV zur Anzeige bringt. Nun gibt es einen Start Button der nach betätigung zu End Button wird. Was passiert im Hintergrund:

Beim starten wird eine Thread angelegt, der die Aufgabe hat die DB auszulesen, und die Controls zu füllen. Gleichzeitig dient er dazu das die GUI nicht hängt und man einen Progressbar bedienen kann. Nun kann der Anwender aber auch auf End klicken. Wie beendet man den Thread sauber?

Mein Idee wäre ein Flag zu setzen "isaborted" und das zu anfang auf false setzen. Drückt der Anwender auf End dann wird das Flag auf true gesetzt.

Im Thread selber, bzw. in den Funktionen die der Thread dann alle aufruft, müsste ich dann immer uaf das Flag prüfen, und einfach via return aus der Funktion zurückspringen die der Thread aufgerufen hat. Ist das gängige Praxis, oder gibt es eine "sauberere" Lösung?

12.05.2009 - 23:08 Uhr

Ich habe hier ein DGV von Codeprojekt. Dieses würde ich gern nach bestimmten Columns Filtern. Das Outlookgrid wird an ein DataSet gebunden. Die DataSoucre wird durch einen eigenen DataSourceManager implementiert.

Allgemein kann man ja DGV die an DataSet gebunden sind Filtern


BindingSource source1 = new BindingSource();
source1.DataSource = view1;

// Set the data source for the DataGridView.
datagridview1.DataSource = source1;

source1.Filter = "id = '1'";

Nun ist aber das Problem das der DataSourceManager kein Filter hat. Gibt es eine andere Möglichkeit die Filterfunktion in das OutlookGrid einzubauen?
Oder kann man das in den DataSourceManager leicht hinzufügen?

Danke im vorraus

12.05.2009 - 17:14 Uhr

Das hat mir sehr geholfen, nur leider ergeben sich einige Probleme wenn man nur den Titelfont ändern will.


private const int WM_NCPAINT = 0x0085;

[DllImport( "user32.dll", SetLastError=true )]
private static extern IntPtr GetWindowDC( IntPtr handleWindow );

protected override void WndProc( ref Message m )
{
    base.WndProc(ref m);
    if (m.Msg == WM_NCPAINT)
    {
        DrawTitle(m.HWnd);
    }
}

private void DrawTitle( IntPtr handleWindow )
{
    Graphics gr = Graphics.FromHdc( GetWindowDC( handleWindow ) );
    //.....draw the new string
}

Das Funktioniert soweit. Man muss natürlich den form.Text auf string.empty setzen und einen neuen Zeichnen.

Dabei gibt es 2 Probleme

  1. Wenn man die Form ablegt und wieder maximiert wird der String ncith mehr gezeichnet. Daher muss ich mich noch an mehr msg hängen, weis aber nicht an welche.
  2. In der Taskbar wird jetzt natürlich nicht mehr der text dargestellt, weil ja string.empty.

Jetzt hatte ich versucht vor dem Aufruf der base.WndProc(ref m) Methode den form.Text auf leer zu setzen, und danach wieder zurück zu setzen. Problem ist das es dann ein StackOverflow gibt weil das Ändern der Eigenschaft sofort wieder zum Aufruf der WndProc führt.

Kann man das irgendwie verhindern, weil das wäre die Einfachste Lösung, denn dann würde alle so laufen wie vorher, nur in der Titelleiste würde mein eigener Titel (mit separaten Font) stehen...?

12.05.2009 - 15:28 Uhr

Besten Dank Jack30lena...

12.05.2009 - 15:12 Uhr

Gibt es eine Möglichkeit den Text der Titelleiste einer Form mit einem separaten Font darzustellen?

Vielleicht kann man sich ja auch irgendwie an das Zeichnen hängen, und selbst dafür sorgen, hab aber leider bis jetzt noch nix gefunden...

11.05.2009 - 15:10 Uhr

Das kann ich ausprobieren, vielleicht komm ich da dahinter.

Zum vorgehen aber noch mal allgemein: Mach ich da irgendwas falsch.

  1. Alle externen Assemblies in die Appl. mergen

  2. Alle unmanaged dll draußen lassen (kann man ja nicht mergen)

  3. Phoenix öffnen und einzig die exe auswählen (die externen dll's) wähl ich nicht mit aus (weil ja unmanaged und damit kein .NET)

  4. Protection starten

  5. In dem Ordner wo jetzt die "Protected" Appl. liegt alle externen Assemblies wieder hin kopieren sodass die erreichbar sind

  6. Appl. starten 😦 Absturz

-> Ich werd das später wenn ich die Appl. zur verfügung habe mal mit dem Debugger starten, nur stellt sich mir jetzt die Frage was das bringen soll, da sich ja die Methodenamen geändert habe, und ich somit nicht die "richtigen" sourcen habe...?

11.05.2009 - 14:42 Uhr

Es gibt keine genaue Fehlermeldung! Das heißt nach dem ich die Anwendung gestartet habe, (unter Vista Buisness 32Bit), kommt der übliche Dialog ("Die Anwendung Funktioniert nicht richtig") wie zum Beispiel hier. Mit dem Reflector hab ich noch nicht nachgeschaut, weil ich die Anwendung grad nicht hier hab.

Also mache ich erstmal nix falsch beim "fuscaten" mit dem Phoenix, oder gibt es da eine speziall Einstellung wenn man externe Library benutzt?

11.05.2009 - 13:11 Uhr

Ich hab mal eine Frage bezüglich des Phoenix und eines Assemblies welches gemerged wurde, daher 2 externe Assemblies wurden zusammen mit der eigentlichen exe gemerged. Jedoch enthält die exe auch noch eine externe dll welche nicht gemered werden kann, weil diese unmanaged Code enthält. Das heißt die exe hat 2 dll's integriert und eine externe und funkioniert ohne Probleme. Nun wollt ich das Assemblie mit dem Phoenix verschleiern, und hab als Source die exe ausgewählt. Der Vorgang wird auch erfolgreich beendet, nur wenn ich danach die exe starte, dann stürzt sie ab. Ich denk ich weis woran es liegt, kann es jedoch nicht verhindern.

Der Phoenix wird sicher auch die funktionen die von der externen dll gebraucht werden umbennen, und das darf es ja nicht. Das ist jedoch nur eine vermutung, noch nicht getestet. Hat einer von euch eine Idee was ich vielleicht falsch mache, bzw. woran es liegt wenn nicht am beschriebenen...?

thx

06.05.2009 - 14:06 Uhr

Danke für die Info. Jetzt weis ich auch mal wie das geht bzw. wie man so was machen kann...

06.05.2009 - 13:52 Uhr

Das stimmt allerdings. Ok das ergibt dann alles Sinn. Gut die freien Tools auf der Seite funktionieren alle nahezu gleich. Der ersetz token ist bei jedem Tool ein wenig anders. Ich bevorzuge den Phoenix, da er mit ILMerge zusammen bedienbar ist und so sehr komfortabel.

Noch mal zum Disassimblieren:

Ich hab in der Liste auch Tools gefunden, die 2000 $ kosten. Können diese das? Und wenn ja, wie machen die das im Detail. Weil der JIT Compiler zum Beispiel muss doch die Assemblies weiterhin in IL Code übersetzen können. D.h. jedes .NET Assembie muss wieder in .NET code Sourcecode zurück transformierbar sein, oder seh ich das falsch? Mich würde trotzdem mal interessieren wie die das machen im Falle die (Salamander .NET Protector etc.) können das...

06.05.2009 - 13:44 Uhr

Ich hab jetzt mal die freien Obfuscator ausprobiert und mir ist folgendes aufgefallen.

Alle beherschen das Umbenennen der Methodennamen und Vaiablennamen

Komischer weise werden einige Methoden nicht umbenant. Zum Beispiel OnPaint() oder einzellne überschriebene Eventmethoden. Variablennamen in den Methoden werdern nicht alle überschrieben bzw. geändert.

Welche Gründe hat das?

06.05.2009 - 13:29 Uhr

Stimmt das geht auch. Naja dann muss man wohl damit Leben.

Fazit: Der Phoenix tut seine Sache echt gut, verhindert zwar nicht das dissambly, jedoch erschwert er das lesen des Codes um ein Vielfaches.

@herbivore

Danke, das hatte ich auch schon überflogen. Bin grad noch auf eine Liste von freien Obfuscatoren gestoßen, und werd die alle mal ausprobieren. Den "Sieger" Poste ich dann hier...

06.05.2009 - 12:25 Uhr

Hier die Antwort auf das SuppressIldasmAttribut. Jetzt wird auch das öffnen der Assemblies mit dem .NET Reflector verhindert. Reflection wird nicht verhindert, allerdings bringt das auch nicht mehr so viel, weil der Phoenix sämtliche Methodennamen und variablennamen komplett vercrytet hat. Beides zusammen ein denke ich sehr guter Schutz vor "leichten" Code Klau 😃

[Edit:] Ein Frage hätte ich noch. Ich dachte der .NET Reflector benutzt zum disassemblieren den ildasm. Aber dies ist nicht der Fall. Kann ich auch noch das Disassemblieren via .NET Reflector für eine .dll oder .exe unterbinden?

06.05.2009 - 12:17 Uhr

Also der http://ntcore.com/phoenix.php ist echt sehr gut für ein free fuscator. Den kann ich nur empfehlen. Jetzt schau ich noch mal JAck30lena's Hinsweis an, sodass man mit dem Reflector gar nix mehr sieht. Wenn ich dazu was gefunden habe, poste ich das hier.

Besten Dank euch beiden erstmal.

06.05.2009 - 11:20 Uhr

Ich hab mal eine Frage bezüglich .NET Assemblies und des verschleiern dieser.
Ich hab den "DotFuscator" schon probiert. Der macht seine Sache ganz gut, und nennt so ziemlich alle Methoden um, und durch die Überladungen sieht der Code auch dämentsprechend undurchsichtig aus (wie gewünscht). Nun wöllt ich noch gern das ILDASM verhindern, sprich das disassemblieren von .Net sourcen (.exe|.dll). Dazu hab ich zum Beispiel dieses Tool gefunden http://www.eziriz.com/. Dieses ist aber leider nicht free. Ich suche nach einem freien Tool und hab dieses auch bis jetzt noch nicht gefunden.

Zum Schutz. Mir ist klar das so eine "verschlüsseltes" Programm mit ein bisschen Aufwand wieder in .NET code zurück transformierbar ist, aber wie gesagt mit AUFWAND. ICh denk mit beiden Sachen zusammen sollte man vor Code Klau gut geschützt sein.

04.05.2009 - 16:57 Uhr

So nun hab ich es fast komplett, nur eine Sache stört mich noch, und ich will einfach nicht kappieren warum.


class ResizeDGV : DataGridView
{
    private int OldWidth;
    private List<int> ColumnOffset;
    private List<int> ColumnValues;
    private bool BeginInit;
    private bool IgnoreColumnChange;

    public ResizeDGV()
    {
        this.OldWidth = this.Width;
        this.BeginInit = true;
        this.IgnoreColumnChange = false;
        this.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
        this.ColumnOffset = new List<int>();
        this.ColumnValues = new List<int>();
    }


    private void EndInit()
    {
        if (this.Columns.Count != this.ColumnOffset.Count)
        {
            for (int i = 0; i < ColumnCount; i++)
            {
                this.ColumnOffset.Add(0);
                this.ColumnValues.Add(0);
            }
        }
    }

    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        this.UpdateColumnWidth();
    }

    protected override void OnColumnWidthChanged(DataGridViewColumnEventArgs e)
    {
        base.OnColumnWidthChanged(e);
        if (!this.IgnoreColumnChange)
        {
            int dif = this.ColumnValues[e.Column.Index] - e.Column.Width;
            for (int i = 0; i < this.ColumnCount; i++)
            {
                if (i != e.Column.Index)
                {
                    ColumnOffset[i] += (int)dif / 3;
                }
            }
            UpdateColumnWidth();
        }
        if (BeginInit)
        {
            e.Column.MinimumWidth = e.Column.Width;
        }
        if (e.Column.Index == this.ColumnCount - 1 && BeginInit)
        {
            this.EndInit();
            BeginInit = false;
        }
    }

    public int GetMinMaxIndex(int direction, List<int> offset)
    {
        int index = 0;
        if (direction < 0)
        {
            int min = offset[0] + ColumnOffset[0];
            for (int i = 1; i < offset.Count; i++)
            {
                if (offset[i] + ColumnOffset[i] < min)
                {
                    index = i;
                    min = offset[i] + ColumnOffset[i];
                }
            }
        }
        else
        {
            int max = offset[0] + ColumnOffset[0];
            for (int i = 1; i < offset.Count; i++)
            {
                if (offset[i] + ColumnOffset[i] > max)
                {
                    index = i;
                    max = offset[i] + ColumnOffset[i];
                }
            }
        }
        return index;
    }

    public void UpdateColumnWidth()
    {
        try
        {
            IgnoreColumnChange = true;
            if (ColumnOffset.Count != this.Columns.Count)
            {
                EndInit();
            }
            List<int> offset = new List<int>();
            int direction = this.Width < this.OldWidth ? -1 : 1;
            int ColumnWidth = 0;
            for (int i = 0; i < this.ColumnCount; i++)
            {
                offset.Add(0);
                ColumnWidth += this.Columns[i].Width;
            }

            if ((this.Width - ColumnWidth > 0 && direction == 1) || (this.Width - ColumnWidth < 0 && direction == -1))
            {
                if (this.Parent != null)
                    this.Parent.Text = String.Format("columnwidth={0} | widht={1} | direction={2}", ColumnWidth, Width, direction);
                int dif = this.Width - ColumnWidth - 3;

                for (int i = 0; i < Math.Abs(dif); i++)
                {
                    int index = GetMinMaxIndex(dif * -1, offset);
                    if (this.ColumnOffset[index] + offset[index] + (dif / Math.Abs(dif)) > 0)
                    {
                        offset[index] += dif / Math.Abs(dif);
                    }
                }


                for (int i = 0; i < this.ColumnCount; i++)
                {
                    if (Columns[i].Width + offset[i] > Columns[i].MinimumWidth)
                    {
                        this.Columns[i].Width += offset[i];
                    }
                    if (this.ColumnOffset.Count != 0)
                    {
                        this.ColumnOffset[i] += offset[i];
                    }
                }
            }
            this.OldWidth = this.Width;
        }
        finally
        {
            this.IgnoreColumnChange = false;
            for (int i = 0; i < this.ColumnCount; i++)
            {
                this.ColumnValues[i] = this.Columns[i].Width;
            }
        }

    }

}

Wenn man das DGV vergrößert oder verkleinert dann passt alles. Wenn man manuell eine Column ändert dann auch. Nur dort funzen 1 Sache noch nicht.
Wenn man einer Column vergrößert dann passt sich auch die Scrollbar an, soweit korrekt. Nur wenn man jetzt das DGV verkleinert dann sollen die Columns solange nicht geändert werden wie halt eine Scrollbar zu sehen ist. Meiner Meinung nach müsste das die Zeile


if ((this.Width - ColumnWidth > 0 && direction == 1) || (this.Width - ColumnWidth < 0 && direction == -1))           

machen. Aber ich versteh nicht wieso das nicht geht...
Kann mir einer auf die Sprünge helfen?

04.05.2009 - 16:02 Uhr

Das Problem ist das dass nicht seqentiell abläuft. Daher wenn ich in der UpdateColumnWidth() was an den Columns ändere, dann kann es sein ich flieg sofort danach in den Event Handler dazu. Aber wenn man genau nachdenkt müsste das finally trotzdem ausgeführt werden.

Mir ist noch was anderes eingefallen, und zwar hab ich gecheckt ob das OnMouseUp() Event vor dem OnColumnWidthChanged() kommt. Dann kann ich nämlich im Up Event ein flag setzen und im Ende der OnColumnWidth wieder zurück setzen. Meine Frage jetzt, wenn es auf meinem System so ist, ist dass dann überall so, sprich kann ich mir sicher sein das dass Event immer vorher kommt?

04.05.2009 - 14:53 Uhr

Hier der Code. Bisher funzt es soweit nur das manuelle Ändern einer Column ist für mich nicht erkennbar.


class ResizeDGV : DataGridView
{
    private int oldwidth;
    private List<int> ColumnOffset;
    private bool BeginInit;
    
    public ResizeDGV()
    {
        this.oldwidth = this.Width;
        this.BeginInit = true;
        this.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
        this.ColumnOffset = new List<int>();
    }

    private void EndInit()
    {
        if (this.Columns.Count != this.ColumnOffset.Count)
        {
            for (int i = 0; i < ColumnCount; i++)
            {
                this.ColumnOffset.Add(0);
            }
        }
    }

    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        this.UpdateColumnWidth();
    }

    protected override void OnColumnWidthChanged(DataGridViewColumnEventArgs e)
    {
        base.OnColumnWidthChanged(e);
        if (BeginInit)
        {
            e.Column.MinimumWidth = e.Column.Width;
        }
        if (e.Column.Index == this.ColumnCount - 1 && BeginInit)
        {
            this.EndInit();
            BeginInit = false;
        }
    }

    public int GetMinMaxIndex(int direction, List<int> offset)
    {
        int index = 0;
        if (direction < 0)
        {
            int min = offset[0] + ColumnOffset[0];
            for (int i = 1; i < offset.Count; i++)
            {
                if (offset[i] + ColumnOffset[i] < min)
                {
                    index = i;
                    min = offset[i] + ColumnOffset[i];
                }
            }
        }
        else
        {
            int max = offset[0] + ColumnOffset[0];
            for (int i = 1; i < offset.Count; i++)
            {
                if (offset[i] + ColumnOffset[i] > max)
                {
                    index = i;
                    max = offset[i] + ColumnOffset[i];
                }
            }
        }
        return index;
    }

    public void UpdateColumnWidth()
    {
        if (ColumnOffset.Count != this.Columns.Count)
        {
            EndInit();
        }
        List<int> offset = new List<int>();
        int direction = this.Width < this.oldwidth ? -1 : 1;
        int ColumnWidth = 0;
        for (int i = 0; i < this.ColumnCount; i++)
        {
            offset.Add(0);
            ColumnWidth += this.Columns[i].Width;
        }

        if (!(ColumnWidth > this.Width && direction == 1))
        {
            int dif = this.Width - ColumnWidth - 3;
            
            for (int i = 0; i < Math.Abs(dif); i++)
            {
                int index = GetMinMaxIndex(dif * -1, offset);
                if (this.ColumnOffset[index] + offset[index] + (dif / Math.Abs(dif)) > 0)
                {
                    offset[index] += dif / Math.Abs(dif);
                }
            }


            for (int i = 0; i < this.ColumnCount; i++)
            {
                if (Columns[i].Width + offset[i] > Columns[i].MinimumWidth)
                {
                    this.Columns[i].Width += offset[i];
                }
                if (this.ColumnOffset.Count != 0)
                {
                    this.ColumnOffset[i] += offset[i];
                }
            }
        }
        this.oldwidth = this.Width;
    }

}

Im OnColumnWidthChanged Event kann ich leider nicht erkennen ob das durch das UpdateColumnWidth() hervorgerufen wurde oder durch eine Useraction. Dannn köönt ich nämlich die ColumnOffset List anpassen, und den offset der Verschiebung auf die Column drauf rechnen....

Versteht ihr was ich meine?

04.05.2009 - 14:12 Uhr

Ich hab eine Grundlegende Frage zu dem Autosize Column Mode. Ich möchte folgendes Verhalten haben, und hab leider keine Standard Lösung gefunden. Die eigenen Versuche beachten leider immer nicht alles 😦

Hier zum vorhaben. Ein DGV mit Bsw. 4 Columns. Die width jeder Column ist gesetzt und auch die MinWidth jeder Column.

  • Beim Init sollen alle Columns gleich vergrößert werden, sodass das GDV komplett (breite) gefüllt ist und keine Scrollbar hat. Ist die Summe der Minwidth jeder Column größer als die Width des GDV dann wird natürlich eine Scrollbar dargestellt.

  • Vergrößert der USer nun das DGV oder verkleinert er es, dann soll auch alle Columns gleichmäßig verkleinert werden. Selbes verhalten, wie beim Init. Spirch ist die Summe der Minwidth aller Columns größer als die Width des GDV dann wieder scrollbar.

  • Ändert nun aber der User händisch die Breite einer Column (es wird immer die linke Column angenommen) dann sollen sich alle anderen Column die zugefügte bzw. weggenommen Breite gleichmäßig teilen.

Ich hab schon einiges versucht nur leider klappt die Kompination aller Details nicht weil ich dann mich im Kreis drehe und die Handler sich gegenseitig aufrufen. Codebespiel folgt.

Ein weiteres kleines Problem was ich habe ist, wenn man das DGV nur um 1-2 Pixel vergrößert dann werdne immer wieder die ersten 2 Columns vergrößert und verkleinert. D.h. man muss sich auch noch merken welche offsets man verteilt hat.

Wenn einer schon irgendwas vergleichbares hat dann her damit. Ich stell dann gleich noch den Code rein, und bisschen erklärung was geht und was nicht.

04.05.2009 - 11:13 Uhr

Da wirst du wohl selber nachhelfen müssen. Du musst das OnPaint anpacken, und die RowHeaders selber malen. Dabei dann einfach das base.OnPaint() weg lassen und die Strings selber zeichnen.

04.05.2009 - 10:45 Uhr

Mit


this.dgv.RowHeaderVisible = false;

04.05.2009 - 09:37 Uhr

@seamonkey: Der weg ist nicht gut. Weil du dann immer Rundungs bzw. "Abschneide" Fehler bekommen wirst wie zum beispiel bei 4. Dort würde sich dann nach deiner Lösung keine Spalte ändern. Erst wenn der User das Fenster noch 1 Breiter macht.

Es gibt einen besseren und auch logischeren weg.

Du musst die Differenz gleich verteilen. Bzw. am "verteiltesten" verteilen 😃

Beispiel 4 Spalten und 7

1 Spalte +2
2 Spalte +2
3 Spalte +2
4 Spalte +1


class MyListView : ListView
{
    private int oldwidth;

    public MyListView()
    {
        this.oldwidth = this.Width;
    }

    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        int dif = this.Width - oldwidth;
        int count = this.Columns.Count;
        int columnwidth = 0;

        if (count != 0)
        {
            List<int> offset = new List<int>();
            for (int i = 0; i < count; i++)
            {
                offset.Add(0);
                columnwidth += this.Columns[i].Width;
            }

            if ((dif < 0 && this.Width < columnwidth + 4) ||(dif > 0 && this.Width > columnwidth + 3))
            {
                for (int i = 0; i < Math.Abs(dif); i++)
                {
                    offset[i % count] += Math.Abs(dif) / dif;
                }

                for (int i = 0; i < count; i++)
                {
                    this.Columns[i].Width += offset[i];
                }
            }
        }
        this.oldwidth = this.Width;
    }
}

Die Listview sollte es tun.

30.04.2009 - 12:46 Uhr

Ich versteh ehrlich gesagt das Problem nicht.

  1. Warum kann dein String so aussehen "aj32jkl"?
    Ich denke der User soll Zahlen eingeben, und kein Misch-Masch?

  2. Was willst du immer mit deinen delimiter? Die brauchst du doch gar nicht.

String.Length gibt dir die Länge des Strings zurück.
Und mit mystring[index] (Char) greifst du auf jedes einzellne Zeichen zu. Da kommt dann ein wert zwischen 0-255 zurück, wobei jeder Wert ein Zeichen representiert. Nun musst du nur noch bei jedem Zeichen schau, ob es eine Zahl ist, und dann addieren...

30.04.2009 - 12:35 Uhr

Jo das stimmt allerdings, du änderst die width der List ja nicht. Kleiner Denkfehler. Und das mit der 5 ist natürlich auch falsch gewesen, dort muss die dynamische länge rein.

30.04.2009 - 08:40 Uhr

Ich will ja nicht meckern, aber ich würde bevor ich die Spalten Größe ändere, den Eventhandler entkoppeln, sonst ruft der sich nämlich immer wieder selber auf.

das geht übrigens auch


for (int i = 0; i < list.Columns.Count; i++)
{
    list.Columns[i].Width = list.Width / 5 - (i == list.Count - 1 ? 3 : 0);
}

29.04.2009 - 14:40 Uhr

Du kannst auch einen nicht proportionallen Font benutzen, musst dann aber dir die Länge der Strings in Pixeln errechnen. Graphics.MessureString("bla", Font).Width

29.04.2009 - 14:26 Uhr

Weil heut Bergfest ist 😃


class BoldButton : Button 
{
    private string boldtext;

    public BoldButton()
    {
        this.boldtext = string.Empty;
    }

    protected override void OnPaint(PaintEventArgs pevent)
    {

        string text = this.Text;
        if (this.boldtext != string.Empty)
        {
            this.Text = string.Empty;
        }
        base.OnPaint(pevent);
        this.Text = text;

        Font boldfont = new Font(this.Font.FontFamily, this.Font.Size, FontStyle.Bold);
        int boldwidth = (int)pevent.Graphics.MeasureString(this.boldtext, boldfont).Width;
        int difwidth = (int)pevent.Graphics.MeasureString(this.boldtext, this.Font).Width;
        int originalwidth = (int)pevent.Graphics.MeasureString(this.Text, this.Font).Width;
        int newwidth = originalwidth - difwidth + boldwidth;
        int heigth = (int)pevent.Graphics.MeasureString(this.Text, this.Font).Height;
        int x = (this.Width - newwidth) / 2;
        int y = (this.Height - heigth) / 2;

        string str1 = this.Text.Substring(0, this.Text.IndexOf(this.boldtext));
        int width1 = (int)pevent.Graphics.MeasureString(str1, this.Font).Width;
        string str2 = this.BoldText;
        int width2 = (int)pevent.Graphics.MeasureString(str2, boldfont).Width;
        string str3 = this.Text.Substring(this.Text.IndexOf(this.boldtext) + this.BoldText.Length);
        
        if (this.boldtext != string.Empty)
        {
            pevent.Graphics.DrawString(str1, this.Font, Brushes.Black, new PointF(x, y));
            pevent.Graphics.DrawString(str2, boldfont, Brushes.Black, new PointF(x + width1, y));
            pevent.Graphics.DrawString(str3, this.Font, Brushes.Black, new PointF(x + width1 + width2, y));
        }

        boldfont.Dispose();
    }

    [DefaultValue("")]
    public string BoldText
    {
        get 
        { 
            return this.boldtext; 
        }
        set
        {
            if (this.Text.ToLower().Contains(value.ToLower()))
            {
                this.boldtext = value;
            }
        }
    }

}


Das sollte funzen. Nutzen kannst du den Button dann so...


this.button1.Text = "Klicken Sie jetzt nur einmal";
this.button1.BoldText = "jetzt";

Das müsste dann deinen gewünschten effekt hervorrufen.

Übrigens das base.OnPaint() brauch man zwecks des Hintergrundes. Nur muss man vorher den .Text auf leer setzen, und danach wieder zurück, sonst zeichnet es ja den original Text drüber...

29.04.2009 - 13:59 Uhr

Ich würde dir empfehlen selbst ein Control zu schreiben. Du lässt von Button erben. Dann überschreibst du dort die OnPaint() und unterbindest die base.OnPaint(). Dann nimmst du in der OnPaint dein zeichnen des Strings selber vor. Du kannst einfach mit Graphics.MessureString() die Breite des Strings mit dem entsprechenden Font prüfen und so die 3 Strings "klicken sie" "jetzt" (fett) "nur einmal" zentriert auf den button schreiben.

Du kannst das ganze auch bisschen benutzerfreundlich gestalten und zum Beispiel ein Attribut einfügen, in dem du den Fett zu machenden Text schreibst. BoldText zum Beispiel. Dann vergleichst du in deiner OnPaint() den Bold Text, und wenn der als SubString im Text enthalten ist, dann zeichenst du den Bold.

Das wären spontan meine Idee(n) dazu...

28.04.2009 - 09:11 Uhr

@Handycommander:

Das funzt so wirklich? Ich hab nämlich auch so ein Problem gehabt, und das nie wirklich weg bekommen. Ich hab eine Form mit einem TabControl, welches die Tabs selber zeichnet. In den Tabs hab ich DGV's die ich auch selber zeichne, sprich jede Menge eigener UserControls. Jetzt müsste ich sozu sagen in jedem UserControl die OnCreateControl überschreiben, und dort die Style's setzen?

Probier das heut gleich mal aus.

27.04.2009 - 16:06 Uhr

Ich würde dafür die Timer verwenden, und im Timer Event die gewünschte(n) Aktion(en) ausführen. Anschließend kannst du dann das TimerIntervall aktualisieren, somit hast du auch das dynamische Zeitverhalten mit drin.

27.04.2009 - 15:25 Uhr

Bitte schön, dafür ist das Forum ja da... 😃

27.04.2009 - 14:58 Uhr

Es sieht so aus als würdest du dich bei jedem Buttonklick erneut auf das Event anmelden (und das sogar 2 mal) den bei jedem weiteren Klick wird dein Code und damit dein Event 2 mal öfter ausgeführt.

27.04.2009 - 14:49 Uhr

class UnderlineLabel : System.Windows.Forms.Label
{
    public UnderlineLabel()
    {
        this.AutoSize = false;
        this.TextAlign = System.Drawing.ContentAlignment.TopLeft;
    }

    [DefaultValue(false)]
    public override bool AutoSize
    {
        get
        {
            return base.AutoSize;
        }
        set
        {
            base.AutoSize = value;
        }
    }

    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
        base.OnPaint(e);
        e.Graphics.DrawLine(Pens.Black, new Point(0, e.ClipRectangle.Bottom - 2), new Point(e.ClipRectangle.Right, e.ClipRectangle.Bottom - 2));
        e.Graphics.DrawLine(Pens.Gray, new Point(1, e.ClipRectangle.Bottom - 1), new Point(e.ClipRectangle.Right, e.ClipRectangle.Bottom - 1));


ich denk mal so was würde es tun...

27.04.2009 - 14:31 Uhr

Ich seh das auch wie Jack30lena,

einfach ein eigenes UnderlineLable was von Label erbt und dort die OnPaint Methode überschreiben und die Linie Zeichnen...

27.04.2009 - 14:27 Uhr

Ist mir schon klar das dass die Buisness Logic übernehmen sollte, das ungültige Werte abgefangen werden bzw. validiert werden, ich meinte ja nur, das es auch schon im GUI Layer verhindert werden könnte...

27.04.2009 - 12:45 Uhr

Nein das ist nicht egal. Weil wenn es eine Textbox wäre dann gebe es eine alternative die automatisch nur gültige Zahlen zulässt. Andernfalls kannst du die zahlen mit Int32.TryParse() und Double.TryParse() überprüfen und ggf. darauf reagieren.

27.04.2009 - 12:12 Uhr

Gehts ein bisschen genauer? Wo gibt man die Zahl ein? Textbox, Console....

24.04.2009 - 14:13 Uhr

Als erstes mal wenn man einen Tooltip anklickt, dann geht der sofort weg. Und zum zweiten, wenn du willst das wenn die Textbox im Writemode ist, sich dann ein Tooltip IMMER an einer Stelle befindet, dann frag ich micht wieso du kein Label nimmst?

22.04.2009 - 15:18 Uhr

Der Button hat ein eigenes KeyPress/KeyDown/KeyUp Event. Dort kannst du nach den Tasten filtern, und die Action abbrechen bzw. dein gewünschtes Control fokusieren.

16.04.2009 - 17:08 Uhr

Stelle in deiner Rechnen.cs ein event zu verfügung das du feuerst wenn sich der Wert geändert hat. In deiner MainForm.cs meldest du dich auf dieses Event an. Das ist eine saubere Kommunikation zwischen den beiden "Komponenten".

16.04.2009 - 08:57 Uhr

Ich würds selber zeichnen. Sprich erstell dir ein Control (Vertikal Label) und erbe von Label.

Dann vertauscht du die Höhe mit der Breite. Danach überschreibst du die OnPaint() und drehst deinen Graphic Kontext einfach um 90 grad um einen Punkt.


Matrix m = new Matrix();
m.RotateAt(this.angle, new PointF(x, y));
g.Transform = m;

g.DrawString(text, this.Font, Brushes.Black, x, y);
g.ResetTransform();

14.04.2009 - 13:56 Uhr

Sehr gute Lösung, hab ich gar nicht dran gedacht...

14.04.2009 - 13:38 Uhr

Ich kann mich dran errinnern das man im Studio im Debug Modus nur eine Inztanz deiner Application starten kann. Vielleicht ist dass das Problem.

14.04.2009 - 13:37 Uhr

Du kannst das draw_points nicht direkt aufrufen. Du kannst nur mit Invalidate dafür sorgen das es schnellst möglich aufgerufen wird. Schau dir mal an wie unter .NET Controls bzw. deren Oberfläche gezeichnet werden.

14.04.2009 - 13:28 Uhr

Ja das stimmt, vorallem weil ein Invalidate() nicht sofort die OnPaint Mehtode aufruft, sondern sich nur in die "Queue" fürs Zeichnen rein schreibt. Man könnte auch vor dem Invalidate prüfen ob der letzte invalidate schon ausgeführt wurde (boolsches Flag) und dann das neue Invalidate() unterbinden und nur den index erhöhen.

14.04.2009 - 13:24 Uhr

Wenn du einfach nur wissen willst ob sich an der stelle[x] eines strings eine "Ziffer" befindet, geht auch die Int32.TryParse(string s, out int number) Mehtode. Für mehrere Zahlen ist die von Jack30lena erwähnte regex Methode deutlich besser geeignet...

14.04.2009 - 13:14 Uhr

Eine möglichkeit die mir spontan einfällt wäre folgende. Du hast ja angenommen ein Array welches alle Punkte enthält. Nun kannst du dir eine index-variable anlegen die du mit 0 initialisierst.
Danach baust du dir ein Timer Event, das du aller 20ms feuerst. In der Methode dazu, erhöhst du jedesmal den index, und führst ein Invalidate deines Benutzersteuerelements aus. Im OnPaint() deines Benutzersteuerelements zeichnest du dann immer bis zum aktuellen index alle Punkte. Das müsste eigentlich funktionieren...

06.04.2009 - 14:04 Uhr

Zommi dein Tip hat geholfen, ich hab den Textrenderer mal auf AntiAlising gestellt und sieht deutlich besser aus. Besten Dank

06.04.2009 - 14:01 Uhr

Hier ein kleines Beispiel.

Font = new Font("Tahoma", 10, FontStyle.Bold);