I've got 2 CascadingDropdownList, Application and Role. When Application changes Role is populated.
I do a partial rendering of a UpdatePanel with User List when Application or Role changes.
The problem is that when Application changes the value of Role sent in the POST to render UpdatePanel is the old Role value before Role is populated whih the list of roles of the new emphasized textselected Application.
So, the solution I am trying is to do the partial rendering after Role is populated. I remove Application trigger from the UpdatePanel and launch a postback by hand using populated event in Role CascadeDropDownList.
This way, when Application changes, Role is populated and (thanks to the event) UpdatePanel is updated. When Role changes the basic trigger in UpdatePanel makes the updated.
Code Behind:
ToolkitScriptManager.RegisterStartupScript(Me, Me.GetType,"wireEvents","Sys.Application.add_load(addPopulatedEvent);", True)
HTML:
<script>
function updatePanel() { __doPostBack('<%=UpdatePanel1.ClientID %>', null); }
function addPopulatedEvent(sender, args) {if (!args.get_isPartialLoad()) { $find('<%=cmbRoles_CascadingDropDown.ClientID %>').add_populated(updatePanel); } }
</script>
And another problem raises. I can see in firebug network how the partial rendering POST launch at the same time, sometimes even before, that the populate roles POST. And still see the old 'pre-populated' value of Role in the partial rendering POST. In a few words: CascadingDropdownList populated event does not rise after the CascadingDropdownList is populated. It is weird because the event verb is in past form and a populating event also exist. So everything tells me that populated event should rise after Role is filled with the new data. But not.
2 Questions:
Am I doing something wrong about CascadingDropDownList events?
In the case my solution could not never work, could you point me to another working solution?
It was a real bug. Fixed in v15.1.3 version. Here is the issue report.
Related
I'm currently working with a form that has a grid at the bottom. Whenever I hit f5, the grid refreshes, but the rest of the form does not. What can I do to make the entire form refresh it's data?
Thanks.
You may override the research method on a datasource:
public void research(boolean _retainPosition = false)
{
super(_retainPosition);
other_ds.research(_retainPosition);
}
The other_ds is a datasource not joined by the current datasource.
It depends on the form you are working with. When you hit F5 on a record, it runs the research method on the datasource the record belongs to or its parent datasource (depends on the form's query, e.g. if you hit F5 on SalesLine in the SalesTable form, SalesTable_ds.research(true) will be run). As I see it, if the rest of your form displays fields that belong to these datasources then these fields will be updated. If the fields do not belong to these datasource the rest of your form will not be updated (unless e.g. the active method has been overridden to refresh the rest of the form from the code.
What you can do to make the entire form refresh its data when F5 is hit: again, it depends on the form, so not knowing all the details it is difficult to advise something, but one of the things you can do is override the research method on your datasource and refresh the rest of the form programatically from there. It is more common to override the active method, you should normally go for it.
Hopefully there is an obvious answer to this that my brain at 2am is not seeing (I'm basing this on the fact I can't find anyone else with the same problem).
When I press the "hardware/built in" back button on my windows phone 7 none of my bindings are re-evaluating. For example on my MainPage I have a button's "IsEnabled" bound to a bool property in my ViewModel that checks if a value is in isolated storage. In the emulator it starts as disabled (obviously). I then navigate to another page and add the required value to isolated storage. When i press the hardware back button to return to the original page the binding does not get re-evaluated and my button remains disabled.
However if I go back to MainPage via code using the navigate method the binding gets re-evaluated and everything is good.
Any ideas as to why?
The issue sounds like the RaisePropertyChanged method isn't being raised by your MVVM Light ViewModel - if you're binding Get{} accessor of your IsEnabled property on the viewmodel directly to a value in IsolatedStorage, then the ViewModel isn't going to know that that underlying value has necessarily changed.
When you write the value to IsolatedStorage, you can use the Messenger interface in MVVM to notify the ViewModel-in-question that it should fire the RaisePropertyChanged() event for your model, and that will re-bind that property in your view.
When you use the NavigationService.Navigate method, you are actually performing a forwards navigation and a new instance of your page is created. When you press the hardware back button, a backwards navigation is performed and the previous page is re-displayed. Almost all of the time, what you get is a cached version of the original instance of the page.
You could re-evaluate any bindings in the OnNavigatedTo override for the page, but this introduces a fair bit of 'code smell'. As mentioned above, using the Messenger will enable you to update the associated view model, which will update the binding on the page.
I am working on a project which creates controls dynamically for a form in the page_load event, loads in their current values from the database and saves their values (using FindControl) when the user clicks the continue button.
When I added a control statically in the .aspx page and followed their same procedure of loading the value in the page load and saving it on the button press I found that the value would not save correctly. It seems that it wouldn't save because the click event fires after the page_load, so the page_load of the post back reverted the value and the user entered value was not saved.
The strange thing is that by changing the control to be dynamically created just as all the other controls on the page and keeping the loading and saving the same it now works. Even though the page load still creates the control with the old database value.
It seems like a very fundamental asp .net feature here but i'm just unclear as to what is going on. I suspect it is to do with the timing of creation and maybe when the view state kicks in.
Static page controls are created just like dynamic page controls. The difference might be coming in your Page_Load. Whenever you postback all the controls are created afresh which means they are created with their initial values. This happens because after creating the controls asp.net throws away the controls/objects.
So, when the request comes, the first thing that asp.net does it to recreate the controls by looking at their definitions (in the designer files). On each postback they are created and initialized again losing their state in the process.
But after creating the controls Asp.Net loads any viewstate that is sent along with the request which makes people think that the state is always saved at the server.
What might be happening is that either the viewstate is not enabled for your control (in case they are created in designer), in which case you may try using EnableViewState property to true of the control.
Or, when you're doing a Page_Load, you're forcefully re-initializing everything. And in process losing all the control data. If you could post the logic of Page_Load, it might get clarified.
Make sure that:
you are not setting the value again for the static control in Page_Load. The dynamic control are probably getting around it by grabbing the ViewState and form values at a different stage in the lifecycle.
The dynamic controls are added After the static control. Or at least they are added in a different container. Placement in the control's collection can affect the ViewState, although it doesn't look like your scenario / since what you mention seems to be more about the values in the current post.
The save is happening After the Page_Load in response to the corresponding event.
I've run into similar problems in the past (quite a few times actually), but what helped me the most is understanding the ASP.NET Page Lifecycle.
Microsoft has an article on it which describes it pretty well, but this post by Solomon Shaffer really cleared up everything.
I suggest reading them both and coming back with additional questions regarding to a particular state, when to load/save data etc..
Hope this helps.
Marko
Note that you may want to use Page.IsPostBack property to avoid reinitializing values on button clicks and other events.
private void Page_Load()
{
if (!this.IsPostBack)
{
// Assign values to the controls.
}
}
I have in my webform many TBs bound to a property in the code behind:
<asp:TextBox ID="tbFirstName" Text="<%# Contact.FirstName %>" runat="server" />
<script language="c#">
public Contact Contact
{
get
{
return (Contact)ViewState["Contact"];
}
}
</script>
<script language="VB">
Public ReadOnly Property Contact() As Contact
Get
return ViewState("Contact");
End Get
End Property
</script>
While Contact is that property.
I want that when the user inserts text, it should immediately be bound to the Contact object e.g. when the user presses a key down or even when losing focus (TextChanged) would be good too.
Is there a way to do it dynamically (rather than manually retrieve the data from all the TBs and update the Contact object)?
I am actually willing to achieve two-way databinding with simple textboxes spread in the form body.
Note: I am not going to store the items to the DB of course, I just want the object (Contact) which resides in the state manager.
Do you realize you're talking about a web application? It's running in the users' browser. In order to update a database, you have to make a round trip to the server, either through AJAX or through a postback. Do you really want to do this for every keystroke?
From your comments, it's apparent that you aren't trying to write back to the database on every keystroke.
Still, data binding doesn't work this way. Data binding is a purely server-side action in ASP.NET. Even the two-way data binding afforded by the Bind method only works on a full postback (though I admit I haven't tried it with an UpdatePanel).
As an experiment, create a new page, and set up two-way databinding (see "Using the FormView for a More Flexible Data Modification User Interface" in An Overview of Inserting, Updating, and Deleting Data for an example). Once you get it working "normally", try putting the FormView into an UpdatePanel and see if the Bind still works. If so, see if you can get the UpdatePanel to fire on every keystroke.
Stop thinking like you are developing a desktop application! Because yo are not. The "Contact" object lives on the server while your textbox "lives" at the client, refreshing the server object would be very costly, you'll have to do async transfers between the server and the client with the new data, and doing it at so shorts intervals wouldn't even be possible. Thought you can add a delay on the textbox after which you would transfer the data to the server. Why would you ever need this?
I am building a asp.net webforms (3.5 sp1) application, using jquery where I can to animate the UI, change its state. It has worked great until I started doing postbacks, where the UI obviously resets itself to its initial state.
So my question is, what are the best practices for saving and restoring jquery/UI state between postbacks?
Thanks, Egil.
Update: Thanks a lot guys, great input, to bad I cant mark more than one answer as the "answer".
I typically store things like menu state or filter (set of inputs in a div) visibility, etc. server-side in the session via AJAX. When a menu expands or a filter is shown, the click handler will fire an AJAX event to a web service that will record the state of the menu or filter visibility in the user's session. On a postback I use the session variables corresponding to each menu/filter to set it's initial state via CSS. I find that this is better user experience since the page doesn't flash when it is updated by javascript after loading if you make the changes client-side.
Example -- as I'm on the road this not actual code from a project and may be incomplete. Uses jQuery. The Url for the web service is going to depend on how you implement web services. I'm using ASP.NET MVC (mostly) so mine would be a controller action.
<script type='text/javascript'>
$(document).ready( function() {
$('#searchFilter').click( function() {
var filter = $(this);
var filterName = filter.attr('id');
var nowVisible = filter.css('display') === 'none';
if (nowVisible) {
filter.show();
}
else {
filter.hide();
}
$.post('/controller/SetFilterVisibility',
{ name: filterName, visibility: nowVisible } );
});
});
</script>
<div id='searchFilter' <%= ViewData["searchFilterVisibility"] %> >
...
</div>
Server-side code
[AcceptVerbs( HttpVerbs.POST )]
[Authorization]
public ActionResult SetFilterVisibility( string name, bool visible )
{
Session[name] = visible;
return Content( string.Empty ); // not used...
}
[AcceptVerbs( HttpVerbs.GET )]
[Authorization]
public ActionResult SomeAction( int id )
{
...
ViewData["searchFilterVisibility"] = Session["searchFilter"];
...
return View();
}
I think you are referring to saving the state of the ui widgets between postbacks (rather than saving user preferences).
A lot of that state is applicable only to a particular widget, for a particular user, after a particular series of interactions (eg expand this tree node, click on that grid row, etc). This stuff doesn't have to go into the database, or even in the session, unless restoring state across page loads is important to you.
All that stuff I tend to put into an object or two, eg:
treeState.expandedNodeId = 'foo';
gridState.selectedRowIndex = 3;
Then I save it in a hidden field periodically:
$('.treeState').val(Sys.Serialization.JavaScriptSerializer.serialize(treeState));
etc.
The value is sent back with the postback result, and I just deserialize it and restore my widgets from the saved values. Annoying, but it works well.
You have two options:
Client side cookie
Store UI settings server side via postback or webmethod calls
The second option will require alot more effort but would allow you to provide 'portable' UI settings that could be applied for a user regardless of client machine. If the settings are 'throw-away', I would go for client side cookies.
How to work with javascript and cookies:
http://techpatterns.com/downloads/javascript_cookies.php
I generally store UI settings server side in a database via postbacks, however if users are changing their UI via jQuery and you want to persist those changes, I would probably go about it something like this:
add a script manager to your aspx page
set EnablePageMethods="true"
create a WebMethod in your codebehind
in your jQuery methods that update the UI, add a call to your WebMethod and pass back the UI setting
store any settings passed to the WebMethod in the database
then when the user visits the page the next time, either fetch the settings and populate as many controls server side as you can, or use the jQuery ready method to make a call to another webmethod that fetches the UI settings from the database, passes them back to jQuery allowing you to populate the controls.
Here is a decent article on jQuery and WebMethod calls:
http://encosia.com/2008/05/29/using-jquery-to-directly-call-aspnet-ajax-page-methods/
The problem you will need to be aware of is EventValidation; you will get into trouble if you fetch control values outside of the scope of the page lifecycle and then expect to use those settings on postback. For example, adding values to a dropdownlist via a webmethod will throw an error on postback, unless those values were also added to the dropdownlist when the page was built.
I'm using HTML5 storage, you can choose how to persist (local storage or per browser session). If you're worried about non HTML5 you can use Amplify.Storage. The downside is that you have to write the code to call the save/read. I'm looking at a way to automate this, if anyone has any ideas then please say. Thanks.