Using a FormView with LINQ - asp.net

I am using a FormView control to edit a record fetched using a LinqDataSource. In essence, the markup for the FormView and the data source looks like this:
<asp:FormView ID="RuleInstancePropertiesFormView" runat="server" DataKeyNames="RuleInstanceId"
DataSourceID="RuleInstanceDataSource" DefaultMode="Edit" Visible="false"
CssClass="PropertiesTable">
<EditItemTemplate>
<asp:Label ID="RuleInstanceId" runat="server" Text='<%# Eval("RuleInstanceId") %>' />
<telerik:RadTextBox ID="RuleInstanceNameTextBox"
runat="server"
Text='<%# Bind("Rule.Name") %>' />
<telerik:RadTextBox ID="LimitIndexTextBox"
runat="server"
Text='<%# Bind("LimitIndex") %>' />
</EditItemTemplate>
</asp:FormView>
<asp:LinqDataSource ID="RuleInstanceDataSource" runat="server"
ContextTypeName="Questionnaire.QuestionnairesDataContext"
TableName="RuleInstances" EnableUpdate="true">
</asp:LinqDataSource>
The record I am editing has a foreign key reference to another table, namely the "Rule" table. In the FormView, I need to edit fields in this foreign key table (I have a binding to the Rule.Name field in the above code).
When I try to save my changes, the local field (LimitIndex) is saved correctly in the database, but the foreign field (Rule.Name) isn't. I'm a bit puzzled by this, as the FormView correctly fetches the current value of Rule.Name, but refuses to persist it back to the LINQ object.
I hope anyone can help, thanks :)

You're specifying which table to use as a datasource using the TableName property. This controls which table Linq2Sql will update and so is limiting the update to just the RulesInstances table.

Okay, I found an alternative (but not elegant) solution. I use an ObjectDataSource instead of a LinqDataSource. I have then defined an class
public class RuleInstanceProjection {
public RuleInstanceProjection(){}
// Bind properties from the LINQ object.
public RuleInstanceProjection(RuleInstance instance) { ... }
public int RuleInstanceId {get; set;}
public string Rule_Name {get;set;}
...
}
The object above takes a RuleInstance as constructor, and updates its own properties with all the values that I need in the FormView. I then configure the ObjectDataSource to use another custom class, RuleInstanceProjectionDS, as data source. This class handles updates and inserts of my custom RuleInstanceProjection class:
public class RuleInstanceProjectionDS
{
public RuleInstanceProjectionDS() { }
public RuleInstanceProjection GetRuleInstance(int ruleInstanceId)
{ /* Retrieve the RuleInstance, and instantiate
a RuleInstanceProjection object */ }
public void SaveInstanceProjection(InstanceProjection projection)
{ /* Map fields back to the LINQ objects and submit. */ }
}
I can therefore handle all mappings in these two classes. Now, I only have to decide if this is actually better than updating the GUI controls directly...
I must say it isn't the most elegant solution, and I hope there will be a better data binding framework in later versions of ASP.NET. The current one only seems to handle the most trivial cases :(.

Related

ASP.Net WebForms Model Binding GridView Using Entity Framework 5.0.0.0

im binding List<T> to my GridView where T is the object created by EntityFramework from my database. There is a foreign key in my said table and i want to display its corresponding text value in the GridView.
<asp:TemplateField HeaderText="Foreign Key Type">
<ItemTemplate>
<asp:Label ID="LabelID" Visible="true" runat="server"
Text="<%# Item.<foreignKeyTable>.Text %>" >
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
when i do that i get the following error
The operation cannot be completed because the DbContext has been disposed.
how can i get pass that
Most likely, you have query code that does the following:
using (var ctx = new SomeContext())
{
var data = ctx.Data.Where(..).ToList();
return data;
}
You may not have a using, but either way, the context has it's Dispose() method on it, and any unloaded navigation properties will always fail, because there is no context alive for it to attach to. Even though you may use the context within a method, and may not be storing it globally, as long as you aren't explicitly disposing the context, by calling the method or with a using statement, you will be fine.

Getting the bound type of templated column controls in gridView

Hi I have following grid view
<asp:GridView ID="grdSettings" runat="server" Height="400px" Width="100%"
AutoGenerateColumns="false" >
<Columns>
<asp:TemplateField HeaderText="XYZ" BoundFieldName="XYZTypeName">
<ItemTemplate>
<asp:Label ID="lblCustomerName" runat="server" Text='<%# Bind("CustomerName") %>'>
</asp:Label>
<asp:Label ID="lblCostumerId" runat="server" Text='<%#Bind("CustomerId") %>'></asp:Label>
</asp:TemplateField>
</Columns>
</asp:GridView>
Which is bound by List of Customer ,class is as follows
Class Customer
{
public string CustomerName { get; set; }
public int CustomerId { get; set; }
}
Now on a method named GetGridStuff() , i need to iterate in every column and get the type that was bound to controls in template field. For example in case of the first control in the template field
<asp:Label ID="lblCustomerName" runat="server" Text='<%# Bind("CustomerName") %>' >
</asp:Label>
I need to know what type of property data it contains , in this case its CustomerName. I need to get this dynamically at run time as to write code in part of program which is not aware if this grid structure. I have the grid object with me and i can access all properties.
Let me try this, being away from coding for more than 5 years now and if I understand the problem correctly as you may want to handle it through server side code.
Look for an event called ItemBound (or similar forgive me for my memory), this gives you values of all the items in current row (Properties). You also need to declare temp control types (label,textbox etc) and assign corresponding value to these controls using e.FindControl with appropriate type casting, e.g. Label l = (Label)e.Findcontrol("Name")
downside of the approach you should avoid too much of process as it is going to execute on every row creating of the grid.
Let me know if you still want a precise code to handle the problem but otherwise this description should at least help you to look for Row Level Event to crack the prob and also encourage you to stick to tech forums :)

Set TemplateField HeaderText dynamic for localization

I am trying to create localization for my ASP.NET code, but I have issues setting the TemplateField's HeaderText
I have this that works
<asp:TemplateField HeaderText="Description">
<ItemTemplate>
<%# Eval("Description") %>
</ItemTemplate>
<FooterTemplate>
<asp:Panel ID="Panel5" runat="server" DefaultButton="EditSubmission">
<asp:TextBox runat="server" ID="Submission_DescriptionTxtBox" TextMode="MultiLine"
ToolTip='<%# GetById("atforbedringsforslag_description_tooltip") %>'/>
</asp:Panel>
</FooterTemplate>
</asp:TemplateField>
But I want to change
<asp:TemplateField HeaderText="Description">
To
<asp:TemplateField HeaderText='<%# GetById("atforbedringsforslag_description_title") %>'>
But then I get
Databinding expressions are only supported on objects that have a DataBinding event. System.Web.UI.WebControls.TemplateField does not have a DataBinding event.
How should I set this field? I can find some that uses OnRowCreated, but then you access the fields with an index number, and then it becomes easy to make mistakes or forgot to change indexes if new fields are added later on
EDIT My solution:
Created the custom expression builder
using System.Web.Compilation;
using System;
using System.CodeDom;
public class LocalizationExpressionBuilder : ExpressionBuilder
{
public override CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
CodeExpression[] inputParams = new CodeExpression[] { new CodePrimitiveExpression(entry.Expression.Trim()),
new CodeTypeOfExpression(entry.DeclaringType),
new CodePrimitiveExpression(entry.PropertyInfo.Name) };
// Return a CodeMethodInvokeExpression that will invoke the GetRequestedValue method using the specified input parameters
return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(this.GetType()),
"GetRequestedValue",
inputParams);
}
public static object GetRequestedValue(string key, Type targetType, string propertyName)
{
// If we reach here, no type mismatch - return the value
return GetByText(key);
}
//Place holder until database is build
public static string GetByText(string text)
{
return text;
}
}
Added the prefix to my web.config
<system.web>
<compilation debug="true" defaultLanguage="c#" targetFramework="4.0">
<expressionBuilders>
<add expressionPrefix="localizeByText" type ="LocalizationExpressionBuilder"/>
</expressionBuilders>
</compilation>
</system.web>
And I can now get my text like this
<asp:TemplateField HeaderText='<%$ localizeByText:Some text %>'>
You can build your own custom Expression Builder which calls your GetById method. Look at the following link for an old but good article explaining how to build an expression builder and how to use it:
https://web.archive.org/web/20210304125044/https://www.4guysfromrolla.com/articles/022509-1.aspx
When you have an expression builder, you use it with the <%$ syntax. This is different from the databinding syntax <%#.
For the HeaderText field, it is not allowed to use DataBinding syntax (not sure why, but that's how MS made it). Using expression syntax IS allowed and will work once you have your custom expression builder done.
Do go through the page I linked to, it's quite a lot of text, but in the end making you expression builder will not take much effort...
Also, the page has a link at the bottom to a library of expression builder that the author has made. Have a look at them, maybe one of them could be used directly to solve your problem (specifically, the CodeExpressionBuilder).

How do I bind a GridView to a custom object?

If I have the following ASP.NET code (it's not complete - obviously there's a lot missing, but none of it matters):
<asp:GridView>
<Columns>
<asp:TemplateField>
<ItemTemplate>
My Label: <asp:Label />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
My Text Box: <asp:TextBox />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And if I have something like this in the CodeBehind:
Private MyListOfObjects As List(Of MyObject)
...
Public Class MyObject
Public MyTextBoxString as String
Public MyLabelString as String
End Class
How can I bind the GridView so that one row is equivalent to one item in my MyListOfObjects list, and so that the data will populate and persist across page loads or postbacks? I've never done custom databinding like this before, so a full explanation would be very helpful. All the tutorials I've come across so far only talk about using GridViews directly with Database query results, and that's not what I need.
Thanks!
Just set the datasource of the gridview to your object.
MyGridView.DataSource = myList
MyGridView.DataBind()
Here's a very similiar post:
Binding a method that returns List<employee> to a gridview
Looks like you are using a list in vb.net. Remember lists can hold integers, strings, dates, objects (these include user defined types (your object)).
So you can bind a gridview to a list object by setting the datasource property to your list.
In the above example, myList, might hold a ton of employee objects, etc. So assign it to the datasource and .DataBind() and voila a gridview with each row containing your object.
You can do something like
My Label: <asp:Label id="myLabel" runat="server" Text='<%# Eval("MyTextBoxString") %>' />
in the markup and similar stuff for your textbox.
GridView1.DataSource = MyListOfObjects
GridView1.DataBind()
First remember any binding controls like GridView, DropdownList e.t.c bind to public properties, so first make your public members to public properties.
Then create objects of MyObject class and add them to your List<MyObject> object
Finally you can persist this list object by saving it in Session or ViewState to maintain it after postbacks.
I hope you can do it now!!! you can ask for more help if neccessary.

CheckBoxList with multiple values bound to a single flag enum

I have a FormView (bound to an ObjectDataSource) that contains a CheckBoxList that I'd like to bind to a single property of the underlying object that is an Enum with the FlagsAttribute applied to it. Binding to the SelectedValue property always gives me just the FIRST selected value from the list as the property's value. Anyone know how to get around this without overriding the Inserting or Updating methods and manually getting the values of the checkbox list and stuffing it into the parameters of the datasource? Sample code below of what I'm trying to do...
<asp:FormView runat="server" ID="MyFormView" DataSourceID="MyDataSource">
<InsertItemTempate>
<asp:CheckBoxList runat="server" ID="MyCbl" SelectedValue='<%# Bind("MyProperty") %>'>
<asp:ListItem Text="Choice 1" Value="ChoiceOne"></asp:ListItem>
<asp:ListItem Text="Choice 2" Value="ChoiceTwo"></asp:ListItem>
</asp:CheckBoxList>
</InsertItemTemplate>
</asp:FormView>
<asp:ObjectDataSource runat="server" ID="MyDataSource" TypeName="MyClass" ...></asp:ObjectDataSource>
behind the scenes, my object is declared like this...
public class MyClass
{
public MyEnum MyProperty { get; set; }
}
[Flags()]
public Enum MyEnum
{
ChoiceOne = 1,
ChoiceTwo = 2
}
You will have to iterate through the Items collections and build up the enum values from there.
A search on Google for FlaggedEnumTypeConverter should also be helpful.

Resources