Search code examples
c#asp.netgridviewwebformsdotnetnuke

C# DotNetNuke module: Accessing data in the CodeBehind for a GridView


I'm attempting to write a widget for DotNetNuke in C#. This is my first major project in C#, and although I think I've gotten the hang of things, I'm still running into a couple of issues dealing with WebForms. More specifically, I'm having issues with the GridView, and although I feel like I'm 90% there, the last 10% is a killer.

First, the relevant bits from my .ascx file:

<asp:ObjectDataSource ID="objDataSource" runat="server" TypeName="MyCompany.Modules.Discovery.DiscoveryController" SelectMethod="GetDiscoverys" UpdateMethod="UpdateDiscovery" DeleteMethod="DeleteDiscovery">
    <SelectParameters>
        <asp:QueryStringParameter Name="ModuleId" QueryStringField="mid" />
    </SelectParameters>
    <UpdateParameters>
        <asp:QueryStringParameter Name="ModuleId" QueryStringField="mid" />
    </UpdateParameters>
    <DeleteParameters>
        <asp:QueryStringParameter Name="ModuleId" QueryStringField="mid" />
    </DeleteParameters>
</asp:ObjectDataSource>
<!-- Unrelated code... -->
<asp:GridView ID="grdDiscoverys" runat="server" DataSourceID="objDataSource" EnableModelValidation="True" AutoGenerateColumns="false" AutoGenerateEditButton="true" AutoGenerateDeleteButton="true" DataKeyNames="ItemId">
    <Columns>
        <asp:BoundField DataField="ItemId" HeaderText="#" ReadOnly="true" />
        <asp:BoundField DataField="Title" HeaderText="Title" />
        <asp:TemplateField HeaderText="Image">
            <ItemTemplate>
                <%# Eval("Image") %>
            </ItemTemplate>
            <EditItemTemplate>
                <asp:DropDownList ID="ddlEditImage" runat="server" title="Image" OnDataBinding="cmdPopulateImages_prebind" OnLoad="cmdPopulateImages_load" DataValueField="Key" DataTextField="Value" SelectedValue='<%# Bind("Image")%>' />
            </EditItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="Link" HeaderText="Link" />
    </Columns>
</asp:GridView>

Now, a few relevant tidbits from my CodeBehind file:

protected void cmdPopulateImages_load(object sender, EventArgs e)
{
    try
    {
        ((System.Web.UI.WebControls.DropDownList)sender).DataSource = GetFileDictionary();
    }
    catch (Exception exc)
    {
        //Module failed to load 
        Exceptions.ProcessModuleLoadException(this, exc);
    }
}

protected void cmdPopulateImages_prebind(object sender, EventArgs e)
    {
    try
    {
        ((System.Web.UI.WebControls.DropDownList)sender).SelectedValue = "-1";
    }
    catch (Exception exc)
    {
        //Module failed to load 
        Exceptions.ProcessModuleLoadException(this, exc);
    }
}

protected Dictionary<int, string> GetFileDictionary()
{
    // Folder ID where images will be grabbed from.  Will be put in settings.
    int intFolderId = 20;
    // Extensions that are allowed to be seen in the list.  Will be put in settings.
    List<string> slValidExtensions = new List<string>("gif,jpg,jpeg,png".Split(','));
    slValidExtensions.ForEach(delegate(string ext) { ext.Trim(); });

    // Grab a list of files and put it in a dictionary.
    ArrayList alFiles = FileSystemUtils.GetFilesByFolder(PortalId, intFolderId);

    Dictionary<int, string> dFiles = new Dictionary<int, string>();
    dFiles.Add(-1, "---");

    foreach (FileInfo fiFile in alFiles)
    {
        // Make sure we are looking at a valid extension
        if (slValidExtensions.Contains(fiFile.Extension))
        {
            dFiles.Add(fiFile.FileId, fiFile.FileName);
        }
    }

    return dFiles;
}

Now, for my questions:

  1. When you aren't editing the column, you see an Image. However, because this is an ID and not an actual file, it's not very informative. My plan of attack here is to turn that Eval into a label which fires a method in the codebehind onRender, which will grab the associated file for that ID and write it into the .Text of the label...either that, or write out "Missing Image" if the ID can't be found (if the user deleted the image for example). However, the problem is that when I'm actually in the method for the event based off that label, I have no idea how to get access to the data for that particular row.
  2. You'll notice that in cmdPopulatedImages_Prebind I force the SelectedValue to -1 as a by-product of something similar. I have no idea how to grab the image ID from that method, and if the Image ID doesn't actually exist then the module tosses an error in my face because it doesn't exist in the drop down list. So I just set it to -1 always (which represents the blank entry on the data dictionary). If I had the image ID, I could first check to see if it actually existed in the dataset, and if it did then set it, and if not choose the default -1 value.

Solution

  • I'm not answering your question fully because I'm not exactly sure what you're trying to achieve but here's my best effort...

    You want to get your ImageID, right? If your query returns the ImageID then add "ImageID" to your DataKeyNames property of your GridView. That way you can access it for each row.

    A method I think you might find useful is the RowDataBound method. The is called when each row is databound (obviously...). Use it, it is your friend.

    From this method you can call methods etc. for each row. You can also get the RowIndex using e.Row.RowIndex.

    For example to get your "ImageID" to populate an asp:Image ImageUrl property you can use something such as:

    var Image1 = (Image)e.Row.FindControl("Image1");
    var imageId = Convert.ToInt32(GridView1.DataKeys[e.Row.RowIndex].Values["ImageID"]);
    Image1.ImageUrl = GetImageUrlFromId(imageId); //Get the url of your image
    

    You could also populate your dropdown list to select the correct SelectedValue of the current ImageID.

    I hope this helps. The code was all off the top of my head so some things may be a bit off.

    In short. Use the DataKeyNames property and the RowDataBound event.