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

05.03.2009 - 15:49 Uhr

Besser als die enums ist natürlich ein Interface zu definieren das dann die einpack und auspack funktion (aus und in die Registry) übernimmt und dann für jeden neuen Filter das Interface implementieren. Irgendwie so in der Art...

05.03.2009 - 15:23 Uhr

Also ich habs jetzt mal eben mit in die Registry gehauen. Das bereinigen ist auch einfach, nur den einen Key weg schmeißen der sich dann in CurrentUser/Software/ mit dem namen Calculator befindet. Ist bisschen Dirty mit die enums, aber so in der Art kann man das eventuell schnell implementieren und man kann dann eigene Filter definieren. Sprich wenn man Buttonfarben ändern kann usw....


public enum settingtype
{ 
    width,
    rectangle
}

/// <summary>
/// Manager for the application settings.
/// </summary>
class SettingsManager
{
    Form maincontrol;
    Dictionary<Object, Type> controllist;
    Dictionary<Object, settingtype> settinglist;
    List<object> datalist;

    /// <summary>
    /// Initializes a new instance of the <see cref="SettingsManager"/> class.
    /// </summary>
    /// <param name="maincontrol">The maincontrol.</param>
    public SettingsManager(Form maincontrol)
    {
        controllist = new Dictionary<object, Type>();
        controllist.Add(maincontrol, typeof(Form));
        datalist = new List<object>();
        settinglist = new Dictionary<object, settingtype>();
        this.maincontrol = maincontrol;
    }

    /// <summary>
    /// Loads the settings.
    /// </summary>
    public void LoadSettings()
    {
        ReadRegistry();
        if (datalist.Count != 0)
        {
            FindControls(this.maincontrol);
            int count = 0;
            IEnumerator e = this.controllist.GetEnumerator();

            while (e.MoveNext())
            {
                KeyValuePair<Object, Type> pair = (KeyValuePair<Object, Type>)e.Current;

                if ((Type)pair.Value == typeof(SplitContainer))
                {
                    SplitContainer sc = (SplitContainer)pair.Key;
                    sc.SplitterDistance = Int32.Parse(datalist[count].ToString());
                    count++;
                }
                if ((Type)pair.Value == typeof(Form))
                {
                    Form form = (Form)pair.Key;
                    Rectangle r = StringToRectangle(datalist[count].ToString());
                    //form.SetDesktopLocation(r.Left, r.Top);
                    form.SetDesktopBounds(r.Left, r.Top, r.Width, r.Height);
                    count++;
                }
            }
        }
    }

    /// <summary>
    /// Strings to rectangle.
    /// </summary>
    /// <param name="val">The val.</param>
    /// <returns></returns>
    private Rectangle StringToRectangle(string val)
    { 
        string[] split = val.Split(',');

        return new Rectangle(Int32.Parse(split[0]), Int32.Parse(split[1]), Int32.Parse(split[2]), Int32.Parse(split[3]));
    }

    /// <summary>
    /// Writes the registry.
    /// </summary>
    private void WriteRegistry()
    {
        RegistryKey regkey, tmp;
        int count = 0;
        regkey = Registry.CurrentUser.OpenSubKey("SOFTWARE", true);

        tmp = regkey.OpenSubKey("Calculator");

        if (tmp != null)
        {
            regkey.DeleteSubKeyTree("Calculator");
        }
        regkey = regkey.CreateSubKey("Calculator");

        IEnumerator e = this.settinglist.GetEnumerator();

        while (e.MoveNext())
        {
            KeyValuePair<Object, settingtype> pair = (KeyValuePair<Object, settingtype>)e.Current;

            string val = string.Empty;
            if (pair.Value.ToString() == settingtype.rectangle.ToString())
            { 
                Rectangle r = (Rectangle)pair.Key;
                val = String.Format("{0},{1},{2},{3}", r.Left, r.Top, r.Width, r.Height);
            }
            if (pair.Value.ToString() == settingtype.width.ToString())
            {
                val = pair.Key.ToString();
            }
            
            regkey.SetValue("#key_" + count.ToString(), val);
            count++;
        }

    }

    /// <summary>
    /// Loads the registry.
    /// </summary>
    private void ReadRegistry()
    {
        RegistryKey regkey;
        regkey = Registry.CurrentUser.OpenSubKey("SOFTWARE", true);

        regkey = regkey.OpenSubKey("Calculator");

        if (regkey != null)
        {
            for (int i = 0; i < regkey.ValueCount; i++)
            {
                datalist.Add(regkey.GetValue("#key_" + i.ToString()));
            }
        }
    }

    /// <summary>
    /// Saves the settigns.
    /// </summary>
    public void SaveSettigns()
    {
        FindControls(this.maincontrol);

        IEnumerator e = this.controllist.GetEnumerator();

        while (e.MoveNext())
        {
            KeyValuePair<object, Type> pair = (KeyValuePair<object, Type>)e.Current;

            if ((Type)pair.Value == typeof(SplitContainer))
            {
                SplitContainer sc = (SplitContainer)pair.Key;
                settinglist.Add(sc.SplitterDistance, settingtype.width);
            }
            if ((Type)pair.Value == typeof(Form))
            {
                Form form = (Form)pair.Key;
                settinglist.Add(form.Bounds, settingtype.rectangle);
            }

        }

        this.WriteRegistry();
    }

    /// <summary>
    /// Finds the controls.
    /// </summary>
    /// <param name="control">The control.</param>
    private void FindControls(Control control)
    {
        foreach (Control c in control.Controls)
        {
            if (c.Controls.Count != 0)
            {
                FindControls(c);
            }
            controllist.Add(c, c.GetType());
        }
    }
}


Und nun in der Form einfach nach dem Load die LoadSettings() aufrufen und in der OnFromClosing() die SaveSettings() aufrufen.


public Form1()
{
    InitializeComponent();
    settings = new SettingsManager(this);
    settings.LoadSettings();
}


protected override void OnFormClosing(FormClosingEventArgs e)
{
    settings = new SettingsManager(this);
    settings.SaveSettigns();
    base.OnFormClosing(e);
}

Wie gesagt quick and dirty kann man sicher besser machen...

05.03.2009 - 13:02 Uhr

Jepp habs mir grad mal angesehen. Ich glaub ich bastel mir mal was eigenes und poste das dann hier. Entweder ich knalle die paar Settings in eine xml datei oder in die registry in irgendein current_user_key. Wenn man es genau betrachtet sind das net so viele. Vielleicht 10-15 Einstellungen. Die werden dann einfach in der OnClosing() der Form gespeichert und in der FormLoad() geladen. Was meint ihr lieber in eine xml datei oder in die registry?

05.03.2009 - 12:56 Uhr

Da geb ich dir recht, viele haben Ihre Position weil sie viel und gut reden können, aber taten folgen lassen das bleibt dann schon mal aus. Im Fall von Köln wird der/die schludigen sicher noch zu rechenschaft gezogen.

Und soll ich dir jetzt schon sagen was raus kommt: Geldstrafe und das bezahlt dann noch die Firma....! So läuft es doch immer...

05.03.2009 - 12:26 Uhr

Ich hab mal eine Frage bezüglich des Speicherns und Ladens spezifischer Einstellungen einer Form. Z.b. splitter distance, colors, fonts etc. Ich hab ein Program mit ziemlich vielen solchen kleinen vom user Einstellbaren sachen wie oben erwähnt. Nun will der User ja nicht immer wieder seine appl. anpassen sondern beim laden soll der alte Zustand wieder her gestellt werden. Gibt es für solche Sachen ein vorgefertigte Klasse der man eine From in die Hand gibt und die rattert das durch und speichert dann alle Daten die man vielleicht sogar noch mit einem Filter einstellen kann? Oder ist es besser man macht das selber? Ich find im inet nicht wirklich was dazu, vielleicht auch weil ichj nicht richtig weis wie man das betiteln soll...

many thx

05.03.2009 - 12:16 Uhr

Ich würde ein bisschen vorsichtig sein mit deinen Äußerungen bezüglich 99% aller anderen Bücher. Hast du schon mal eines geschrieben um beurteilen zu können wie schwer bzw. leicht das ist?

Du nimmst den Mund ziemlich voll meiner Meinung nach.

Mein Tipp machs besser dann kannst die Klappe aufreisen...

05.03.2009 - 12:11 Uhr

Jo das keydown event hat die entsprechenden flags in den event args.

05.03.2009 - 11:22 Uhr

Das sollte gehen...


if (e.Modifiers == Keys.Control && e.KeyValue == 70)
{
    //sourcecode here
}            

03.03.2009 - 11:14 Uhr

So nach langem druchkämpfen hab ich den Fehler gefunden. Wie schon fast gar nicht anders möglich lag der Fehler in der Paint der OutlookGridRow. Und zwar wird das Icon und der Text hinter dem Icon der entsprechenden GroupRow in abhängigkeit der scrollbar gesetzt. Soweit klar. Nur wurde das auch bei dem Hintergrund und der horizontalen Linie gemacht. Und das ist ja gar nicht nötig wenn man die erst zeichnet.


// draw the background
graphics.FillRectangle(brush, rowBounds.Left + rowHeadersWidth  /*-grid.HorizontalScrollingOffset*/, rowBounds.Top, gridwidth, rowBounds.Height - 1);
//draw bottom line
graphics.FillRectangle(brush2, rowBounds.Left + rowHeadersWidth /*- grid.HorizontalScrollingOffset*/, rowBounds.Bottom - 2, gridwidth - 1, 2);


Und die schwarzen Balken entstanden bei mir unter Vista daher das er dort nichts gezeichnet hat, und daher schwarze balken waren.

So funzt es jetzt. Für alles die es interessiert der Fehler ist auch im Control auf CodeProject drin...

03.03.2009 - 09:24 Uhr

Ich konnte es reproduzieren. Ich hab mal ein Beispiel Projekt erstellt mit dem outlookgrid und ein myGrid welches davon erbt und hochgeladen. Dann kurz ein DataSet drüber gehauen und in eine Form rein. Mit Absicht die Columns ziemlich groß gemacht damit eine hscrollbar kommt. Wenn man nun bis ganz rechts scrollt und dann die vertikale scrollbar betätigt sieht man das dilema...! Ich weiß trotzdem noch nicht warum das passiert.

03.03.2009 - 09:02 Uhr

Noch zusätzlich das MyGrid befindet sich in einem SplittControll, dies sollte aber relativ egal sein. Mir scheint als könne der die GroupRows nicht richtig zeichnen, zumindest ab einer bestimmten spalten zahl, und zeichnet dann den Hintergrund schwarz. Wenn man zum Beispiel das OnCellPaint Event überschreibt und das base.cellpaint(e); auskommentiert kommt ein ähnlich Fehler. Dann werden alle Zellen scharz gezeichnet (halt im prinzip gar nicht). Ich Vertseh den Fehler einfach nicht. Was geht da nur schief...

02.03.2009 - 15:51 Uhr

Ich hab ein DataGridView mit welchem man Gruppierungen wie im ListView erstellen kann von der CodeProject Seite und auf meine Bedürfnisse angepasst. Nun habe ich es so umgestellt das ich ein Beispielprojekt gemacht habe bei dem ich ein DGV mit einem DataSet binde und ein paar gruppierungen mache. Das Funzt alles bestens. Nun wollt ich in einem anderen Projekt auf dieses (nennen wir es mal OutlookGrid) zurückgreifen. Also hab ich meine DGV's davon erben lassen. In diesen DGV selber ist einzig nur noch die OnCellPainting überschrieben um die Zellen anders dar zu stellen. Wenn ich nun die Anwendung starte passiert fogendes. Der Zustand der DGV ist der, das ein horizontasler Srollbar existiert, und ca. 4 Columns im nicht sichtbaren Bereich sind. Wenn ich nun den Scrollbar nach rechts bewege dann sind alle GroupRows aber der vorletzten Zelle schwarz. Verändere ich die Größe der DGV, sprich das die scrollbar verschwindet, dann sind die schwarzen flächen in den GroupRows weg. Zieh ich die wieder kleiner das dann wieder die schwarzen balken. Das eigenartige ist, das es für sich alleine stehend (also nur die OutlookGrid) geht, auch wenn das eine scrollbar ist. Nun in dem anderen Projekt nicht, obwohl ich an der darstellung der Grouprows überhaupt nix geändert habe.

wird damit ausgeschlossen


 protected override void PaintCells(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle rowBounds, int rowIndex, DataGridViewElementStates rowState, bool isFirstDisplayedRow, bool isLastVisibleRow, DataGridViewPaintParts paintParts)
        {
            if (!this.isGroupRow)
                base.PaintCells(graphics, clipBounds, rowBounds, rowIndex, rowState, isFirstDisplayedRow, isLastVisibleRow, paintParts);
        }

Das ist im OutlookGridRow welches von DataGridRow erbt. Hier noch mal kurz das Paint der Row an sich.


 protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle rowBounds, int rowIndex, DataGridViewElementStates rowState, bool isFirstDisplayedRow, bool isLastVisibleRow)
 {
     if (this.isGroupRow)
     {

         OutlookGrid grid = (OutlookGrid)this.DataGridView;
         int rowHeadersWidth = grid.RowHeadersVisible ? grid.RowHeadersWidth : 0;

         // this can be optimized
         Brush brush = new SolidBrush(grid.DefaultCellStyle.BackColor);
         Brush brush2 = new SolidBrush(Color.FromKnownColor(KnownColor.GradientActiveCaption));

         int gridwidth = grid.Columns.GetColumnsWidth(DataGridViewElementStates.Displayed);
         Rectangle rowBounds2 = grid.GetRowDisplayRectangle(this.Index, true);

         // draw the background
         graphics.FillRectangle(brush, rowBounds.Left + rowHeadersWidth - grid.HorizontalScrollingOffset, rowBounds.Top, gridwidth, rowBounds.Height - 1);
         
         // draw text, using the current grid font
         Font font = new Font(grid.Font, FontStyle.Bold);
         graphics.DrawString(group.Text, font, Brushes.Black, rowHeadersWidth - grid.HorizontalScrollingOffset + 23, rowBounds.Bottom - 20);
         font.Dispose();
         //draw bottom line
         graphics.FillRectangle(brush2, rowBounds.Left + rowHeadersWidth - grid.HorizontalScrollingOffset, rowBounds.Bottom - 2, gridwidth - 1, 2);
         
         // draw right vertical bar
         if (grid.CellBorderStyle == DataGridViewCellBorderStyle.SingleVertical || grid.CellBorderStyle == DataGridViewCellBorderStyle.Single)
             graphics.FillRectangle(brush2, rowBounds.Left + rowHeadersWidth - grid.HorizontalScrollingOffset + gridwidth - 1, rowBounds.Top, 1, rowBounds.Height);

         if (group.Collapsed)
         {
             if (grid.ExpandIcon != null)
                 graphics.DrawImage(grid.ExpandIcon, rowBounds.Left + rowHeadersWidth - grid.HorizontalScrollingOffset + 4, rowBounds.Bottom - 18, 11, 11);
         }
         else
         {
             if (grid.CollapseIcon != null)
                 graphics.DrawImage(grid.CollapseIcon, rowBounds.Left + rowHeadersWidth - grid.HorizontalScrollingOffset + 4, rowBounds.Bottom - 18, 11, 11);
         }
         brush.Dispose();
         brush2.Dispose();
     }
     base.Paint(graphics, clipBounds, rowBounds, rowIndex, rowState, isFirstDisplayedRow, isLastVisibleRow);

 }


Ich hab oben die Brushes auch mal auf eine feste Farbe gestellt, selbes Problem. Weder im Debug noch im Release mode verschwinden die schwarzen balken.

Zusammengefasst: OutlookGrid stand alone funzt bestens
Eine myOutlookGrid in einer anderen Anwendung was davon erbt und die OnCellPaint methode überscheibt verhält sich wie oben beschrieben. Ich kann mir das überhaupt nicht erklären, aber vielleicht weiß einer von euch an was das liegen kann. Den Code des DGV's welches von outlookGrid erbt reiche ich noch nach, den hab ich grad net zur Hand, aber wiegesagt der macht rein gar nix an dem OutlookGrid selber, bzw an der outlookRow. Er überscheibt nur dieses eine OnCellPaint Event/Mehtode. Danke im vorraus...

26.02.2009 - 17:28 Uhr

Das Problem ist das der Content innerhalb neu berechnet werden muss. Am einfachsten du stößt das damit an.


((DataGridView)sender).Rows[0].Visible = !((DataGridView)sender).Rows[0].Visible;
((DataGridView)sender).Rows[0].Visible = !((DataGridView)sender).Rows[0].Visible;

Das solltest du am Ende der foreach schleife ausführen. Dann sollte es den Inhalt wieder korrekt anzeigen.

26.02.2009 - 17:09 Uhr

Ich habe mal eine Frage bezüglich der Einstellungen einer DGV. Ich hab Sie so konfiguriert das sie als AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill bekommt. Nun wollt ich aber trotzdem die Möglichkeit haben die columns Resizen, sprich einzelne Spalten größer oder kleiner machen. Das geht aber leider net, sprich das Control lässt es nicht zu.


this.dgv.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
this.dgv.GridColor = System.Drawing.SystemColors.Control;
this.dgv.RowTemplate.Height = 19;            
this.dgv.BackgroundColor = System.Drawing.SystemColors.Window;
this.dgv.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal;
this.dgv.RowHeadersVisible = false;
this.dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
this.dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
this.dgv.MultiSelect = false;
this.dgv.AllowUserToAddRows = false;
this.dgv.AllowUserToDeleteRows = false;
this.dgv.AllowUserToResizeRows = false;
this.dgv.AllowUserToResizeColumns = true;
this.dgv.EditMode = DataGridViewEditMode.EditProgrammatically;

So sind meine Einstellung, rein vom überlegen her müsste es ja gehen. Gibt es eine Möglichkeit die Columns auf Fill zu stellen aber das resizen der Columns trotzdem zu erlauben?

26.02.2009 - 15:17 Uhr

Weis jetzt warums nicht gegangen ist. Man muss das


protected override void OnMeasureItem(MeasureItemEventArgs e)
        {
            e.ItemHeight = 20;
            e.ItemWidth = 100;
            base.OnMeasureItem(e);
        }

Überschreiben und dem Item sagen wie groß es sein soll. Dann funzt es bestens. Werd mal bisschen rum spielen. Danke für eue Hilfe...

26.02.2009 - 14:03 Uhr

Okay ich habe einen neuen Ansatz der deutlich Sinnvoller erscheint. Und zwar zeichnet es das ContextMenu ja schon nur fehlen da die Icons. Also hab ich versucht mal die MenuItem klasse zu überschreiben. wie folgt.


 class MyItem : MenuItem
    {
        public MyItem(string text)
        {
            this.Text = text;
            this.OwnerDraw = true;
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            base.OnDrawItem(e);
            e.Graphics.FillRectangle(Brushes.Red, 50, 50, 100, 100);
            
        }

    }

    //der aufruf aus einer Form heraus

    ContextMenu m = new ContextMenu();
    m.MenuItems.Add(new MyItem("test1"));
    m.MenuItems.Add(new MyItem("test2"));
    m.Show(this, e.Location);


Das Problem ist es wird kein Rechteck gezeichnet. Nur eine kganz kleines was wahrscheinlich das OnPoint der ContextMenu klasse macht. Dieser weg wäre deutlich besser da ich mich um die ganzen eventsachen nicht mehr kümmern muss. Allerdings müsste ich dazu zeichnen können, bin aber zu blöde zu...

26.02.2009 - 13:46 Uhr

Also wenn ich micht von ContextMenu ableite dann gibt es weder ein SetStyle noch kann ich da eine OnPaint Mehtode überschreiben. Wenn ich mich von Control ableite und nur ein Rechteck mal ein will dann geht das auch nicht. Ich schreib mal kurz wie ich das versucht habe.


class popupmenu : Control
    {
        public popupmenu(Point Location)
        {
            this.SetStyle(ControlStyles.UserPaint, true);
            this.Width = 100;
            this.Height = 100;
            this.Location = Location;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.FillRectangle(Brushes.Red, this.Bounds);
            base.OnPaint(e);
        }

Wenn ich das nun so aufrufe


popupmenu menu = new popupmenu(new Point(10,10));

sollte es eigenbtlich ein Rechteck malen bei Punkt 10,10 mit größe 100,100. Tut es aber nicht. Auch ein menu.Sjow() birngt nix. Es geht auch nicht in die OnPaint Methode. Es kann doch nicht so schwer sein, was mache ich nur falsch

26.02.2009 - 13:32 Uhr

Jo das ist eine gute Idee, ich hatte das ja schon versucht nur leider hatte das ContextMenü kein ownerdraw proberty. Aber this.SetStyle(ControlStyles.UserPaint, true); sollte es ja gehen. Werd mal schnell versuchen und dann mal posten was ich habe. Ich lad mal eben ein bild hoch wie ich das ContextMenü gern haben möchte...

26.02.2009 - 13:11 Uhr

Okay also leite ich mich jetzt von Control ab. Nun hab ich folgendes Problem. Ich will erstmal nur realisieren das ich ein Rechteck male. Im prinzip soll aus einer Anwendung heraus das Control aufgerufen werden. Das hat zur folge das eine Instanz erzeugt wird und das Rechteck gemalt wird. Klickt man den diesen Bereich passiert später etwas, klickt man außerhalb des Rechteckes dann verschwindet es, sprich das Control wird geschlossen. Ich bekomm es aber nicht hin was zu zeichnen. Wenn ichd ie OnPaint Methode überschreibe dann passiert nix. Das heißt ich lande nie dort drin. Könnt erklären wie ich ein Zeichnen realisiere (wohlgemerkt nur in dem Control) also nicht in der Unterliegenden Form?

25.02.2009 - 17:18 Uhr

Schau mal das du die entsprechende Zelle erst in Ihren typ castest, und dir dann das entsprechende value holst.


string val = ((DataGridViewComboBoxCell)row.Cells[j]).Value.ToString();

Probiers mal aus.

25.02.2009 - 17:11 Uhr

Ich weiß, ich wollt ja auch hauptsächlich verdeutlichen wie man mit datatables umgeht...

25.02.2009 - 16:57 Uhr

Ich habe vor ein eigenes Kontextmenü zu bauen, das ein bisschen ansprechener als das ContextMenu aussieht. Rounded Canvas etc.

Es soll relativ einfach gehalten sein, sprich beim erzeugen eine Liste mit Icons und text geben und dann soll es erschein. Beispielsweise bei einem Rechtsklick. Klickt man dann woanders hin, soll es verschwinden, klickt man auf ein Item (kann man in der klasse dann triggern) soll es ebenfalls verschwinden aber ein index oder ähnbliches zurückgeben. Nun wollt ich wissen von was ich mich am besten ableite, sodass ein Zeichnen relativ einfach ist. Hat einer vcon euch sowas ähnliches schon mal gemacht oder hat eine Idee wie ich am besten anfange? Oder sogar ein Beispiel?

25.02.2009 - 16:07 Uhr

Den Fehler hab ich gefunden, ist mir aber komisch. Und zwar hab ich alle


Rows[0].Visible = !Rows[0].Visible;
Rows[0].Visible = !Rows[0].Visible;

durch


Invalidate();

ausgetauscht. Durch das zusammenklappen muss die scrollbar neu berechnet werden, und das Invalidate veranlasst nur ein neu Zeichnen. Ich glaub das ist der Fehler, zumindets gehts jetzt.

Nur dadurch ergibt sich ein kleines Problem. Und zwar klickt man nun auf ein ExpandIcon dann ändert sich dadurch nach dem klciken die position dieses Icons da der gesamte Inhalt neu berechnet wird und auch die scrollbar ihren Größe ändert. Kann man die scrollbar irgendwie setzen? Sodass die position wieder stimmt? Sonst wundert der User sich nämlich warum nach dem klicken der Mauszeiger wo anders ist... 😃

25.02.2009 - 15:40 Uhr

Ich hab jetzt mal bisschen rum gespielt, und hab ein Problem das ich einfach nicht verstehe. Die DGV bekommt jetzt für jede Column eine eigene Sorteigenschaft und wird dann auch anhand dieser richtig Sortiert. Hab dann noch ein ContextMenü eingebaut, mit dem man die Gruppen löschen, expanden und collapsen kann. Nun zu dem Problem wenn ich die Items Collapse dann spinnt die anzeige, sprich der Content wird nicht mehr richtig gezeichnet. Wenn ich sie einzeln Collapse dann geht das nur bei den obersten. Wenn ich alle expande wird es wieder normal gezeichnet. Ich hab das jetzt schon etliche male durchdebugged nur find ich den fehler leider nicht. Kann mal einer von euch rein gucken, vielleicht wisst ihr ja was ich falsch mache...

Ich habs mal dran gehangen...

Vielen Dank im vorraus

24.02.2009 - 17:39 Uhr

Jo danke, ich werds gleich mal implementieren.

24.02.2009 - 17:25 Uhr

Das ist ja grad das problem. Mit fehlt die Idee. Beim alphabetischen sortieren ist es ja einfach weil das Kriterium IMMER DAS GLEICHE ist. Und zwar vergleiche das erste Zeichen der Namen miteinander.

Aber bei mir ändert sich das Kriterium ja bezüglich der entfernung zum Referenz Datum. Ich hätte die Idee dann enum zu machen und jedes Datum damit zu vergleichen. Dann muss ich das Kriterium immer zugänglich machen da jedesmal damit verglichen werden muss. Ändert sich dieses dann fängt eine neue Gruppe an, und das Kriterium muss auf das aktuelle gesetzt werden z.b. letzer Monat. Wenn ein Datum dafür nicht mehr passt, dann neue Gruppe und Kriterium auf letztes Jahr setzen. Ich find das bisschen umständlich, oder habt ihr eine andere Idee?

24.02.2009 - 17:11 Uhr

Hallo zusammen, ich habe ein kleines Denkproblem bei meinem folgenden vorhaben. Vielleicht kennt der eine oder andere dieses Grid OutlookGrid.

Ich möchte ein DateComparer schreiben in der Art:
Es wird ein ReferenceDatum Hinterlegt, im allgemeinen ist das dass aktuelle Datum. Dann soll die Gruppierung wie folgt vorgenommen werden.

->diese Woche
->letzte Woche
->diesen Monat
->letzten Monat
->dieses Jahr
->früher

Als Beispiel hier mal die Alphabetische Sortierung sprich nach dem Anfangsbuchstaben also alle mit A in Gruppe A usw.


public class OutlookGridAlphabeticGroup : OutlookgGridDefaultGroup
    {
        public OutlookGridAlphabeticGroup()
            : base()
        {
            
        }

        public override string Text
        {
            get
            {
                return string.Format("Alphabetic: {1} ({2})", column.HeaderText, Value.ToString(), itemCount == 1 ? "1 item" : itemCount.ToString() + " items");
            }
            set { text = value; }
        }

        public override object Value
        {
            get { return val; }
            set { val = value.ToString().Substring(0,1).ToUpper(); }
        }

        #region ICloneable Members
        /// <summary>
        /// each group class must implement the clone function
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            OutlookGridAlphabeticGroup gr = new OutlookGridAlphabeticGroup();
            gr.column = this.column;
            gr.val = this.val;
            gr.collapsed = this.collapsed;
            gr.text = this.text;
            gr.height = this.height;
            return gr;
        }

        #endregion

        #region IComparable Members
        /// <summary>
        /// overide the CompareTo, so only the first character is compared, instead of the whole string
        /// this will result in classifying each item into a letter of the Alphabet.
        /// for instance, this is usefull when grouping names, they will be categorized under the letters A, B, C etc..
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override int CompareTo(object obj)
        {
            return string.Compare(val.ToString(), obj.ToString().Substring(0, 1).ToUpper());
        }

        #endregion IComparable Members


Dieser Gruppierer wird dann an das Control gebunden.


outlookGrid1.GroupTemplate = new OutlookGridAlphabeticGroup();
outlookGrid1.GroupTemplate.Collapsed = prevGroup.Collapsed;
// set the column to be grouped
// this must always be done before sorting
outlookGrid1.GroupTemplate.Column = outlookGrid1.Columns[e.ColumnIndex];
// execute the sort, arrange and group function
outlookGrid1.Sort(new DataRowComparer(e.ColumnIndex, direction));

Der DataRowComparer der die einzellnen Rows vergleicht sieht dann so aus.


public class DataRowComparer : IComparer
    {
        ListSortDirection direction;
        int columnIndex;

        public DataRowComparer(int columnIndex, ListSortDirection direction)
        {
            this.columnIndex = columnIndex;
            this.direction = direction;
        }

        #region IComparer Members

        public int Compare(object x, object y)
        {

            DataRow obj1 = (DataRow)x;
            DataRow obj2 = (DataRow)y;
            return string.Compare(obj1[columnIndex].ToString(), obj2[columnIndex].ToString()) * (direction == ListSortDirection.Ascending ? 1 : -1);
        }
        #endregion
    }

Das dass funktioniert leuchtet mir nicht ganz ein. Der Aufruf von Sort(..) hat doch ersteinmal zur Folge das alle Rows sortiert werden. Danach wird der gruppierer Aufgerufen. Dieser wird vom FillGrid() Aufgerufen.


private void FillGrid(IOutlookGridGroup groupingStyle)
        {

            ArrayList list;
            OutlookGridRow row;

            this.Rows.Clear();

            // start filling the grid
            if (dataSource == null) 
                return; 
            else
                list = dataSource.Rows;
            if (list.Count <= 0) return;

            // this block is used of grouping is turned off
            // this will simply list all attributes of each object in the list
            if (groupingStyle == null)
            {
                foreach (DataSourceRow r in list)
                {
                    row = (OutlookGridRow) this.RowTemplate.Clone(); 
                    foreach (object val in r)
                    {
                        DataGridViewCell cell = new DataGridViewTextBoxCell();
                        cell.Value = val.ToString();
                        row.Cells.Add(cell);
                    }
                    Rows.Add(row);
                }
            }

            // this block is used when grouping is used
            // items in the list must be sorted, and then they will automatically be grouped
            else
            {
                IOutlookGridGroup groupCur = null;
                object result = null;
                int counter = 0; // counts number of items in the group

                foreach (DataSourceRow r in list)
                {
                    row = (OutlookGridRow)this.RowTemplate.Clone();
                    result = r[groupingStyle.Column.Index];
                    if (groupCur != null && groupCur.CompareTo(result) == 0) // item is part of the group
                    {
                        row.Group = groupCur;
                        counter++;
                    }
                    else // item is not part of the group, so create new group
                    {
                        if (groupCur != null)
                            groupCur.ItemCount = counter;

                        groupCur = (IOutlookGridGroup)groupingStyle.Clone(); // init
                        groupCur.Value = result;
                        row.Group = groupCur;
                        row.IsGroupRow = true;
                        row.Height = groupCur.Height;
                        row.CreateCells(this, groupCur.Value);
                        Rows.Add(row);

                        // add content row after this
                        row = (OutlookGridRow)this.RowTemplate.Clone();
                        row.Group = groupCur;
                        counter = 1; // reset counter for next group
                    }


                    foreach (object obj in r)
                    {
                        DataGridViewCell cell = new DataGridViewTextBoxCell();
                        cell.Value = obj.ToString();
                        row.Cells.Add(cell);
                    }
                    Rows.Add(row);
                    groupCur.ItemCount = counter;
                }
            }

        }
        #endregion Grid Fill functions

Jetzt kommt mein Problem. Ich steh ein bisschen auf dem Schlauch, weil ich nicht ganz weis wie ich das jetzt machen soll. Der FillGrid geht doch durch alle Rows durch und fängt dann immer eine neue Gruppierung an wenn der vergleich mit result nicht mehr stimmt. Hat einer von euch eine Idee wie ich mein vorhaben am besten umsetzten kann oder eventuell eine fertige Lösung?

23.02.2009 - 16:26 Uhr

Falls du nicht weiß wie man mit DataTable umgeht hier ein Beispiel.


//DataGridView instance is called dgv for these example
DataTable table = new DataTable();
//copy columns to datatable
foreach (DataGridViewColumn column in dgv.Columns)
{
    table.Columns.Add(column.Name);
}

//take all rows of the dgv
foreach (DataGridViewRow row in d.Rows)
{
    List<object> tmp = new List<object>();
    //insert each cell into the list
    foreach (DataGridViewCell cell in row.Cells)
    {
        tmp.Add(cell.Value);
    }
    //insert the copied list to the datatable
    table.Rows.Add(tmp.ToArray());
}

//this is a how to act a value
object value = table.Rows[0]["columnname"];
//or
object value = table.Rows[0][1];

19.02.2009 - 09:32 Uhr

Ok war auch nur ne Idee. Aber logischer weis darf das auch nicht gehen.

Bentutz sonst nur Datenbanken, allein dieses eine Problem hat zur Quelle eine Excel Datei und ich darf/kann das auch nicht in eine DB importieren. Von daher ist nur temporär das mit dem excel.

Eine Frage noch. Wenn man ein Select Statement macht und man will nur alle Rows ab Rowcount > 40 wie ist da die Syntax?

SELECT * FROM [ExcelSheet$] WHERE xxx > 6;

18.02.2009 - 15:16 Uhr

Für alle die es interessiert, ich hab den grund gefunden.

Die ersten 4 Zeilen meines Excel Files sind überschriften bzw. dienen dem Aufrufen der Makros durch dropdown boxen. Danach folgen dann die Daten. Liest man nun mit Oledb ein, dann nimmt er wahrscheinlich den ersten Record der die Select Statement erfüllt und verteilt anhand dieser die Typen für die entsprechenden Spalten. Da aber double als Daten vorliegen, in der "Überschrift" aber Text ist, kommt er da wahrscheinlich nicht zurecht.

Man kann das jetzt umgehen in dem man einfach erst bei den Daten beginnt auszulesen. Das finde ich aber nicht toll, den wenn sich mal jemand entscheidet die Überschriften zu ändern, oder eine Zeile einzufügen, dann klappt das wieder nicht.

Schöner wäre es beim Select Statement jeder Column einen Typ zu verpassen.

irgendwie so


command = "SELECT F1 (Double), F2 (char(255)) FROM [ExcelSheet$];";

Der Syntax geht aber nicht, bzw. ich weis gar nicht ob das überhaupt so geht. Unter der Hilfe findet man leider nicht viel dazu. Hat einer von euch Ahnung davon und weiß ob man das so ähnlich machen kann.

THX

17.02.2009 - 14:05 Uhr

Das eine hat nix mit dem anderen zu tun. In dem anderen Thread wollte ich nur wissen ob man die Spalten auch anders ansprechen kann, also nicht mit F1,F2 etc. sondern mit dem in Excel angezeigten Spaltennamen A, B, C, ect.

Zu dem Problem in diesem Thread, es ist komisch das im Excel was angezeigt wird für eine bestimmt Spalte, und mit Oledb ist diese Spalte dann leer? Komisch auch noch ist, wenn ich in diesen Spalten Text, also keine Ziffern eintrage, dann plötzlich liest Oledb die richtigen inhalte. Aber wenn ich nur ziffern Eintrage, dann nicht. Wie gesagt überhalb der Spalte im Excel ist ein dropdown button in dem man dann nach den ziffern sortieren kann. Es sind auch weitere macros enthalen und noch weiter excelsheets in dem file. Kann das leider nicht hoch laden, da geschützes Dokument.

Mir ist das einfach ein Rätsel. Den wenn ich die Spalte markiere dann zeigt der oben ganz klar Daten an im excel, und Oledb leist nix.

Kann mir da einer helfen?

17.02.2009 - 13:40 Uhr

verwendetes Datenbanksystem: <Oledb>

Quelle ist ein Excel file mit mehreren Spalten. In der Spalte G ist jeweils eine Zahl zwischen 1 und 10 eingetragen und kann über eine interens Makro gefiltert werden.

Nun möchte ich diese Daten auslesen, und stoße auf eine Problem. Wenn ich die Spalte G auslese erhalte ich immer isDBNull(index) => true, obwohl diese Spalte in jeder Zeile mit einer Zahl gefüllt ist Ich versteh nicht warum, den wenn ich das File mit excel öffne, dann stehen dort Zahlen. Les ich jetzt genau diese Spalte aus, dann sind alles rows leer.

Was ist da los, bzw. weiß einer woran das liegen kann.

17.02.2009 - 10:15 Uhr

verwendetes Datenbanksystem: <OleDb>

Ich habe ein Excel File welches aus mehreren Spalten besteht. Außerdem ist ein makro enthalten welches aber hier keine Rolle spielt, ist nur mit erwähnt. Nun möchte ich z.b. die Spalte B und C auslesen.

Das kann man mit F2 und F3 machen also


 OleDbConnection excelConnetion = new OleDbConnection();
            excelConnetion.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" +
                "Data Source=" + filepath + ";" +
                "Extended Properties=Excel 8.0;";

            OleDbCommand excelCommand = new OleDbCommand("SELECT F2, F3 FROM [TableSheet$]", excelConnetion);

            try
            {
                excelConnetion.Open();
                OleDbDataReader reader = excelCommand.ExecuteReader();
            }

Wie kann ich aber die Spalten mit den Bezeichner A, B, C etc. ansprechen?

11.02.2009 - 15:27 Uhr

Ich habe den Fehler jetzt lokalisiert. Ich hab mir das Teil jetzt so umgebaut das ich dort auch entsprechene File auf Copy Local stellen kann, und die vom mergen ausgeschlossen werden. Dazu kann man

<CreateItem Include="@(ReferencePath)" Condition="'%(CopyLocal)'=='true' and '%(ReferencePath.FileName)'!='System.Data.SQLite'">

diesen Code verwenden. Nun bleibt bei mir aber unter VS2005 noch folgendes Problem.Im Reference Path sind zwei exe enthalten. Die eine verweist auf /obj/ und die andere verweist auf /bin/. Es kommt dann ein Fehler zustande weil das <Exec> Command folgendes Produziert.

Error 1 The command ""C:\Program Files\Microsoft\Ilmerge\Ilmerge.exe" /out:bin\Debug\SQLite_test.exe "obj\Debug\SQLite_test.exe" " exited with code 1.

Das ist doch aber ein Fehler des VS2005? Wieso will der in 2 Verzeichnisse builden? Also ins bin und ins obj. Weis das einer, denn wenn ich das abstelle sollte es funzen...

THX

11.02.2009 - 14:29 Uhr

Ich hab jetzt doch noch mal eine Frage zu dem ILMerge.

Ich hab das ja wie schon erwähnt ins VS2005 eingefügt, und mit hilfe dieser beschreibung klappt das auch ohne probleme.

Nun meine Frage:


<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

 <Target Name="AfterBuild">
   <CreateItem Include="@(ReferencePath)" Condition="'%(CopyLocal)'=='true'">
       <Output TaskParameter="Include" ItemName="IlmergeAssemblies"/>
   </CreateItem>
   <Exec Command="&quot;$(ProgramFiles)\Microsoft\Ilmerge\Ilmerge.exe&quot; /out:@(MainAssembly) &quot;@(IntermediateAssembly)&quot; @(IlmergeAssemblies->'&quot;%(FullPath)&quot;', ' ')"/>
   <!--Delete Files= "@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')"/-->
 </Target>

 <Target Name="_CopyFilesMarkedCopyLocal"/>

</Project>


Das wurde in die Postbuild eingefügt. Nun aber meine Frage. Dort steht ja Condition == true, das heißt nur wenn copy local auf true steht versucht ILMerge die Datei zu mergen. Komischer weise funzt das net so ganz.

Kleines Beispiel. Ich hab eine Project das nur .Net referencen einbidnet. Dort hab ich das IlMerge eingebaut und kompiliert. Klaro hier muss nix gemerged werden, nur zum Test, aber es funzt. Nun hab ich eine externe reference eingebunden, bzw. sqlite.dll, und hab die im programm auch referenciert. Nun hab ich copy local auf false gestellt. Und es lässt sich nicht kompilieren? Er startet das ILMerge mit keinem dll Assemblie und der exe. Komisch.

Jetzt wollt ich einfach in die Condition mit einbauen das wenn der Referencename == "sqlite.dll" ist soll er die nicht mit einbauen. Problem ist aber ich weis nicht welche Items dort mitgegeben werden. CopyLocal gibt es ja, aber was noch? Wo kann man das raus finden, den google sagt mir dazu nicht allzu viel?

THX for help

10.02.2009 - 15:22 Uhr

Was genau meinst du mit VORLAGEN? Meinst du code templates?

10.02.2009 - 10:10 Uhr

Ok dann schau ich mir mal den wrapper an... Danke

10.02.2009 - 09:34 Uhr

Der lädt die dll's doch eh zur Laufzeit rein. Das heißt der JIT compiler bearbeitet die wenn sie benötigt werden. nun meine Frage meinst du nicht das dass länger dauert wenn der die erst aus der exe laden muss, anstatt direkt drauf zu zu greifen?

10.02.2009 - 09:23 Uhr

Es scheint das ich meine Frage nicht korrekt ausgedrückt habe. Also ich weiß das ILMerge das nicht kann nativen Code zu mergen. Mir ist auch klar warum. Nur zielte meine Frage darauf hinaus, ob es möglich ist, bei der Anleitung oben, einige DLL's außen vor zu lassen. Sprich ILMerge geht einfach alle Referenzen durch und will die mergen. Dazu musste (wie oben in der Anleiung beschrieben) man die cvporj Datei öffnen und auf ein anderes File verlinken. Kann man nun irgendwie diese eine Dll vom mergen ausschließen.

@Golo Roden

Es ist Performance Technisch bestimmt nicht die beste Variante. deswegen meine ich ist es nicht optimal. Aber es geht um den FAKTUM der leichten sharebarkeit. Und das ist immer noch einfach als erst etwas auszupacken, oder net?

09.02.2009 - 18:38 Uhr

Zu 1. Ich weis nur, dadurch leichter zu sharen

Zu 2. Ist ne dll von SqLite die nativen Code enthält. (ich glaub c++ code)

09.02.2009 - 17:17 Uhr

Ich hab ein Projekt welches mehrere dlls referenziert. Nun wollt ich das diese Assemblies mit in die Exe kompiliert werden, und habe dies auch mit hilfe von ILMerge geschafft. Mit dieser Anleitung kann man das sogar in das Studio einbinden, und so diesen Prozess automatisieren.

Jetzt hab ich folgendes Problem. Ich bin seit neusten ein Assemblie ein, welches nicht ausschließlich manged code enthält, also auch nativen code. Nun spinnt natürlich mein ilmerge, da er diese dll nicht in die exe einbinden kann.

Gibt es eine Möglichkeit weiterhin alle dll's in die exe einzubinden, aber die eine dll davon auszuschließen?

Vielleicht hat einer von euch ja ein ähnliches problem gehabt!

Danke im vorraus...

09.02.2009 - 14:18 Uhr

Versuch mal ein bisschen genauer zu bescheiben was du vor hast, den erhlich gesagt weis ich es nicht 😃

Soweit ich das verstanden habe möchtset du doch nur unten in der StatusBar anzeigen welcher Menüeintrag selectiert wurde/ist??

Dann mach es doch einfach so: Du meldest dich an jedem Event an welches dir mitteilt das ein Menüitem geklickt wurde.
Sprich du iterierst du alle Items und meldest dich auf Item.click an.
Verweisen tust du immer auf die selbe Methode.


public Form1()
{
    InitializeComponent();
    AddHandler(this.menuStrip1.Items);
}

private void AddHandler(ToolStripItemCollection items)
{
    foreach (ToolStripMenuItem item in items)
    {
        //für hover event
        item.Hover += new EventHandler(item_Click);
        //für click event
        item.Click += new EventHandler(item_Click);
        AddHandler(item.DropDownItems);
    }
}

void item_Click(object sender, EventArgs e)
{
    this.StatusLabel.Text = ((ToolStripItem)sender).Text;
}

09.02.2009 - 13:45 Uhr

Die Frage hat sich mal wieder selber beantwortet. Ich war irretiert weil die SelectedItems Proberty nur readonly war.

Aber die eigenschaft auf dem Item nicht....

Also

listview.Items[index].Selected = true;

funzt...

09.02.2009 - 13:29 Uhr

Kann man bei einer ListView (ohne sie zu überschreiben) das selectierte Item Programm-technisch ändern, also nicht vom anwender gesteuert?

09.02.2009 - 12:25 Uhr

Da hätte ich auch drauf kommen können 😃

Danke dir.

09.02.2009 - 12:11 Uhr

Ich hab mal eine frage bezüglich der SelectionBackColor des Systems. Eine Listview zeichnet ihre Items mit einer bestimmten Hintergrundfarbe im falle sie sind selectiert. Diese Farbe ist meines wissens vom System (windows) festgelegt, jenach dem welchen style man eingestellt hat. Wie kommt man an die farbe ran?

Mein vorhaben: Ich habe 2 LV's, und wenn man in der einen etwas selektiert, und dann in der anderen, verliert die erste ja Ihren Focus. Dadurch verschwindet auch die selectionsfarbe des items. Nun möchte ich einfach das onselectedindexchanged überschrieben und dort die Backcolor des Items setzen. Dazu brauch ich aber die genau farbe....

THX

08.02.2009 - 12:31 Uhr

@GMLOD

merci

08.02.2009 - 12:28 Uhr
  1. konnt ich grad selber lösen. Jetzt fehlt noch das 1te, also denn ältesten bzw. jüngsten eintrag in der Table bezogen auf die column date.

zu 1)

SELECT COUNT(column) FROM (SELECT column FROM TABLE WHERE ...);
08.02.2009 - 12:14 Uhr

verwendetes Datenbanksystem: <SQLite>

Ich hätte man eine Frage bezüglich 2 Selectstatements.

Ich hab eine Table die mehrere Columns enthält, unteranderen eine Datums Spalte.

1)Nun möchte ich das älteste Datum das sich in der DB befindet erhalten.

2)Wenn ich Daten aus der Table auslese, dann möchte ich vor dem auslesen wissen wieviel entitäten dieses selectstatement treffen. Um eine Progressbar zu steuern. Geht das irgendwie mit dem COUNT func?

Danke für eure hilfe.

06.02.2009 - 20:35 Uhr

Ich bin vielleicht ein trottel....
Man muss natürlich auch die parameter auf die command parameter linken also


command.parameters.Add(p1);
command.parameters.Add(p2);


dann funzt es.

Danke für deine hilfe