GarbageCollection does not release of memory in Silverlight - c#

I am worried about my application because the longer I use it, the more memory it consumes. I am using Silverlight-enabled WCF service to retrieve datas from the database.
Let me explain the application. There is DataGrid and a frame in MainPage. User enters some datas and after clicking Search button, service gets datas from database and fills the DataGrid. And after this, user can select row and application changes URI of the frame from the ViewModel like that:
// Sending selectedId as Query string
FrameURI = new Uri(
string.Format("/Views/PersonDetails.xaml?SelectedID={0}",
SelectedID,
UriKind.Relative);
I am getting datas of the person with the given ID in OnNavigatedTo event and calling a method which return object with the type of Person:
_id = this.NavigationContext.QueryString["SelectedID"];
if (_id != "")
{
Uri address = new Uri(Application.Current.Host.Source, "../UserServiceName.svc");
UserServiceNameClient client = new UserServiceNameClient("CustomBinding_UserServiceName", address.AbsolutePath);
client.GetPersonByIDCompleted += (sender, event) =>
{
if (e.Result.Name != null)
{
LayoutRoot.DataContext = (Person)e.Result;
}
};
client.GetPersonByIDAsync(_id);
}
But the problem is here. It seems that GC is not kicking in after selecting new id from the DataGrid. After changing selected row in DataGrid, memory of the application keeps growing up. And the storyboards/animations become laggy...
I have read some posts in web, some of them tell that, it is about event handlers. I have tried somethings, but didn't help.
Thanks.

Related

Binding data MVVM after Tap on ListBox

This is my situation:
- I have a WebApi that sends me a json data.
- My app reads this data and binds all information in a list box
- When I tap on Item of the list box I want to show all information about that item
The problem is: How can I bind data on the new view?
This is the code after tap (MainViewModel):
this.ProfessorDetail = new RelayCommand(() =>
{
if (SelectedIndexProfessors != -1)
{
//This variable contain all detail information
Professor x = Professors.ElementAt(SelectedIndexProfessors);
//Open new page
App.RootFrame.Navigate(new Uri("/Pages/ProfessorDetailPage.xaml", UriKind.RelativeOrAbsolute));
}
});
You can use Uri parameter to pass simple string information between pages. For example, in your RelayCommand pass unique information about selected professor :
.........
//pass selected professor Id to ProfessorDetailPage
App.RootFrame.Navigate(new Uri("/Pages/ProfessorDetailPage.xaml?professorId=" + x.ProfessorId, UriKind.RelativeOrAbsolute));
.........
Then in the ProfessorDetailPage's Loaded or NavigatedTo event handler get the uri parameter and display information accordingly :
.........
string professorId;
if(NavigationContext.QueryString.TryGetValue("professorId", out professorId))
{
//load information based on professorId parameter value
}
.........
I never made a page based application, but I was looking at this link and from basic knowledge of WPF, I do know you need to set the DataContext of that page just like you asked.
Take a look at the following code in the link:
this.Frame.Navigate(typeof(BasicPage2), tb1.Text);
That is sending the text entered in tb1 to the object you're navigating to. Then look at how the receiving object is utilizing that information:
private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
string name = e.NavigationParameter as string;
....
}
You're going to want to follow the same idea, except you're going to want to do something like:
App.RootFrame.Navigate(new Uri(".....", ...), x);
And then in the page itself, you're going to want to set up a LoadState event in ProfessorDetailPage control and inside it do:
Professor prof = x as Professor;
if( prof != null)
{
this.DataContext = prof;
}
That should set the DataContext of ProfessorDetailPage and your data should be populated.
Let me know how it works out, hope this helps!

Retrieve Values from asp control in c# code behind

I have looked extensively to find an answer to this question but I only get extremely close. I have a web form that I use to add and edit records. When a record is selected in the gridview, a session variable is set and then used on page load to populate the text fields. If the session variable is not set, the form will be blank and the logic run as a new record. My problem is that I can add a new record successfully - I debugged and checked to make sure the asp controls passed the proper values to the code behind - but I cannot edit a record successfully. For some reason, the code behind file does not retrieve the proper values from the text boxes. Instead, it keeps the original populated values thus defeating the purpose of the edit. I imagine it is a binding issue but I am unsure and have searched upon end. Here is my code behind file:
protected void Page_Load(object sender, EventArgs e)
{
resultOutput.Visible = false;//Output results as to whether or not a record was added successfully is automatically hidden at page load
//Checking to see if session variable has been created
if (Session["editID"] != null)
{
//Create objects to get recipe data
dbCRUD db = new dbCRUD();
Recipe editRecipe = new Recipe();
//Grabbing session ID
var id = Convert.ToInt32(Session["editID"]);
//Call method to retrieve db data
editRecipe = db.SelectRecord(id);
//Populate results to text boxes
recordID.Text = editRecipe.Recipe_ID.ToString();
addName.Text = editRecipe.Name;
addTypeDDL.SelectedValue = editRecipe.Meal;
addDifficultyDDL.SelectedValue = editRecipe.Difficulty;
addCookTime.Text = editRecipe.Cook_Time.ToString();
addDirections.Text = editRecipe.Directions;
//Change Button Text
submitRecord.Text = "Edit Record";
//Change Title Text
addEditTitle.Text = "Edit Recipe";
}
}
protected void submitRecord_Click(object sender, EventArgs e)
{
Recipe recipe = new Recipe();
dbCRUD newRecord = new dbCRUD();
//Variables for execution results
var modified = "";
int returned = 0;
//Creating the recipe Object to pull the values from the form and
//send the recipe object as a parameter to the method containing insert stored procedure
//depending on Add or Edit
//recipe.Recipe_ID = int.Parse(recordID.Text);
recipe.Name = addName.Text.ToString();
recipe.Meal = addTypeDDL.SelectedValue.ToString();
recipe.Difficulty = addDifficultyDDL.SelectedValue.ToString();
recipe.Cook_Time = int.Parse(addCookTime.Text);
recipe.Directions = addDirections.Text.ToString();
//Checking to see if the page is loaded for edit or new addition
if (Session["editID"] != null)
{
recipe.Recipe_ID = Convert.ToInt32(Session["editID"]);
//If recordID exists, recipe will be passed to UpdateRecord method
returned = newRecord.UpdateRecord(recipe);
modified = "has been edited.";
Session.Remove("editID");
}
else
{
//If recordID does not exist, record will be passed to InsertRecord method (new recipe)
returned = newRecord.InsertRecord(recipe);
modified = "added";
}
//Method returns 0 if successful, 1 if sql error, 2 if other error
if (returned == 1)
{
resultOutput.Text = "There was an sql exception";
resultOutput.Visible = true;
}
else if (returned == 2)
{
resultOutput.Text = "There was a non sql exception";
resultOutput.Visible = true;
}
else
{
resultOutput.Text = "\"" + addName.Text + "\" recipe " + modified;
resultOutput.Visible = true;
}
}
Any object passed to my edit method is successful, however, as I mentioned, it does not grab the newly updated text box values.
Did you try checking PostBack property , Your code is loading the data everytime the page is posted back. So when you update the values in the form and hit update button. The Page_Load method is called first and it reloads all the data (replaces your updated values on the form) and then hit the update button event handler. So everytime your old values are being saved.
You may remove the code from page_load method and put it where you are setting the Session["EditId"] value. This will solve your problem.
I would suggest using a static dataset and bind it to the recordsource of the gridview control. Whenever you wanna edit a record update the dataset simultaneously and rebind it to the gridview control....hope that helps:)

ListBox SelectionChanged WP7 to navigate with parameters

So, in the Windows Phone 7 app I'm making, I use a ListBox with a SelectionChanged event handler to navigate a user to a new webpage, showing additional information. The MainPage.xaml shows a ListBox populated with information from a JSON file, which works correctly. However, if a user wants to read more about the news, he/she will have to click on the news in the ListBox, which fires the SelectionChanged event, which looks like this:
private void NewsList_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
int index = NewsList.SelectedIndex;
fetchNewsContent newsContentGetSet = new fetchNewsContent();
newsContentGetSet.newsID = newslistJson.ElementAt(index).news_id;
newsContentGetSet.newsTitle = newslistJson.ElementAt(index).news_title;
newsContentGetSet.newsAbstract = newslistJson.ElementAt(index).news_abstract;
newsContentGetSet.newsContent = newslistJson.ElementAt(index).news_content;
newsContentGetSet.newsAuthor = newslistJson.ElementAt(index).news_author;
newsContentGetSet.newsDatePublished = newslistJson.ElementAt(index).news_date_published_no;
//object[] someobject = { newsContentGetSet.newsID, newsContentGetSet.newsTitle, newsContentGetSet.newsAbstract, newsContentGetSet.newsContent, newsContentGetSet.newsAuthor, newsContentGetSet.newsDatePublished };
NavigationService.Navigate(new Uri("/NewsPage.xaml?obj=" + index, UriKind.Relative));
}
This simply uses a class (newsContentGetSet.cs) with getters and setters for each of the strings (newsID, newsTitle, etc.), but when the SelectionChanged is fired, it the .cs file doesn't set the newly given newslistJson values! Why?
I also tried sending only text parameters in the NavigationService, but the newsContent string was too long (whole news story), so it returned an "shell page uri too long" error.
Right now, this sends simply the index int to the NewsPage page, which tries to capture the values, but fails since the newsContentGetSet doesn't actually set anything (doesn't debug into it when I try). Aaany ideas, really?
Instead of passing the data on parameter. You should save the data to variable into App class and then retrieve them from there when you have navigated to next page.
App.xaml.cs
public static fetchNewsContent newsContentGetSet;
Accessing it
var fetchedNewsContent = App.fetchNewsContent;
You can store/retrieve the data from any page. Note that if the application is closed the data is gone.

Silverlight 4 with RIA + EntityFramework + MVVM: Childwindow DomainContext Load does not refresh

I have a silverlight 4 application which uses RIA with EF to query multiple tables in a single DomainContext. BUGroup, BUGroupBuilding and vwBusinessUnit.
The UI basically loads the BUGroup entity set and I can select different BUGroups and it would load child tables like this:
I have a DomainContext that I'm passing to a childwindow in the Manage Buildings button like this:
ManageBuildingsChildWindow ManageBuildingscw = new ManageBuildingsChildWindow();
ManageBuildingscw.Closed += new EventHandler(ManageBuildingscw_Closed);
ManageBuildingscw.DataContext = null;
ManageBuildingsViewModel ManageBuildingsViewModel = new ManageBuildingsViewModel();
ManageBuildingscw.DataContext = ManageBuildingsViewModel;
and then I'm loading the childwindow context in the childwindow view model like this:
GetBUGroupResult = SecurityDomainContext.Current.Load(SecurityDomainContext.Current.GetBUGroupsCustomQuery(), LoadBehavior.RefreshCurrent, false);
GetBUGroupResult.Completed += new EventHandler(GetBUGroupResult_Completed);
here's the event handler for GetBUGroupResult
void GetBUGroupResult_Completed(object sender, EventArgs e)
{
GetBUGroupBuildings = SecurityDomainContext.Current.BUGroupBuildings.Where(w => w.BUGroupID == BUGroupID).ToList();
GetBUGroupResult.Completed -= new EventHandler(GetBUGroupResult_Completed);
}
I bind each BUGroupBuilding to a delete link in a datagrid and it deletes from database fine. when I click on the manage building button to invoke the child window and it loads fine for the first time. if i have 5 buildings, it loads 5 buildings. the problem is when i loads it 2nd or other times after deleting a few buildings. it retains the old DomainContext even after the load.
I even try setting the LoadBehavior to RefreshCurrent on the Load for the GetBUGroupsCustomQuery()
say I have 5 buildings in a group and i deleted 2 on parent window using the delete link so now i have 3. invokes the childwindow. it still shows 5.
Now I put a break on the DomainServices for GetBUGroupsCustomQuery() and i get the correct 3 value coming back
But during the GetBUGroupResult_Completed event handler, I'm seeing 5 buildings still. It looks like my DomainContext is not refreshing even when I specified the loadbehavior to refresh current.
any input?
I had a similar problem to this and it was solved with a workaround that loads data into the context and then detaches any objects in the entity collection that is not in the collection of the newly returned objects. Try something like this with your load operation:
SecurityDomainContext.Current.Load<YourObjectType>(
SecurityDomainContext.Current.GetBUGroupsCustomQuery(),
LoadBehavior.MergeIntoCurrent,
loadOperation =>
{
var results = context.Comments.Where(
entity => !loadOperation.Entities.Contains(entity)).ToList();
results.ForEach(entity => context.Comments.Detach(entity));
}, null);
I'm not sure if you'll need to replace <YourObjectType> with the entity type that is returned, or if you can just remove that part, but this should at least get you close.
You can also do:
var c = SecurityDomainContext.Current;
var group = c.BUGroups.Single(w => w.BUGroupID == BUGroupID);
c.Refresh(RefreshMode.StoreWins, group.BUGroupBuildings);
GetBUGroupBuildings = group.BUGroupBuildings.ToList();
By RefreshMode.StoreWins it is guaranteed that the current state of the database is retrieved.

C# - Entity Framework add new object to ObjectContext

im working with Entity Framework, SQL and C#.
i have a Table called Client and other called clients_phone.
I have a form with a Xtragrid and using BindingSource I bind the IQueryable to the grid.
myBindingSource = new BindingSource();
myBindingSource.DataSource = clients; //Clients it is the IQueryable<Client>
myBindingSource.DataMember = "clients_phone";
myBindingSource.AllowNew = true;
Then, i wan to add a new clients_phone to my client. To do this, i make a New Client() and then add the Phone.
clients newclient = objContext.CreateObject<clients>();
newclient.clients_phone = newClients_Phone;
objContext.AddObject("Clients", newclient);
Finally i add the new clients_phone in the ObjectContext, but when i see the Xtrag clients_phone don't show.
Any idea of what happens??.
Thanks
Lucas B is right. Whenever you've gotten round to adding all the new Clients and Clients_phone's you need to call the SaveChanges() method in order to persist the data into the database.
Whether you need to create the client first and then do an update to add further client_phone entries or whatever. If you never call SaveChanges() method nothing you do will be saved back to the database.
Have you tried saving and commiting the object?
objContext.SaveChanges(true);
objContext.AcceptAllChanges();
I have done the SaveChanges() but I see it as a workaround.
Drawback of this: When the user cancels the action the new object will be in the DB.
Use case: "Create person"
User select a menu item (or button or whatever) named "Create person" (and the new user should appear in a GridView control for example - SaveChanges() is called)
The the user fills in First Name, Last name etc.
But then the users discovers that he does not need to create that person (e.g. the user remembers that he has created that person already yesterday)
The user does not press the Save button (menu item or whatever ;-)) he uses the "Cancel" menu item (or button or whatever) - and so there will be an orphan person in the DB
Other approach: In order to add the new person (not committed yet) to a GridView control you can set the DataSource to "current persons + new person"
private object GetBindingList(ObjectSet<Person> contextObjects, Person newObject)
{
List<Person> list = new List<Person>();
list.AddRange(contextObjects);
list.Add(newObject);
return list;
}
Usage:
PersonsBindingSource.DataSource = GetBindingList(Context.PersonSet, newPerson);
But this has a disadvantage:
It works only the first time ... So you need to to something like:
PersonsBindingSource.DataSource = GetBindingList(Context.PersonSet, newPerson);
Context.PersonSet = Populate with persons from PersonsBindingSource.DataSource // ;-)
But why is contextObjects.AddObject(newObject); not working (the new item will not be displayed in the GridView - the problem only occurs for objects without foreign keys to other objects)
Also works only when calling SaveChanges():
PersonsBindingSource.DataSource = Context.PersonSet.Execute(MergeOption.AppendOnly);

Categories