RadTreeNode data set in code behind doesn't appear in WebService callback - c#

I have a radtreeview that I am initially data binding in the my page code but any node expansion relies on a call to a SVC web service.
The problem is that while the event fires properly and runs the following method out of my webservice:
[OperationContract]
[WebMethod]
public RadTreeNodeData[] TreeViewNodeExpand(RadTreeNodeData ExpandedNode,
object context) {
// blah blah some code
}
The RadTreeNode ExpandedNone parameter is null.
When I built the initial tree in my code behind, I set
List<RadTreeNode> collection
= (data.Select(x => new RadTreeNode
{
Category = category,
ExpandMode = WebService,
Value = x.Value.ToString(),
Text = x.Text,
DataItem = 555
})).ToList();
I explicitly set DataItem to '555'.
Am I missing something as to why RadTreeNodeData ExpandedNode is null when the webservice method fires?
My radtreeview markup is below:
<telerik:RadTreeView ID="treeView" CheckBoxes="true" PersistLoadOnDemandNodes="true"
TriStateCheckBoxes="True" runat="server" CheckChildNodes="True" CausesValidation="false"
EnableEmbeddedSkins="false" Skin="VBoD">
<WebServiceSettings Path="~/WebServices/Retriever.svc" Method="TreeViewNodeExpand">
</WebServiceSettings>
</telerik:RadTreeView>

I assume signature of service method is stronly fixed:
RadTreeNodeData[] WebServiceMethodName(RadTreeNodeData node, object context).
You should rename 'ExpandedNode' to 'node'.

Related

Why objectdatasource is executing obsolete method without any error?

ObjectDataSource is not recognizing obsolete method and executing it as normal method.
ObjectDataSource is not identifying the obsolete attribute where as the code behind file recognizes the obsolete method and throwing an error during compilation/build.
public class TEST
{
public TEST()
{
//
// TODO: Add constructor logic here
//
}
[Obsolete("Old method", true)]
public DataTable GetData()
{
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Desc");
for (int i = 0; i < 10; i++)
{
DataRow drow = dt.NewRow();
drow[0] = "Name_" + i.ToString();
drow[1] = "Desc_" + i.ToString();
dt.Rows.Add(drow);
}
return dt;
}
}
ASPX
<form id="form1" runat="server">
<div>
<asp:GridView ID="Gridview1" runat="server" DataSourceID="ObjectDataSource1" EnableModelValidation="True"></asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetData" TypeName="TEST"></asp:ObjectDataSource>
</div>
</form>
ASPX.CS
Am I missing any settings here? Please help and let me know if additional information is required.
Thanks in advance.
The problem is that the markup is not compiled at design time.
<asp:ObjectDataSource ID="ObjectDataSource1"
runat="server"
SelectMethod="GetData"
TypeName="TEST">
</asp:ObjectDataSource>
So no compiler is invoked when you add or edit the value in the SelectMethod attribute, hence no error or warning is raised.
In the description of the ObsolteAttribute we find:
Initializes a new instance of the ObsoleteAttribute class with a workaround message and a Boolean value indicating whether the obsolete element usage is considered an error.
Key is here the word usage. When the method is used in a declarative and/or late bound manner the compiler couldn't detect it's usage hence no error is raised. The method is still compiled and present in the assembly. There will no runtime exception be raised.
An ObjectDataSource instance uses reflection to invoke the method. Deep inside its bowels you'll find this (simplified):
Type type = this.GetType(this.TypeName);
MethodInfo method = type.GetMethod(this.SelectMethod, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
objectDataSourceResult = method.InvokeMethod(this, null);
Which basically lookups the method at runtime and invokes it. You can even change the value of SelectMethod during runtime and the code will still work. The obsolete attribute is not taken into account once the assemblies are compiled.

Variables inside control properties

This code:
<asp:TextBox runat="server" MaxLength="<%=Settings.UsernameMaxLength %>" ID="Username"/>
Throws a parser error.
Is it possible to set properties in any way similar to this without using the code behind?
No, it is not possible. Syntax <%= some code here %> cannot be used with server-side controls. You can either go with <%# some code here %>, but only in case of data binding, or just set this property in code behind, say on Page_Load:
protected void Page_Load(object source, EventArgs e)
{
Username.MaxLength = Settings.UsernameMaxLength;
}
You may try this, which should set the MaxLength value upon rendering :
<%
Username.MaxLength = Settings.UsernameMaxLength;
%>
<asp:TextBox runat="server" ID="Username"/>
I think (not tried) you can also write :
<asp:TextBox runat="server" MaxLength="<%#Settings.UsernameMaxLength %>" ID="Username"/>
But you would then need to call Username.DataBind() somewhere in the codebehind.
I'm late to the party here, but here goes anyway...
You could build your own Expression Builder to handle this case. That would allow you to use syntax like this:
<asp:TextBox
runat="server"
MaxLength="<%$ MySettings: UsernameMaxLength %>"
ID="Username"/>
Note the $ sign.
To learn how to make you own Expression Builder, please go through this old but still relevant tutorial. Don't let the wall of text scare you off because in the end, making an expression builder is easy. It basically consists of deriving a class from System.Web.Compilation.ExpressionBuilder and overriding the GetCodeExpression method. Here is a very simple example (some parts of this code was borrowed from the linked tutorial):
public class SettingsExpressionBuilder : System.Web.Compilation.ExpressionBuilder
{
public override System.CodeDom.CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, System.Web.Compilation.ExpressionBuilderContext context)
{
// here is where the magic happens that tells the compiler
// what to do with the expression it found.
// in this case we return a CodeMethodInvokeExpression that
// makes the compiler insert a call to our custom method
// 'GetValueFromKey'
CodeExpression[] inputParams = new CodeExpression[] {
new CodePrimitiveExpression(entry.Expression.Trim()),
new CodeTypeOfExpression(entry.DeclaringType),
new CodePrimitiveExpression(entry.PropertyInfo.Name)
};
return new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression(
this.GetType()
),
"GetValueFromKey",
inputParams
);
}
public static object GetValueFromKey(string key, Type targetType, string propertyName)
{
// here is where you take the provided key and find the corresponding value to return.
// in this trivial sample, the key itself is returned.
return key;
}
}
In order to use it in your aspx page, you must also register it in web.config:
<configuration>
<system.web>
<compilation ...>
<expressionBuilders>
<add expressionPrefix="MySettings" type="SettingsExpressionBuilder"/>
</expressionBuilders>
</compilation>
</system.web>
</configuration>
This is just to show you that it's not difficult. But please review the tutorial I linked to in order to see an example of how to deal with the expected return type from your method depending on the property being assigned etc.

HiddenField.value is undefined in JS

In my aspx markup I have the following defined:
<asp:HiddenField runat="server" ClientIDMode="Static" ID="hidField" />
I have C# code as follows, which gives my hidden field a value:
hidField.value = check().ToString();
assume that check is a function which returns true, for simplicity.
I made JS code to do the following:
_myBool = $("#hidField");
alert(_myBool.value);
This alerts undefined.
For debugging purposes, I stepped through and saw that in C#, hidField.value is indeed true.
And I tried alerting _myBool.length which returned 1 and _myBool which returned [Object object] so Im not calling undefined on undefined.
Try this
_myBool = $("#hidField"); //my bool is a jQuery Object
alert(_myBool.val()); //can only get value with .val()
OR
_myBool = $("#hidField")[0]; //[0] gets the element in the object
alert(_myBool.value); //can use the javascript .value
Missing $ symbol..
var _myBool = $("#hidField");
alert(_myBool[0].value); // DOM Object
alert(_myBool.val() ); // jQuery Object
Also note the selector might Not work with runat="server" attribute as it prepends the content placeholder..
This is a better selector
var _myBool = $('[id*="hidField"]');
You forgot the dollarsign and also use the val() function
alert($("#hidField").val());
Make sure you are using the right ID:
_myBool = $("#<%= hidField.ClientID %>").val();
View your source when the page loads and check for that field. Chances are the ID is not "hidField". The code above will be correct.

Is there a way to drop static declaration from page method?

For a site I'm developing I have two html buttons, not ASP because I do not want them to postback. For the submit button I am calling a javascript function that implements PageMethods to call a C# method from the codebehind. Here is the code for the buttons and the javascript.
<fieldset id="Fieldset">
<button onclick="SendForm();">Send</button>
<button onclick="CancelForm();">Cancel</button>
</fieldset>
<asp:ScriptManager ID="ScriptManager1" EnablePageMethods="true" EnablePartialRendering="true" runat="server" />
<script type="text/javascript">
function SendForm() {
var email = $get("txtEmail").value;
PageMethods.SendForm(email, OnSucceeded, OnFailed);
}
function OnSucceeded() {
$get("Fieldset").innerHTML = "<p>Thank you!</p>";
}
function OnFailed(error) {
alert(error.get_message());
}
</script>
The codebehind method shown here:
[WebMethod]
public static void SendForm(string email)
{
if (string.IsNullOrEmpty(email))
{
throw new Exception("You must supply an email address.");
}
else
{
if (IsValidEmailAddress(email))
{
bool[] desc = new bool[14];
bool[] local = new bool[14];
bool[] other = new bool[14];
for (int i = 1; i <= 14; i++)
{
desc[i] = ((CheckBox)Page.FindControl("chkDesc" + i.ToString())).Checked;
local[i] = ((CheckBox)Page.FindControl("chkLocal" + i.ToString())).Checked;
other[i] = ((CheckBox)Page.FindControl("chkOther" + i.ToString())).Checked;
/* Do stuff here */
}
}
else
{
throw new Exception("You must supply a valid email address.");
}
}
}
does not work unless it is declared as static. Declaring it as static blocks me from checking the checkboxes on the page because it generates a "An object reference is required for the non-static field, method, or property" error. So my problem can be fixed from either of two directions. A) Is there a way I can have this method work without declaring it as static? B) How do I check the checkboxes if the method is static.
It has to be static, no way around that; But you can access the Page like this
Page page = HttpContext.Current.Handler as Page;
and do FindControl on this page instance.
desc[i] = ((CheckBox)page.FindControl("chkDesc" + i.ToString())).Checked;
Page Methods are a special case of the legacy ASMX web service technology. They allow you to place the service in the codebehind class for the page, and keep you from needing a separate project for the service.
But they will never be able to access anything on the page itself. You'll have to do that from the client side, and pass the values of the check boxes to the service.
If you need to check the checkboxes, then you need to either use an UpdatePanel to do your AJAX stuff, or return something from your page method (ideally a string) and check the checkboxes based on what's returned in javascript on client.

How to pass data to an Ajax Service using Telerik Rad Grid Binding?

I have a Telerik RadGrid in which I'm implementing custom paging binding to a Ajax Service. How do you pass data like a Search String to the Web Method?
The Mark up looks something like this:
<telerik:RadGrid ID="radGridProviders" runat="server" AllowPaging="True" PageSize="10" AutoGenerateColumns="false" >
<PagerStyle Mode="NextPrevAndNumeric" />
<MasterTableView TableLayout="Fixed" >
<Columns>
...
</Columns>
</MasterTableView>
<ClientSettings>
<Scrolling AllowScroll="True" EnableVirtualScrollPaging="True" UseStaticHeaders="True">
</Scrolling>
<DataBinding Location="/AjaxServices/SearchService" SelectMethod="GetProductData" SelectCountMethod="GetProductCount" StartRowIndexParameterName="startRowIndex" MaximumRowsParameterName="maxRows" />
<ClientEvents OnCommand="showLoadingPanel" OnDataBound="hideLoadingPanel" />
</ClientSettings>
</telerik:RadGrid>
I want to pass to my Service a search string and/or other customer parameters How do I do it with the RadGrid Binding?
My service that responds to the requests is an ASP.NET MVC Controller. The service responds fine to requests from the browser. My problem is that I don't know how to pass custom data using the Telerik binding features.
public class SearchServiceController : Controller
{
private ISearchController _searchController;
public SearchServiceController(ISearchController searchController)
{
_searchController = searchController;
}
public int GetProductCount()
{
int returnValue = 0;
// brevity brevity
return returnValue ;
}
public List<SearchProviders_Result> GetProductData(int startRowIndex, int maxRows)
{
// brevity brevity
}
}
Any Suggestions?
This is what I found with a little help from Telerik Support.
In the ClientSetting of the RadGrid add a method to the ClientEvents OnDataBinding. My name method name is OnClientDataBinding in this example
Then create the client method:
// This OnClient DataBinding builds the arguments uses to call the
// Ajax Service used to retrieve that when needed.
function OnClientDataBinding(sender, args) {
// get data source location, method name and arguments
var dataSourceLocation = args.get_location();
var selectMethodName = args.get_methodName();
var methodArguments = args.get_methodArguments();
...
I actually modified the sortExpression and fitlerExpresion and these are passed as an Array.
// construct arguments for Ajax Service
var myMethodArguments = new Object();
myMethodArguments.startRowIndex = methodArguments.startRowIndex;
myMethodArguments.maximumRows = methodArguments.maximumRows;
myMethodArguments.sortExpression = sortExpression;
myMethodArguments.filterExpression = filterExpression;
myMethodArguments.myParam1 = "David";
myMethodArguments.myParam2 = 14926;
args.set_methodArguments(myMethodArguments);
}
Then create your Service Controller Method something like:
public JsonResult GetCustomerSearchResults(int startRowIndex, int maximumRows, string sortExpression, FilterExpression[] filterExpression, string myParam1, int myParam2)
{
IEnumerable results;
... fill your Data and Count.
return Json(new { Data = results.ToList(), Count = totalNumberOfRows });
}
FilterExpression[] is an object that I created for my use. This is not a Telerik object.

Categories

Resources