views:

1497

answers:

3

I'm working with the XtraGrid Suite made by DevExpress. I can't find any sort of functionality to do this, but I'm curious if you can add a button or hyperlink to a grid cell.

Context: I've got an Events list. Each Event has a Time, Start/End, and a Category (Utility and Maintenance). There can be Start events and Stop events. Having done my analysis of the problem, I've decided that having a StartTime and EndTime for each event would not work.

So if an event starts, I'd record the current time to the Event object, and set it as a 'Start' event. I'd like to add a "Stop" button/hyperlink to a cell in that row. If the user wishes to log an Ends event, the event type, etc would be copied to a new Event with the type 'Stop' and the button would disappear.

I hope this makes sense.

EDIT: Aaronaught's answer is actually better than what I was originally asking (a button) so I've updated the question. That way, anyone looking for putting a hyperlink in a cell can benefit from his example : )

+3  A: 

I prefer to use hyperlink-style text by overriding the drawing code and handling mouse move/click events, as buttons don't scale too well to the typical row height of a grid. However, if a button is really what you want, you should be able to do that using the RepositoryItemButtonEdit as the editor type.

If you're interested in the former, leave a comment and I'll update this with an example. Otherwise, as mentioned, just use the RepositoryItemButtonEdit. You can change its properties to take up the whole cell if you want, and then make the column a fixed size so the button doesn't get stretched.


UPDATE: I'm posting some sample code for the "pretty hyperlink" below, which I like a lot better than a standard Hyperlink cell because (a) it looks nicer, (b) it gives hover feedback, and (c) you can change the cursor if you want (I use a utility method to get the native hand cursor from the OS, which has a more 3D look than Winforms' built-in hand).

Note to non-DevExpress users reading this: I use almost an identical technique for the standard System.Windows.Forms.ListView. Microsoft uses this UI pattern quite a bit in Vista and Windows 7 and it's good to learn how to do, even if the result isn't a perfect replica.

private int hoverRowHandle = GridControl.InvalidRowHandle;

private void gridView_Click(object sender, EventArgs e)
{
    if (hoverRowHandle != GridControl.InvalidRowHandle)
    {
        MyItem item = gridView.GetRow(hoverRowHandle) as MyItem;
        if (item != null)
            // Do whatever the "click" action is here
    }
}

private void gridView_CustomDrawCell(object sender,
    RowCellCustomDrawEventArgs e)
{
    if (e.Column == linkColumn)
    {
        bool hover = (hoverRowHandle == e.RowHandle);
        FontStyle style = hover ? FontStyle.Underline : FontStyle.Regular;
        TextFormatFlags formatFlags =
            TextFormatFlags.Left | TextFormatFlags.VerticalCenter |
            TextFormatFlags.WordEllipsis;
        Color foreColor = gridView.IsRowSelected(e.RowHandle) ?
            Color.White : (hover ? MyColors.LinkHover : MyColors.Link);
        using (Font font = new Font(gridControl.Font, style))
        {
            TextRenderer.DrawText(e.Graphics, "Link Text", font, e.Bounds,
                foreColor, formatFlags);
        }
        e.Handled = true;
    }
}

private void gridView_MouseLeave(object sender, EventArgs e)
{
    int tempRowHandle = hoverRowHandle;
    hoverRowHandle = GridControl.InvalidRowHandle;
    if (tempRowHandle != GridControl.InvalidRowHandle)
    {
        gridView.InvalidateRowCell(tempRowHandle, linkColumn);
    }
}

private void gridView_MouseMove(object sender, MouseEventArgs e)
{
    int tempRowHandle = hoverRowHandle;
    if (tempRowHandle != GridControl.InvalidRowHandle)
    {
        hoverRowHandle = GridControl.InvalidRowHandle;
        gridView.InvalidateRowCell(tempRowHandle, linkColumn);
    }
    GridHitInfo hitInfo = gridView.CalcHitInfo(e.Location);
    if (hitInfo.InRowCell && (hitInfo.Column == linkColumn))
    {
        hoverRowHandle = hitInfo.RowHandle;
        gridView.InvalidateRowCell(hoverRowHandle, linkColumn);
    }

    bool hoverDetail = (hoverRowHandle != GridControl.InvalidRowHandle);
    gridControl.Cursor = hoverDetail ? Cursors.Hand : Cursors.Default;
}

A few notes about this code:

  • MyItem is whatever type of data you have bound to the grid view. Maybe it's a DataRow, or maybe it's some custom type if the data source is an IList<T>.

  • MyColors is a utility class that defines a couple of public static readonly Color fields used for UI stuff. You can replace the references to that with hard-coded colours if you're only ever going to do this on one grid.

  • I don't bother caching the Font, although you probably could, since there are only two of them.

  • The cursor logic will mess with any other cursor logic you might use in the grid (which is virtually none in almost every case for me, so generally you should be fine).

  • If you want to have more than one "link column", you need to maintain a hoverColumn state field in addition to the hoverRowHandle, and obviously change those single-column equality comparisons to search for multiple columns.

For my own Winforms apps, I actually have an Extender Provider that lets me attach this behaviour to a GridView or ListView by tossing in a list of column name/link text pairs, but that code is just a wee bit too long to post here. The example above should get you started.

Aaronaught
Thanks for the offer, I'd love to see an exmple of the hyperlink. In the meantime, I'll use the `RepositoryItemButtonEdit` working.
calico-cat
@calico-cat: Here you are, as promised!
Aaronaught
@Aaronaught: Thank you so very much for all the effort you put into this answer. I wish I could upvote it more than once!
calico-cat
+2  A: 

Use the RepositoryItemButtonEdit and set the TextEditStyle to HideTextEditor.

Pierre-Alain Vigeant
A: 

you can use RepositoryItemButtonEdit : select your target column, in "Properties" click on "ColumnEdit" and select "new", after than select "ButtonEdit". click on your grid and select "run designer", select "in-place Editor Repository" on "Repository" group . select "repositoryItemButtonEdit1" (if you not changed Button edit component name) select "event" tab and select "ButtonPressed" event. fill your code in this event. if you want, hide editor part of component, select target column, in "Properties" click on "ColumnEdit" find "TextEditStyle" and choose "HideTextEditor".

But, one question!?? i want add a picture into my button, somebody have any idea?

adel tehrani
I'd post this as a new question.
calico-cat