Silverlight VirtualizingPanel recycling containers display wrong content - data-binding

I recently wrote an implementation of a VirtualizingWrapPanel that recycles containers as they scroll into and out of view.
On occasion I've noticed that the content rendered by the control is actually the previously contained data, not the current data. Performing any action on the control that forces a new render call updates the control such that it displays the correct data.
Could this a bug in the ItemContainerGenerator recycling or is it more likely in my recycling code? Is there a way I can force all my bindings to update (after updating the control with new content) without explicitly writing each binding expression in code behind?

I've seen problems very like this in the past when using virtualization when we were using custom controls that really weren't expecting their DataContexts to be changed once they were displayed.
If your panel is correctly (as it sounds) handing new DataContexts to the reused objects then it does sound like the reused objects aren't processing that DataContext change correctly. (This 'render' call you talk about would then pick up the new DataContext and display that.)
If you're using plain data binding in your control then I'm slightly stumped. (Is your panel re-Measure/Arranging the controls after they've got their new DataContext?)
The fix for us was to have our controls listen out for when their DataContext changed. (This is also useful for debugging virtualizing panels to test that the DataContext is coming in correctly.)
Sadly the OnDataContextChanged method isn't public in Silverlight but you can still find out about DC changes by binding to them.
public MyClass()
{
InitializeComponent();
SetBinding(MyDataContextProperty, new Binding());
}
private static readonly DependencyProperty MyDataContextProperty =
DependencyProperty.Register("MyDataContext",
typeof(object),
typeof(MyClass),
new PropertyMetadata(DataContextChanged));
private static void DataContextChanged(
object sender,
DependencyPropertyChangedEventArgs e)
{
MyClass source = (MyClass)sender;
source.OnDataContextChanged();
}
private void OnDataContextChanged()
{
// My DataContext has changed; do whatever is needed.
// re 'render' in your case?
}

Related

Concurrency exception with Devexpress ASPXGridView and EntityFramework 4.3.1

My Issue
I have a simple WebForms project for testing concurrency.
I am using:
1. Entity Framework 4.3.1 code first approach.
2. DevExpress ASP.net controls to visualize my data. Specifically an ASPXGridView control.
3. MySQL as database backend.
Now I am having an issue with the concurrency check.
Even if I am the only user editing the data, if I edit the same record twice using the DevExpress ASPXGridView I get a concurrency exception!
The exception I get is :
System.Data.OptimisticConcurrencyException
My Setup
** Simplified here for brevity
My code first entity is defined something like this:
public class Country
{
//Some constructors here
[Required, ConcurrencyCheck]
public virtual string LastUpdate { get; set; }
[Required, Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public virtual int CountryID { get; set; }
//Various other data fields here
}
You can see I have added a single field called LastUpdate which the concurrecny check is being tested against due to setting the [ConcurrencyCheck] attribute.
On my web page with the DevExpress ASPXGridView I am using an EntityDataSource to make the binding between the grid view and the entity framework. The grid view is using a popup editor. I have the following events hooked:
protected void Page_Load(object sender, EventArgs e)
{
//Hook entity datasource to grid view
dbgCountries.DataSource = CountriesEntityDataSource;
dbgCountries.DataBind();
}
protected void CountriesEntityDataSource_ContextCreating(object sender, EntityDataSourceContextCreatingEventArgs e)
{
//Create and hook my DBContext class to the entity
//datasources ObjectContext property.
var context = new MyDBContextClass();
e.Context = ((IObjectContextAdapter)context ).ObjectContext;
}
protected void dbgCountries_InitNewRow(object sender, DevExpress.Web.Data.ASPxDataInitNewRowEventArgs e)
{
//I create a new MyDBContextClass here and use it
//to get the next free id for the new record
}
protected void dbgCountries_CustomErrorText(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomErrorTextEventArgs e)
{
//My code to catch the System.Data.OptimisticConcurrencyException
//excpetion is in here.
//I try to rtefresh the entity here to get the latest data from
//database but I get an exception saying the entity is not being
//tracked
}
protected void dbgCountries_RowValidating(object sender, DevExpress.Web.Data.ASPxDataValidationEventArgs e)
{
//Basic validation of record update in here
}
protected void dbgCountries_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
//I set the LastUpdate field (my concurrency field)
//to the current time here
}
I also have some button events hooked to test a direct concurrecny test.
eg
- Get Entity
- Update Entity
- Update DB directly with sql
- Save Entity
- Get concurrency exception as expected
eg
- Get Entity
- Update Entity
- Save Entity
- No issue.
- Get Entity again.
- Update Entity again.
- Save Entity again.
- No issue.
These buttons work as expected. Only ther grid updates seem to have an issue.
Maybe it is because the grid needs to use ObjectContect and my entity framework classes are using DBContext?
My Attempted Fixes
I have scoured the internet trying to find a solution. Checked DevExpress forums, checked other posts here on StackOverflow, various posts on the internet, Microsoft MSDN articles on concurrency and I just can not work this out.
None of the posts were as 'simple' as mine. They all had other data involved. eg a master/detail
relashionship. custom editors. etc. I am using all inbuild DevExpress controls and just display a
single grid view on my db table / entity.
Some posts suggest refreshing the entities. I tried this but get an exception saying the entity is
not being tracked in the object state manager.
I tried refreshing the entity framework by destroying and recreating my object context / db
context but somehow I still get the concurrency issue.
I tried refreshing using the DBContexct and also the ObjectContext. Neither worked.
(objContext.Refresh(RefreshMode.StoreWins, entity). I either get an exception as stated]
earlier sayign the entity is not being tracked, or if I tell it to refresh only non modifed
entities then nothing happens at all (no refresh, no excpetion)
I tried making my DBContext global but this is no good as WebForms appears to want to recreate its
entire state and rehook its grids data context etc after every web refresh. (page loads, user
clicks edit, user clicks ok to update)
Now all of these solutions seem to takle what to do AFTER the concurrency exception. Seeing that I should not even be getting the exception in the first place I guess they would not help.
Suggestions
Do any of you have suggestions on how to make this work?
Do I have to maybe force the entity framework to refresh manually after posting data from the grid?
(I only just thought of this one now)
It seems a pretty simple setup I have. Maybe I am missing something very obvious. I have not worked with WebForms or EntityFramework much yet so there could be simple (and perhaps obvious) solutions I am missing?
Any help appreciated.
Thanks
Peter Mayes
I have managed to solve my issue.
It may not be the most correct solution but it is working and any progress at this point is much appreciated.
Approach
I tried refreshing Entity Framework after posting data in the ASPXGridView.
Many attempts. None worked.
I tried using a TimeStamp attribute on my Country entity but this did
not seem to map very well to MySQL. (However I might try this again now
I have solved the issue)
I then thought maybe my DevArt MySQL dot connector and MySQL was at fault.
So I switched over to MSSQL and its standard connector. This showed the same
issue am having with MySQL & co.
Finally I was mucking around with various attempts and noticed that if I go to a different
page on my web site, then back again the issue does not occur.
E.g.:
Edit Country and Save. No Issues.
Switch to other site page.
Switch back to Countries.
Edit Country and Save. No Issues.
The difference being, if I do not switch pages the second edit creates a concurrency exception.
With some more testing with co-workers I got a hunch that maybe the viewstate for the
entity datasource was not being refreshed after a post/update on the ASPGridView.
So what I did was:
> Set EntityDataSource.StoreOriginalValuesInViewState = FALSE
This stopped all concurrency working as no old/pre edit values were being stored and so
were not available for the concurrecny check.
I then thought I would force the oldvalues to be what was in the editor before I edited.
I was using ASPXGridView.RowUpdating to do this.
I thought thats ok, I can just use the OldValues passed to ASPXGridView.RowUpdating to
ensure entity framework is good to go.
Doing this I found some very odd behaviour...
If I:
- open edit form in browser A
- open edit form in browser B
- save changes in browser B (DB updates with new values here)
- save changes in browser A (DB updated here too. but should have been a
concurrency exception!)
The reason post from A was succeeding was that OldValues on A had been magically updated
to the new values B had posted!
Remember the edit form on A was open the whole time so it should not have updated its OldValues underneath. I have no idea why this occurs. Very odd.
Maybe OldValues are not retrieved by the DevExpress ASPXGridView until the
edit form is closing?
Anyway, then I thought. Fine, I will just work around that oddity. So to do so I created
a static member on the web page to store a copy of my Country entity.
When the user goes to open the editor I get the current values and store them.
Then when ASPXGridView.RowUpdating fires I push the stored old values back into the
OldValues data. (I also update my timstamp/concurrency field here too in the NewValues
data)
With this approach my concurrency now works. Hurah!.
I can edit locally as much as I want and get no conflicts. If I edit in two browsers at once the second one to post raises concurrency exception.
I can also switch between MySQL and MSSQL and both work correctly now.
Solution Summary
Set EntityDataSource.StoreOriginalValuesInViewState = FALSE. (I did this in the designer.)
Create private member to hold pre-edit country values
private static Country editCountry = null;
Hook StartRowEditing on ASPXGridView. In here I get the current country values and store them as 'pre edit' values. Note that CopyFrom is just a helper method on my entity.
protected void dbgCountries_StartRowEditing(object sender, DevExpress.Web.Data.ASPxStartRowEditingEventArgs e)
{
if (editCountry == null)
{
editCountry = new Country();
}
var context = new MyDBContext();
var currCountry = context.Countries.Where(c => c.CountryID == (int)(e.EditingKeyValue)).Single();
editCountry.CopyFrom(currCountry);
}
Hook RowUpdating on ASPXGridView. Here is where I make sure old values are correct before update goes ahead. This ensures concurrency will work as expected.
protected void dbgCountries_RowUpdating(object sender, DevExpress.Web.Data.ASPxDataUpdatingEventArgs e)
{
//Ensure old values are populated
e.OldValues["RowVersion"] = editCountry.RowVersion;
//No need to set other old values as I am only testing against
//the one field for concurrency.
//On row updating ensure RowVersion is set.
//This is the field being used for the concurrency check.
DateTime date = DateTime.Now;
var s = date.ToString("yyyy-MM-dd HH:mm:ss");
e.NewValues["RowVersion"] = s;
}

Is it right to instantiate active classes outside of Page_Load?

a quick question for an ASP.NET expert. It is an arguable moment for us in the company at the moment...
We have built a nice (no bugs in there) CMS framework that we use for our sites...
It goes something like this:
MyCms.Content.Channels channels = new MyCms.Content.Channels();
where at the moment of instantiating the Channels class, it loads a bunch of XML files and converts them to a List<MyCms.Content.Channels.Channel> that is held within the Channels class, and cached using System.Web.HttpRuntime.Cache (until there are any changes to the folder holding the XML files)
The Channels class is basically a hierarchical structure for web pages...
We normally use it like this in our ASP.NET pages (code behind):
public partial class Default : System.Web.UI.Page
{
public MyCms.Content.Channels channels;
public MyCms.Content.Images images;
public MyCms.Content.Channels.Channel CurrentChannel;
public List<MyCms.Content.Channels.Channel> latestItems;
public MyCms.Content.GameVotes votes;
public MyCms.Content.GameVotes.Vote vote;
protected void Page_Load(object sender, EventArgs e)
{
channels = new MyCms.Content.Channels();
images = new MyCms.Content.Images();
..
}
as you can see, the public variable 'channels' is instantiated at Page_Load()... where at the moment it has loaded a bunch of XML files either from a file system, or from cache...
Our colleague though, is sometimes instantiating this class outside of Page_Load() - right next to the public declaration of the 'channels' variable like this:
public partial class Default : System.Web.UI.Page
{
public MyCms.Content.Channels channels = new MyCms.Content.Channels();
protected void Page_Load(object sender, EventArgs e)
{
... he does the same in various User Controls...
Now thing is.. I need your opinion on whether it's ok to instantiate a very active class like this - outside of Page_Load() event... ? The site that was built by our colleague was hanging the entire IIS from time to time, and I just suspect that this could be one reason... - what do you think, please ? :)
The same CMS Framework is being used on other sites, on other servers with no issues at all... So the only difference I could find between the good working sites and the one that is hanging - is this .. instantiation of 'channels' class outside the scope of Page_Load()...
It shouldn't make a difference. That's not to say it doesn't.
All that's happening is you're changing the point at which you create the object from load event, which happens about half way through the lifecycle to the constructor, right at the very start. At both points the cache should be available as it's part of the context, although you really ought to check that.
I would say though, instantiating such an important class should happen at a specific point, like page initialise or load, rather than at constructor.
Simon
The only difference I'm aware of is that if you initialize the objects outside of the Page_Load they will be created as soon as your page's class is created (i.e. before all the Page_XXX events), and if you initialize them inside the Page_Load they will be created only when the event is called.
That means if your application crashes, redirects or for whatever reason does not enter Page_Load, you have created the object uselessly.

With ASP.NET viewstate, is there a best practice for when in the lifecycle to access the viewstate?

In building custom controls, I've seen two patterns for using the viewstate. One is to use properties to disguise the viewstate access as persistent data.
public bool AllowStuff
{
get
{
return (ViewState[constKeyAllowStuff] != null) ?
(bool)ViewState[constKeyAllowStuff] : false;
}
set { ViewState[constKeyAllowStuff] = value; }
}
The other is to use private member fields and to override the Load/SaveViewState methods on the control and handle it all explicitly:
protected override object SaveViewState()
{
object[] myViewState = new object[2];
myViewState[0] = base.SaveViewState();
myViewState[1] = _allowStuff;
return myViewState;
}
protected override void LoadViewState(object savedState)
{
object[] stateArray = (object[])savedState;
base.LoadViewState(stateArray[0]);
_allowStuff = (bool)stateArray[1];
}
(I cut out a lot of safety checking for clarity, so just ignore that.)
Is there are particular advantage to one method over the other? I can't see how they'd differ much performance wise. Version 1 is lazy, so I guess you save a bit if you don't need that particular value during a pass. Version 1 is also more abstract, hides the details better. Version 2 is clearer about when the data is actually valid and ok to read or modify (between the load and save) because it more clearly works within the ASP.NET lifecycle.
Version 2 does tend to require more boilerplate code though (a property, a backing private field, and viewstate handling in two places) as opposed to Version 1 which combines all that into one place.
Thoughts then?
The private member field approach is often used for objects who do not directly have access to the ViewState state bag. So in a sense, I'd use option one for custom controls, user controls, or pages, or anything that has a ViewState or similar property, but use the other option for an object that does not directly have access to ViewState (like a class you want to be able to "serialize" and store in viewstate). For instance, custom controls would use that approach to store state for child objects that do not directly reference viewstate.
HTH.
Fist of all I would use ControlState and not viewstate so it works correctly if in a container that has view state turned off.
Then i would override init, savecontrolstate, loadcontrolstate and databind.
and make sure to register that the control uses the control state i.e. Page.RegisterRequiresControlState(this)
oh and the advantage is that your control is more robust (user can't screw it up as easily) and will work when dynamically loaded and across postbacks "better"

Entity Framework ObjectContext re-usage

I'm learning EF now and have a question regarding the ObjectContext:
Should I create instance of ObjectContext for every query (function) when I access the database?
Or it's better to create it once (singleton) and reuse it?
Before EF I was using enterprise library data access block and created instance of dataacess for DataAccess function...
I think the most common way is to use it per request. Create it at the beginning, do what you need (most of the time these are operation that require common ObjectContext), dispose at the end. Most of DI frameworks support this scenario, but you can also use HttpModule to create context and place it in HttpContext.Current.Items. That is simple example:
public class MyEntitiesHttpModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.BeginRequest += ApplicationBeginRequest;
application.EndRequest += ApplicationEndRequest;
}
private void ApplicationEndRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Items[#"MyEntities"] != null)
((MyEntities)HttpContext.Current.Items[#"MyEntities"]).Dispose();
}
private static void ApplicationBeginRequest(Object source, EventArgs e)
{
var context = new MyEntities();
HttpContext.Current.Items[#"MyEntities"] = context;
}
}
Definitely for every query. It's a lightweight object so there's not much cost incurred creating one each time you need it.
Besides, the longer you keep an ObjectContext alive, the more cached objects it will contain as you run queries against it. This may cause memory problems. Therefore, having the ObjectContext as a singleton is a particularly bad idea. As your application is being used you load more and more entities in the singleton ObjectContext until finally you have the entire database in memory (unless you detach entities when you no longer need them).
And then there's a maintainability issue. One day you try to track down a bug but can't figure out where the data was loaded that caused it.
Don't use a singleton.. everyone using your app will share that and all sorts of crazy things will happen when that object context is tracking entities.
I would add it as a private member
Like Luke says this question has been asked numerous times on SO.
For a web application, per request cycle seems to work best. Singleton is definitely a bad idea.
Per request works well because one web page has a User, maybe some Projects belonging to that user, maybe some Messages for that user. You want the same ObjectContext so you can go User.Messages to get them, maybe mark some messages as read, maybe add a Project and then either commit or abandon the whole object graph at the completion of the page cycle.
Late post here by 7 months. I am currently tackling this question in my app and I'm leaning towards the #LukLed solution by creating a singleton ObjectContext for the duration of my HttpRequest. For my architecture, I have several controls that go into building a page and these controls all have their own data concerns that pull read-only data from the EF layer. It seems wasteful for them to each create and use their own ObjectContext's. Besides, there are a few situations where one control may pull data into the Context that could be reused by other controls. For instance, in my masterpage, my header at the top of the page has user information that can be reused by the other controls on the page.
My only worry is that I may pull entities into the context that will affect the queries of other controls. I haven't seen that yet but don't know if I'm asking for trouble. I guess we'll see!
public class DBModel {
private const string _PREFIX = "ObjectContext";
// DBModel.GetInstance<EntityObject>();
public static ObjectContext GetInstance<T>() {
var key = CreateKey<T>();
HttpContext.Current.Items[key] = HttpContext.Current.Items[key] ?? Activator.CreateInstance<T>();
return HttpContext.Current.Items[key] as ObjectContext;
}
private static string CreateKey<T>() {
return string.Format("{0}_{1}", _PREFIX, typeof(T).Name);
}
}

What is the best way to reuse pages from one website in another?

I'm developing a new ASP .NET website which is effectively a subset of the pages in another site we've just released. Two or three of the pages will need minor tweaks but nothing significant.
The obvious answer is to simply copy all of the code and markup files into the new project, make the aforementioned tweaks, and consider the job done. However I'm not keen on this at all due to the amount of duplicated code it will create.
My next idea was to move the code for the pages (i.e. the code-behind file) into a separate assembly which can then be referenced from both sites. This is a little awkward however as if you don't take the designer file with it, you get a lot of build errors relating to missing controls. I don't think moving the designer file is a good idea though as this will need to be regenerated each time the markup is altered.
Does anyone have any suggestions for a clean solution to this problem?
You might want to take a look at the MVP pattern. Since you are probably using WebForms it would be hard to migrate to ASP.Net MVC, but you could implement MVP pretty easily into existing apps.
On a basic level you would move all the business logic into a Presenter class that has a View that represents some sort of interface:
public class SomePresenter
{
public ISomeView View{get; set;}
public void InitializeView()
{
//Setup all the stuff on the view the first time
View.Name = //Load from database
View.Orders = //Load from database
}
public void LoadView()
{
//Handle all the stuff that happens each time the view loads
}
public Int32 AddOrder(Order newOrder)
{
//Code to update orders and then update the view
}
}
You would define your interface to hold the atomic types you want to display:
public interface ISomeView
{
String Name {get; set;}
IList<Order> Orders{get; set;}
}
Once those are defined you can now simply implement the interface in your form:
public partial class SomeConcreteView : System.Web.UI.Page, ISomeView
{
public SomePresenter Presenter{get; set;}
public SomeConcreteView()
{
Presenter = new SomePresenter();
//Use the current page as the view instance
Presenter.View = this;
}
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
Presenter.InitializeView();
}
Presenter.LoadView();
}
//Implement your members to bind to actual UI elements
public String Name
{
get{ return lblName.Text; }
set{ lblName.Text = value; }
}
public IList<Order> Orders
{
get{ return (IList<Order>)ordersGrid.DataSource; }
set
{
ordersGrid.DataSource = value;
ordersGrid.DataBind();
}
}
//Respond to UI events and forward them to the presenter
protected virtual void addOrderButton_OnClick(object sender, EventArgs e)
{
Order newOrder = //Get order from UI
Presenter.AddOrder(newOrder);
}
}
As you can see, your code behind is now extremely simple so code duplication is not a big deal. Since the core business logic is all wrapped up in a DLL somewhere, you don't have to worry about functionality getting out of sync. Presenters can be used in multiple views, so you have high reuse, and you are free to change the UI without affecting the business logic as long as you adhere to the contract.
This same pattern can apply to user controls as well, so you can get as modular as you need to. This pattern also opens up the possibility for you to unit test your logic without having to run a browser :)
The patterns and practices group has a nice implementation of this: WCSF
However, you don't have to use their framework to implement this pattern. I know this may look a little daunting at first, but it will solve many of the problems (In my opinion) you are running into.
Create user controls (widgets) or templates to tweak what you want to achieve.
It might also be possible to achieve the same with CSS styles or JavaScript.
Why not create user controls (or custom controls) from the pages which you wish to share? You can then re-use these across both sites.
What we use in our project (JSP, not ASP, but when it comes to building and files it surely isn't an issue?) is to have a base folder of common files, and then another ("instance") folder of additional files and overwrites, and our build script (in ANT, Maven should be fine too) will first copy the base folders, and then based upon a parameter supplied select which instance's files to copy across as well.
Thus we can change a file in the base, and have it apply across all instances.
An issue is that changing a base file will not update any instance file that overwrites it but at least you can make a process for these updates. Presumably you could also use the SVN (etc) revision to flag a build error is an instance file is older than a base file, but we haven't implemented anything that clever yet.
In addition your back-end code (Struts actions in our case) will end up handling all cases rather than any particular instance's cases only. But at least all the code is in one place, and the logic should be clear ("if (instance == FooInstance) { doFooInstanceStuff(...); }").

Resources