Dailycode.info

Short solution for short problems

Devexpress aspxgrid: Change row color at runtime

 

I needed to change the background color of a grid at runtime.

Found a good and easy solution on how to do this. You will need to override the HTMLRowPrepared event.

protected void grdOrderLocations_HtmlRowPrepared(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewTableRowEventArgs e)

{

CheckBlocked(e);

}

 

private void CheckBlocked(ASPxGridViewTableRowEventArgs e)

{

    if (e.RowType != GridViewRowType.Data) return;

    object blocked = e.GetValue("BlockCodeIC");

    if (blocked != null)

        e.Row.BackColor = System.Drawing.Color.Red;

}

 

This is how it looks:


 


Devexpress aspxgrid: Show dynamic images in a column (Part 1)

There was a problem with this solution when you would use sorting or any other grid related function, the htmlrowcreated is only called when the grid is created, not after postback or callback. So together with a collegue I found a better way, this can be found in (Part 2)!

The challenge is to show images in a column, depending on the data, the image can be different. For example, when de Boolean is true, show OK.gif image, else show NOK.gif image. Or when a bool is set show an image, when it’s not set, show nothing.

 

Here an example of a grid containing several image columns that vary depending on data in that row.


 

The implementation involves 2 fazes. First we add the columns to our grid dynamically from the code behind, next we catch the HTMLRowCreated event were we set the image of the row. The first faze you also can be replaced if you put the columns in the aspx, but it gave me problems with the binding of the data. So I decided to create columns from the code behind. Before I data bind the data to the grid I create the columns from the code behind.

private void FillGrid(string id)

{

    List<Order> orderList = GenericSingleton<GMEntitiesPL>.GetInstance().GetOrdersOnLocation(id);

    grdOrderLocations.DataSource = orderList;

    AddCustomColumns(id);

    grdOrderLocations.DataBind();

    //grdOrderLocations.Columns[showColumns.Length].Visible = false;

}

 

In the AddCustomColumns, I will create all needed columns. Based on some data from the database, I decide which column to show. The interesting part here is where I create the 5 image columns:

Here the code to create the first image column:

GridViewDataColumn col1 = new GridViewDataColumn();

//TODO Set Header Value, Get them in TextTag from GP_MES_Translation on property.Name and use the default 

col1.Caption = "Order ready";

col1.FieldName = "OrderReady"; 

col1.Width = Unit.Pixel(int.Parse(showColumns[count]));

col1.VisibleIndex = 0;

//visibleIndex++; 

col1.DataItemTemplate = new MyImageTemplate() { ID = "ASPxImage1" };

grdOrderLocations.Columns.Add(col1);

 

We create a simple gridviewdatacolumn. Then we create a new ImageTemplate that will add the image to the dataitemtemplate of the column. Here fore I created a class that will instantiate a new class of the interface ITemplate:

class MyImageTemplate : ITemplate

    {

        public string ID { get; set; }

 

        public void InstantiateIn(Control container)

        {

            ASPxImage img = new ASPxImage();

            GridViewDataItemTemplateContainer gridContainer = (GridViewDataItemTemplateContainer)container;

            //img.ImageUrl = "~/Images/OK.gif";

            img.Visible = false;

            img.ID = ID;

            container.Controls.Add(img);

        }

    }

 

The class need the ID to be set, because this ID will be used later on to find the column and set the image.

When you add a next image column, you can use the same MyImageTemplate class, but give a different ID:

GridViewDataColumn col1 = new GridViewDataColumn();

//TODO Set Header Value, Get them in TextTag from GP_MES_Translation on property.Name and use the default 

col1.Caption = "Special";

col1.FieldName = "Special";

col1.Width = Unit.Pixel(int.Parse(showColumns[count]));

col1.VisibleIndex = 2;

//visibleIndex++; 

col1.DataItemTemplate = new MyImageTemplate() { ID = "ASPxImage3" };

grdOrderLocations.Columns.Add(col1);

 

So far so good, by now you should see the columns in the grid, but no image yet. This will be done in the HtmlRowCreated event of the grid:

protected void grdOrderLocations_HtmlRowCreated(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewTableRowEventArgs e)

{

    //string index = e.VisibleIndex.ToString();

    CheckOrderPosShipMentReady(e);

    CheckRushOrder(e);

    CheckSpecial(e);

    CheckSize(e);

    CheckCoatingPrep(e);

}

 

I’ll show the first 2 functions. The first CheckOrderPosShipMentReady(e) will set a OK image if the Boolean value in the column is true else it will show a NOK image:

private void CheckOrderPosShipMentReady(ASPxGridViewTableRowEventArgs e)

{

    ASPxImage image = grdOrderLocations.FindRowCellTemplateControl(e.VisibleIndex, grdOrderLocations.Columns["orderready"] as GridViewDataColumn, "ASPxImage1") as ASPxImage;

 

    if (image == null) return;

    image.Visible = true;

    bool check = false;

    try

    {

        object b = e.GetValue("OrderReady");

        check = bool.Parse(b.ToString());

    }

    catch { }

    if (check)

    {

        image.ImageUrl = "~/Images/OK.gif";

        image.ToolTip = "Ready";

    }

    else

    {

        image.ImageUrl = "~/Images/NOK.gif";

        image.ToolTip = "Not ready";

    }

}

 

The next function will show an image if a property is filled else the image will stay visible false.

private void CheckSpecial(ASPxGridViewTableRowEventArgs e)

{

    ASPxImage image = grdOrderLocations.FindRowCellTemplateControl(e.VisibleIndex, grdOrderLocations.Columns["special"] as GridViewDataColumn, "ASPxImage3") as ASPxImage;

 

    if (image == null) return;

 

    bool check = false;

    try

    {

        object b = e.GetValue("Special");

        if (b.ToString() == "O0")

        {

            check = true;

        }

    }

    catch { }

    if (check)

    {

        image.Visible = true;

        image.ImageUrl = "~/Images/special.gif";

        image.ToolTip = "Rush Order";

    }

 

}

 

It’s working really well, I will continue to explore the grids functionality, combining it will the grid focused events etc… I’ll keep things posted here on the forum!


 


Open a file from the file system in a web browser. (+Demo project)

I included a demo solution, you can download it at the botom.

It sounds easy, just put the file as hyperlink on the system and let the user click the link…

Yes that’s easy, but what if the file needs to be opened from the code behind? I tried to use the Process.start at first, which did the trick. Only when I was working locally, after deploying on the server it stopped working, and it has something to do with the right of the application pool user to the local user’s desktop. So looking for a different solution, I came up with the following solution which works fine for IE, Chrome, Firefox and Safari.

The solution involves 2 pages. The first page has the links to the documents and when clicked, the document needs to be opened.


 

The second page is an empty aspx page where I generate the code for showing the document in the page load event.

After clicking on the link on the first page, I save the url of the document in the session and on the second page I get the url from the session.

On the first page, the click event of a button is triggered and then I get the url of the document from the selected line. I add the url to the Session so I can get it later on the second page. The code on the click event of the first page looks like this:


 

protected void btnView_Click(object sender, EventArgs e)

{

    string[] sfield = { _sKeyField };

    string docUrl = Convert.ToString(grdAttachments.GetRowValues(grdAttachments.FocusedRowIndex, sfield));

 

    try

    {

        Session.Add("OpenFileUrl", docUrl);

        Response.Redirect("OpenFile.aspx", false);

    }

    catch (ThreadAbortException)

    { }

    catch (Exception er)

    {

        lblError.Text = er.Message;

    }

}

 

 

So fairly easy code. Then when the second page (OpenFile.aspx) get loaded, the following code is triggered:

protected void Page_Load(object sender, EventArgs e)

{

    try

    {

        Loadfile();

    }

    catch (Exception er)

    {

        lblError.Text = er.Message;

    }

}

 

private void Loadfile()

{

    if (Session["OpenFileUrl"] != null)

    {

        // Get the physical Path of the file(test.doc)

        //string filepath = Server.MapPath();

 

        // Create New instance of FileInfo class to get the properties of the file being downloaded

        FileInfo file = new FileInfo(Session["OpenFileUrl"].ToString());

 

        // Checking if file exists

        if (file.Exists)

        {

            // Clear the content of the response

            Response.ClearContent();

 

            // LINE1: Add the file name and attachment, which will force the open/cance/save dialog to show, to the header

            //Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);

            Response.AddHeader("Content-Disposition", "inline; filename=" + file.Name);

 

            // Add the file size into the response header

            Response.AddHeader("Content-Length", file.Length.ToString());

 

            // Set the ContentType

            Response.ContentType = ReturnExtension(file.Extension.ToLower());

 

            // Write the file into the response (TransmitFile is for ASP.NET 2.0. In ASP.NET 1.1 you have to use WriteFile instead)

            Response.TransmitFile(file.FullName);

 

            // End the response

            Response.End();

        }

    }

}

 

To complete all the code you need to show the document, here’s the ReturnExtension method:

private string ReturnExtension(string fileExtension)

{

    switch (fileExtension)

    {

        case ".htm":

        case ".html":

        case ".log":

            return "text/HTML";

        case ".txt":

            return "text/plain";

        case ".doc":

            return "application/ms-word";

        case ".tiff":

        case ".tif":

            return "image/tiff";

        case ".asf":

            return "video/x-ms-asf";

        case ".avi":

            return "video/avi";

        case ".zip":

            return "application/zip";

        case ".xls":

        case ".csv":

            return "application/vnd.ms-excel";

        case ".gif":

            return "image/gif";

        case ".jpg":

        case "jpeg":

            return "image/jpeg";

        case ".bmp":

            return "image/bmp";

        case ".wav":

            return "audio/wav";

        case ".mp3":

            return "audio/mpeg3";

        case ".mpg":

        case "mpeg":

            return "video/mpeg";

        case ".rtf":

            return "application/rtf";

        case ".asp":

            return "text/asp";

        case ".pdf":

            return "application/pdf";

        case ".fdf":

            return "application/vnd.fdf";

        case ".ppt":

            return "application/mspowerpoint";

        case ".dwg":

            return "image/vnd.dwg";

        case ".msg":

            return "application/msoutlook";

        case ".xml":

        case ".sdxl":

            return "application/xml";

        case ".xdp":

            return "application/vnd.adobe.xdp+xml";

        default:

            return "application/octet-stream";

    }

 

}

OpenDocDemo.zip (27.30 kb)


Extract a number from a text cell in Excel (Without using VBA)

I needed to get the numbers from a cell that contains a number followed by text. I found this solution, assuming the text is in cell A1:

=REPLACE(LEFT(A1;LOOKUP(10;MID(A1;ROW(INDIRECT("1:30"));1)+0;ROW(INDIRECT("1:30"))));1;MIN(FIND(0;SUBSTITUTE(J1&0;{1;2;3;4;5;6;7;8;9};0)))-1;"")+0

Using the dutch settings, else replace the ; with ,

This function will give problems when numbers appear after the text. So this function is even better:

=LOOKUP(99^99;--("0"&MID(A1;MIN(SEARCH({0;1;2;3;4;5;6;7;8;9};A1&"0123456789"));ROW($1:$10000))))

It will get the leading numbers of a string in a cell for cell A1!

1354655 azezae will be 1354655

1354655 azezae 123 will still be 1354655!

Greets

Source


Audit trail (History) using the entity framework and self-tracking entities (Part2)

The reason why I’m writing part 2 is because I bumped into the problem that when you are using identity insert on the database, the identity is not known the moment the ObjectContext.Savingchanges event is fired.  This only gave problems for the insert statement. The identity key column was always 0. So I found a solution for this. I combined an audit project and a repository. For the update and delete, nothing really changed, but the way I handle the auditing for the insert is changed completely.

First of all, I removed the added objects from the GetObjectStateEntries call:

 

void Ents_SavingChanges(object sender, EventArgs e)

{

    try

    {

        Ents.DetectChanges();

        IEnumerable<ObjectStateEntry> changes = Ents.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted | EntityState.Modified);

        foreach (ObjectStateEntry stateEntryEntity in changes)

        {

            if (!stateEntryEntity.IsRelationship && stateEntryEntity.Entity != null && !(stateEntryEntity.Entity is GP_PROJ_DBAudit))

            {

                //is a normal entry, not a relationship

                GP_PROJ_DBAudit audit = this.AuditTrailFactory(stateEntryEntity, UserName);

                auditTrailList.Add(audit);

            }

        }

 

        if (auditTrailList.Count > 0)

        {

            foreach (var audit in auditTrailList)

            {//add all audits

                Ents.GP_PROJ_DBAudit.AddObject(audit);

            }

        }

        auditTrailList = new List<GP_PROJ_DBAudit>();

    }

    catch (Exception er)

    {

        //Audit falied, need to log it.

    }

}

 

Second, I created a function that is used for all inserts:

 

/// <summary>

/// Add entity to the repository

/// </summary>

/// <typeparam name="E">An Entity type object type which is going to be added</typeparam>

/// <param name="entity">The entity to be added</param>

/// <returns>True/False</returns>

/// <remarks></remarks>

private bool AddRecord<E>(E entity)

{

    if (entity is IObjectWithChangeTracker)

    {

        Ents.AddObject((typeof(E)).Name.ToString(), entity);

        ObjectStateEntry entry = Ents.ObjectStateManager.GetObjectStateEntry(entity);

        GP_PROJ_DBAudit audit = CreateAuditRecord(entry, AuditActions.I);

        Ents.SaveChanges();

        AddKeyFields(entry, audit);

        Ents.GP_PROJ_DBAudit.AddObject(audit);

        Ents.SaveChanges();

        return true;

    }

    else

    {

        return false;

    }

}

 

If we look closer to this function,  the first thing we do is add the object to the context. Then we get the entry in the objectstatemanager. We save the changes in the context, so our key field is filled in. then I create the audit record.

 

Below I used the AddRecord function to insert an entity.

 

public void InsertProject(GP_PROJ_Projects project)

{

    try

    {

        project.Created = DateTime.Now;

        AddRecord<GP_PROJ_Projects>(project);

    }

    catch (Exception er)

    {

        Ents.GP_PROJ_Projects.DeleteObject(project);

        throw new ArgumentException("Insert failed, please check your data!", er.InnerException);

    }

}

 

The AddKeyfields function and the creation of the audit record you can find in PART (1)


Entity Framework and There is already an open DataReader associated with this Command which must be closed first.

There is already an open DataReader associated with this Command which must be closed first.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.

Source Error: 

When using the entity Framework I got that error. Got it when I was looping within a loop. Since there was no association between the objects, I had to do a loop en inner loop, it looks like this:

foreach (GP_PROJ_ProjectSteps step in Ents.GP_PROJ_ProjectSteps.Where(s=>s.ProjectID == project.ProjectID))

{

    foreach (GP_PROJ_ProjectTasks task in Ents.GP_PROJ_ProjectTasks.Where(d => d.StepID == step.StepID))

    {

        Ents.GP_PROJ_ProjectTasks.DeleteObject(task);

    }

    Ents.GP_PROJ_ProjectSteps.DeleteObject(step);

}

Ents.GP_PROJ_Projects.DeleteObject(project);

Ents.SaveChanges();

 

The solution to this problem was to allow or enable Multiple Active Result Sets (MARS). This is done in your connection string:

Data Source=DBServer;Initial Catalog=MyDB;Persist Security Info=True;User ID=DBUSER; Password=PWD;MultipleActiveResultSets=true;


Disallow non numeric characters in an asp.net textbox

A very simple javascript that will block the entry of non numeric characters:

function isNumberKey(evt) {

    var charCode = (evt.which) ? evt.which : event.keyCode

    if (charCode > 31 && (charCode < 48 || charCode > 57))

        return false;

 

    return true;

}

Simply put this on the onkeydown event:

<dx:ASPxTextBox runat="server" ID="txtTaskSortOrder" Width="50px" Value='<%# Eval("TaskSortOrder")%>'

MaxLength="5" onkeypress="return isNumberKey(event);">

</dx:ASPxTextBox>

 

If the user enters non numeric characters, the entry will be withhold and not allowed in the textbox.


ASPMenu on masterpage: Show the selected page

 

I struggled a lot to get a decent working and good looking asp menu that responded the way I wanted.

 

My latest solution shows a small dot on the selected menu item. Because setting a background from the style sheet was not working the way I wanted. I got it working but then I had to drop some of the style I was using for my menu. Now my solution looks nice:


It only takes a bit of code on your master page:

foreach (MenuItem item in NavigationMenu.Items)

{

    if (item.NavigateUrl == Page.AppRelativeVirtualPath)

    {

        item.Selected = true;

        item.Enabled = false;

        item.ImageUrl = ResolveUrl("~/Images/MnuItemSel.gif");

    }

}

 

Add the image to your project and it works!



ASP.Net: Use a different stylesheet for IPAD or IPhone and a destop in your web site

I wanted to get a different style when the site is browsed on an Ipad or Iphone and a normal sized window computer like a laptop …

The site uses a master page, so the logic to check this is on the code behind of the master page. Because the style sheets are defined there.

The check is very easy:

bool ipaddevice = HttpContext.Current.Request.UserAgent.ToLower().Contains("ipad");

if (ipaddevice)

{

    Literal link = new Literal();

    link.Text = @"<link href='" + ResolveUrl("~/css/iPad.css") + "' rel='stylesheet' type='text/css' />";

    this.HeadContent.Controls.Add(link);

}

else

{

    Literal link = new Literal();

    link.Text = @"<link href='" + ResolveUrl("~/css/Custom.css") + "' rel='stylesheet' type='text/css' />";

    this.HeadContent.Controls.Add(link);

}

 

The HeadContent is a content place holder that is located in the head section of the MasterPage:

 

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>My Web</title>

   

    <link href="../css/shared_style.css" rel="stylesheet" type="text/css" />

    <script src="../Scripts/Scripts.js" type="text/javascript"></script>

    <asp:ContentPlaceHolder ID="HeadContent" runat="server">

    </asp:ContentPlaceHolder>

</head>

 

Source