Re-rendering a view in backbone Marionette: best practice - backbone.js

This is a very simple question.
Basically this is my case:
var newViewInstance1 = new MyView();
myLayout.myRegion.show(newViewInstance1)
Now, later, I want to show the View (which is a static one) again in the same layout region . There may or may not have been a different view in that region in the meantime.
Is there any difference between these two:
myLayout.myRegion.show(newViewInstance1) //again
//or
var newViewInstance2 = new MyView();
myLayout.myRegion.show(newViewInstance2)
If I do the latter, for example, will newViewInstance1 be left hanging around?
Thanks
--Justin Wyllie

There's no real difference beyond the view initalization (e.g. if you're fetching or computing information in the view's initialize function).
In any case, when a region shows a view, it closes any open views in that region. So, no: newViewInstance1 won't be left hanging around in the second case.

Related

OxyPlot performance issue on larg data in WPF on InvalidatePlot

I'm using OxyPlot in my wpf application as line recorder. It's like the LiveDemo example.
On a larg visible data set, I get some UI performance issues and may the whole application could freez. It seems to be PlotModel.InvalidatePlot which is called with to many points to often, but I didn't found a better way.
In deep:
Using OxyPlot 2.0.0
I code all in the PlotModel. The Xaml PlotView is only binding to the PlotModel.
I cyclical collect data in a thread an put them in a DataSource (List of List which are ItemSoure for the LineSeries)
I have a class which calculates cyclical in a thread the presentation for x and y axis and a bit more. After all this stuff, it calls PlotModel.InvalidatePlot.
If I
have more than 100 k points on the display (no matter if in multiple LineSeries or not)
and add 1 DataPoint per LineSeries every 500 ms
and call PlotModel.InvalidatePlot every 200 ms
not only the PlotView has performance issues, also the window is very slow in reaction, even if I call PlotModel.InvalidatePlot (false).
My goal
My goal would be that the Windo / Application is working normally. It should not hang up because of a line recorder. The best would be if it has no performance issues, but I'm skeptical.
What I have found or tested
OxyPlot has Performance guidelines. I'm using ItemsSource with DataPoints. I have also tried adding them directly to the LineSeris.Points, but then the Plot doesn’t refresh anyway (even with an ObservableCollection), so I have to call PlotModel.InvalidatePlot, what results in the same effect. I cannot bind to a defined LineSeries in Xaml because I don’t know how much Lines will be there. Maybe I missed something on adding the points directly?
I have also found a Github issue 1286 which is describing a related problem, but this workaround is slower in my tests.
I have also checked the time which is elapsed on the call of PlotModel.InvalidatePlot, but the count of points does not affect it.
I have checked the UI thread and it seems it have trouble to handle this large set of points
If I zoom in to the plot and display under 20 k Points it looks so
Question:
Is there a way to handle this better, except to call PlotModel.InvalidatePlot much less?
Restrictions:
I also must Update Axis and Annotations. So, I think I will not come around to call PlotModel.InvalidatePlot.
I have found that using the OxyPlot Windows Forms implementation and then displaying it using Windows Form integration in WPF gives much better performance.
e.g.
var plotView = new OxyPlot.WindowsForms.PlotView();
plotView.Model = Plot;
var host = new System.Windows.Forms.Integration.WindowsFormsHost();
host.Child = plotView;
PlotContainer = host;
Where 'Plot' is the PlotModel you call InvalidatePlot() on.
And then in your XAML:
<ContentControl Content="{Binding PlotContainer}"/>
Or however else you want to use your WindowsFormsHost.
I have a similar problem and found that you can use a Decimator in LineSeries. It is documented in the examples: LineSeriesExamples.cs
The usage is like this:
public static PlotModel WithXDecimator()
{
var model = new PlotModel { Title = "LineSeries with X Decimator" };
var s1 = CreateSeriesSuitableForDecimation();
s1.Decimator = Decimator.Decimate;
model.Series.Add(s1);
return model;
}
This may solve the problem on my side, and I hope it helps others too. Unfortunately it is not documented in the documentation
For the moment I ended up with calculating the time for calling InvalidatePlot for the next time. I calculate it with the method given in this answer, wich returns the number of visible points. This rededuce the performance issue, but dosent fix the block on the UI Thread on calling InvalidatePlot.

WPF app with multiple usercontrols

I Am creating simple WPF test project which contains multiple UserControls(Insteda of Pages).I Am using Switcher Class to navigate between different UserControls.When i navigate to different pages,i have observed that memory consuption keep on increasing on each UserControle Navigationand GC is not invoked.
1.So am i doing something wrong in following code?
2.Which part of the code consuming more memory?
3.Do i need to invoke GC for disposing my UserControls on each new UserControle creation?
If need how can i invoke GC?
public void On_Navigate_Click()
{
UserControle newusercontrole=new UserControle();
DataSet ds = new DataSet();
ds=con.getSome_Datafrom_SQL();//Gets data from SQL via connection class
dataGrid_test.ItemsSource = ds.Tables[0].DefaultView;
Grid.SetColumn(newusercontrole, 1);//dataGrid_test is inside newusercontrole and following is the code to add "this" usercontrol to the main window.
Grid.SetRow(newusercontrole, 1);
Grid.SetZIndex(newusercontrole, 10);
Container.Children.Add(newusercontrole);
}
First off, I must point out that if garbage collection really isn't happening (as you said), it's not your fault and it does not mean you're doing something wrong. It only means that the CLR doesn't think that your system is under memory pressure yet.
Now, to manually invoke a garbage collection cycle anyway, you can use the GC.Collect() static method. If a garbage collection actually starts and your memory consumption is still unreasonably high, this means that you're probably doing something wrong: You're keeping an ever increasing number of unnecessary object references and the garbage collector cannot safely collect those objects. This is a kind of a memory leak.
As far as your code goes, I think that the problem is at the end of the method you posted:
Container.Children.Add(newusercontrole);
This seems to add a new object (on every click) to the collection Container.Children. If this is not removed elsewhere, this is probably the cause of your memory leak. I don't know what the suitable solution would be for your use case (since I don't know exactly how your UI should behave), but you'll likely need to find a way to remove the last UserControle added from the Container.Children. If you can use LINQ, then the methods OfType<T>() and Last() could be of use to find it.
In any case, don't leave the GC.Collect() line in production code. Use it only to force a collection cycle for testing purposes, like this one.

UIPageViewController navigates to wrong page with Scroll transition style

My UIPageViewController was working fine in iOS 5. But when iOS 6 came along, I wanted to use the new scroll transition style (UIPageViewControllerTransitionStyleScroll) instead of the page curl style. This caused my UIPageViewController to break.
It works fine except right after I've called setViewControllers:direction:animated:completion:. After that, the next time the user scrolls manually by one page, we get the wrong page. What's wrong here?
My workaround of this bug was to create a block when finished that was setting the same viewcontroller but without animation
__weak YourSelfClass *blocksafeSelf = self;
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished){
if(finished)
{
dispatch_async(dispatch_get_main_queue(), ^{
[blocksafeSelf.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];// bug fix for uipageview controller
});
}
}];
This is actually a bug in UIPageViewController. It occurs only with the scroll style (UIPageViewControllerTransitionStyleScroll) and only after calling setViewControllers:direction:animated:completion: with animated:YES. Thus there are two workarounds:
Don't use UIPageViewControllerTransitionStyleScroll.
Or, if you call setViewControllers:direction:animated:completion:, use only animated:NO.
To see the bug clearly, call setViewControllers:direction:animated:completion: and then, in the interface (as user), navigate left (back) to the preceding page manually. You will navigate back to the wrong page: not the preceding page at all, but the page you were on when setViewControllers:direction:animated:completion: was called.
The reason for the bug appears to be that, when using the scroll style, UIPageViewController does some sort of internal caching. Thus, after the call to setViewControllers:direction:animated:completion:, it fails to clear its internal cache. It thinks it knows what the preceding page is. Thus, when the user navigates leftward to the preceding page, UIPageViewController fails to call the dataSource method pageViewController:viewControllerBeforeViewController:, or calls it with the wrong current view controller.
I have posted a movie that clearly demonstrates how to see the bug:
http://www.apeth.com/PageViewControllerBug.mov
EDIT This bug will probably be fixed in iOS 8.
EDIT For another interesting workaround for this bug, see this answer: https://stackoverflow.com/a/21624169/341994
Here is a "rough" gist I put together. It contains a UIPageViewController alternative that suffers from Alzheimer (ie: it doesn't have the internal caching of the Apple implementation).
This class isn't complete but it works in my situation (namely: horizontal scroll).
As of iOS 12 the problem described in the original question seems to be almost fixed. I came to this question because I experienced it in my particular setup, in which it does still happen, hence the word "almost" here.
The setup I experienced this issue was:
1) the app was opened via a deep link
2) based on the link the app had to switch to a particular tab and open a given item there via push
3) described issue happened only when the target tab was not previously selected by user (so that UIPageViewController was supposed to animate to that tab) and only when setViewControllers:direction:animated:completion: had animated = true
4) after the push returning back to the view controller containing the UIPageViewController, the latter was found to be a big mess - it was presenting completely wrong view controllers, even though debugging showed everything was fine on the logic level
I supposed that the root of the problem was that I was pushing view controller very quick after setViewControllers:direction:animated:completion: called, so that the UIPageViewController had no chance to finish something (maybe animation, or caching, or something else).
Simply giving UIPageViewController some spare time by delaying my programmatic navigation in UI via
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { ... }
fixed the issue for me. And it also made the programmatic opening of the linked item more user friendly visually.
Hope this helps someone in similar situation.
Because pageviewVC call multi childVC when swipe it. But we just need last page that visible.
In my case, I need to change index for segmented control when change pageView.
Hope this help someone :)
extension ViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
guard let pageView = pageViewController.viewControllers?.first as? ChildViewController else { return }
segmentedControl.set(pageView.index)
}
}
This bug still exists in iOS9. I am using the same workaround that George Tsifrikas posted above, but a Swift version:
pageViewController.setViewControllers([page], direction: direction, animated: true) { done in
if done {
dispatch_async(dispatch_get_main_queue()) {
self.pageViewController.setViewControllers([page], direction: direction, animated: false, completion: {done in })
}
}
}
Another simple workaround in Swift: Just reset the UIPageViewController's datasource. This apparently clears its cache and works around the bug. Here's a method to go directly to a page without breaking subsequent swipes. In the following, m_pages is an array of your view controllers. I show how to find currPage (the index of the current page) below.
func goToPage(_ index: Int, animated: Bool)
{
if m_pages.count > 0 && index >= 0 && index < m_pages.count && index != currPage
{
var dir: UIPageViewController.NavigationDirection
if index < currPage
{
dir = UIPageViewController.NavigationDirection.reverse
}
else
{
dir = UIPageViewController.NavigationDirection.forward
}
m_pageViewController.setViewControllers([m_pages[index]], direction: dir, animated: animated, completion: nil)
delegate?.tabDisplayed(sender: self, index: index)
m_pageViewController.dataSource = self;
}
}
How to find the current page:
var currPage: Int
{
get
{
if let currController = m_pageViewController.viewControllers?[0]
{
return m_pages.index(of: currController as! AtomViewController) ?? 0
}
return 0
}
}
STATEMENT:
It seems that Apple has spotted that developers are using UIPageViewController in very different applications that go way beyond the
originally intended ones Apple based their design-choices on in the first place. Rather than using it in a gesture driven linear fashion
PVC is often used to programmatically jump to random
positions within a structured environment. So they have enhanced their implementation of UIPageViewController and the class is now calling both DataSource
callbacks
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
after setting a new contentViewController on UIPageViewController with
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
even if an animated turn of pages rather suggests a linear progress in an e.g. page hierarchy like a book or PDF with consecutive pages. Although - I doubt that Apple from a HIG standpoint
is very fond of seeing PVC being used this way, but - it doesn't break backwards compatibility, it was an easy fix, so - they eventually did it. Actually it is just one more call of one of the two DataSource methods that is absolutely unnecessary in a linear environment where pages (ViewControllers) have already been cashed for later use.
However, even if this enhancement might come in very handy for certain use-cases the initial behavior of the class is NOT to be considered a bug. The fact that a lot of developers do - also in other
posts on SO that accuse UIPageViewController of misbehavior - rather emphasizes a widely spread misconception of its design, purpose and functionality.
Without trying to offend any of my fellow developers here in this great facility I nonetheless decided not to remove my initial 'disquisition' that clearly explains to the OP the mechanics of PVC and why his assumption is wrong that he has to deal with a bug here.
This might also be of use for any other fellow developer too who struggles with some intricacies in the implementation of UIPageViewController!
ORIGINAL ANSWER:
After having read all the answers over and over again - included the
accepted one - there is just one more thing left to say...
The design of UIPageViewController is absolutely FLAWLESS and all the
hacks you submit in order to circumvent an alleged bug is nothing but
remedies for your own faulty assumptions because you goofed it up in the
first place!!!
THERE IS NO BUG AT ALL! You are just fighting the framework. I'll explain why!
There is so much talk about page numbers and indices! These are concepts the
controller knows NOTHING about! The only thing it knows is - it is showing
some content (btw. provided by you as a dataViewController) and that it can
do something like a right/left animation in order to imitate a page turn.
CURL or SCROLL...!!!
In the pageViewController's world there only exists a current SPACE (let's call
it just this way to avoid confusion with pages and indices).
When you initially set a pageViewController it only minds about this very SPACE.
Only when you start panning its view it starts asking its DataSource what it
eventually should display in case a left/right flip should happen. When you start
panning to the left the PVC asks first for the BEFORE-SPACE and then for the
AFTER-SPACE, in case you start to the right it does it the other way round.
After the completed animation (a new SPACE is displayed by the PVC's view) the
PVC considers this SPACE as its new center of the universe and while it is at it, it
asks the DataSource about the one it still does not know anything about. In case of
a completed turn to the right it wants to know about the new AFTER space and in
case of a completed turn to the left it asks for a new BEFORE space.
The old BEFORE space (from before the animation) is in case of a completed turn to
the right completely obsolete and gets deallocated as soon as possible. The old center
is now the new BEFORE and the former AFTER is the new center. Everything just
shifted one step to the right.
So - no talk of 'which page' or 'whatever index' - just simply - is there a BEFORE or
an AFTER space. If you return NIL to one of the DataSource callbacks the PVC just
assumes it is at one extreme of your range of SPACES. If you return NIL to both
callbacks it assumes it is showing the one and only SPACE there is and will never
ever again call a DataSource callback anymore! The logic is up to you! You define
pages and indices in your code! Not the PVC!!!
For the user of the class there are two means of interacting with the PVC.
A pan-gesture that indicates whether a turn to the BEFORE/AFTER space is desired
A method - namely setViewControllers:direction:animated:completion:
This method does exactly the same than the pan gesture is doing. You are indicating the
direction (e.g. UIPageViewControllerNavigationDirectionBackward/Forward)
for the animation - if there is one intended - which in other words just means -> going to
BEFORE or AFTER...
Again - no mentioning of indices, page-numbers etc....!!!
It is just a programmatically way of achieving the same a gesture would!
And the PVC is doing right by showing the old content again when moving back
to the left after having moved to the right in the first place. Remember
- it is just showing content (that you provide) in a structured way - which is a 'single page turn' by design!!!
That is the concept of a page turn - or BOOK, if you like that term better!
Just because you goof it up by submitting PAGE 8 after PAGE 1 doesn't mean the PVC
cares at all about your twisted opinion of how a book should work. And the user of your
apps neither. Flipping to the right and back to the left should definitely result in reaching
the original page - IF done with an animation. And it is up to YOU to correct the goof by
finding a solution for the disaster. Don't blame it on the UIPageViewController. It is doing
its job perfectly!
Just ask yourself - would you do the same thing with a PAGE-CURL animation? NO ?
Well, neither should you with a SCROLL animation!!! An animated page turn is a page turn and only a page turn!
In either mode!
And if you decide to tear out PAGE 2 to PAGE 7 of your BOOK that's perfectly fine!
But just don't expect UIPageViewController to invent a non-existing PAGE 7 when turning back to the recent page unless YOU tell it that things have changed...
If you really want to achieve an uncoordinated jump to elsewhere, well - do it without an
animation! In most cases this will not be very elegant but - it's possible... -
And the PVC even plays nicely along! When jumping to a new SPACE without animation
it will ask you further down the road for both - the BEFORE and AFTER controller. So your application-logic can keep up with the PVC...
But with an animation you are always conveying - move to the previous/next space (BEFORE -
AFTER). So logically there is no need at all for the PVC to ask again about a space it already
knows about when animating page turns!!!
If you wanna see PAGE 7 when flipping back to the left after having animated from PAGE 1
to the right - well, I would say - that's definitely your very own problem!
And just in case you are looking for a better solution than the 'completion-block' hack from
the accepted answer (because with it you are doing work beforehand for something that might
possibly not even get used further down the road) use the gesture recognizer delegate:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
Set your PVC's DataViewController here (without animation) if you really intend to go back
left to PAGE 7 and the DataSource will be asked for BEFORE and AFTER and you can submit
whatever page you like! With a flag or ivar that you should have stashed away when doing your uncontrolled
jump from PAGE 1 to 8 this should be no problem...
And when people keep on complaining about a bug in the PVC - doing 2 page turns when it is
supposed to do 1 turn only - point them to this article.
Same problem - triggering an un-animated setViewControllers: method within the transition gesture
will cause exactly the same havoc. You think you set the new center - the DataSource is asked
for the new BEFORE - AFTER dataController - you reset your index count... - Well, that seems OK...
But - after all that business the PVC ends its transition/animation and wants to know about the
next (still unknown to it) dataViewController (BEFORE or AFTER) and also triggers the DataSource. That's totally justified ! It needs to know where in its small BEFORE - CENTER - AFTER
world it is and be prepared for the next turn.
But your program-logic adds another index++ count to its logic and suddenly got 2 page turns !!!
And that is one off from where you think you are.
And YOU have to account for that! Not UIPageViewController !!!
That is exactly the point of the DataSourceProtocol only having two methods! It wants to be as generic as possible - leaving you the space and freedom to define your own logic and not being stuck with somebody else's special ideas and use-cases! The logic is completely up to you. And only because you find functions like
- (DataViewController *)viewControllerAtIndex:(NSUInteger)index storyboard:(UIStoryboard *)storyboard position:(GSPositionOfDataViewController)position;
- (NSUInteger)indexOfViewController:(DataViewController *)viewController;
in all the copy/pasted sample applications in the cloud doesn't necessarily mean that you have to eat that pre-cook food! Extend them any way you like! Just look above - in my signature you will find a 'position:' argument! I extended this to know later on if a completed page turn was a right or a left turn. Because the delegate unfortunately just tells you whether your turn completed or not! It doesn't tell you about the direction! But this sometimes matters for index-counting, depending on your application's need...
Go crazy - they are your's...
HAPPY CODING !!!

How do I avoid a memory leak with LINQ-To-SQL?

I have been having some issues with LINQ-To-SQL around memory usage. I'm using it in a Windows Service to do some processing, and I'm looping through a large amount of data that I'm pulling back from the context. Yes - I know I could do this with a stored procedure but there are reasons why that would be a less than ideal solution.
Anyway, what I see basically is memory is not being released even after I call context.SubmitChanges(). So I end up having to do all sorts of weird things like only pull back 100 records at time, or create several contexts and have them all do separate tasks. If I keep the same DataContext and use it later for other calls, it just eats up more and more memory. Even if I call Clear() on the "var tableRows" array that the query returns to me, set it to null, and call SYstem.GC.Collect() - it still doesn't release the memory.
Now I've read some about how you should use DataContexts quickly and dispose of them quickly, but it seems like their ought to be a way to force the context to dump all its data (or all its tracking data for a particular table) at a certain point to guarantee the memory is free.
Anyone know what steps guarantee that the memory is released?
A DataContext tracks all the objects it ever fetched. It won't release this until it is garbage collected. Also, as it implements IDisposable, you must call Dispose or use the using statement.
This is the right way to go:
using(DataContext myDC = new DataContext)
{
// Do stuff
} //DataContext is disposed
If you don't need object tracking set DataContext.ObjectTrackingEnabled to false. If you do need it, you can use reflection to call the internal DataContext.ClearCache(), although you have to be aware that since its internal, it's subject to disappear in a future version of the framework. And as far as I can tell, the framework itself doesn't use it but it does clear the object cache.
As Amy points out, you should dispose of the DataContext using a using block.
It seems that your primary concern is about creating and disposing a bunch of DataContext objects. This is how linq2sql is designed. The DataContext is meant to have short lifetime. Since you are pulling a lot of data from the database, it makes sense that there will be a lot of memory usage. You are on the right track, by processing your data in chunks.
Don't be afraid of creating a ton of DataContexts. They are designed to be used that way.
Thanks guys - I will check out the ClearCache method. Just for clarification (for future readers), the situation in which I was getting the memory usuage was something like this:
using(DataContext context = new DataContext())
{
while(true)
{
int skipAmount = 0;
var rows = context.tables.Select(x => x.Dept == "Dept").Skip(skipAmount).Take(100);
//break out of loop when out of rows
foreach(table t in rows)
{
//make changes to t
}
context.SubmitChanges();
skipAmount += rows.Count();
rows.Clear();
rows = null;
//at this point, even though the rows have been cleared and changes have been
//submitted, the context is still holding onto a reference somewhere to the
//removed rows. So unless you create a new context, memory usuage keeps on growing
}
}
I just ran into a similar problem. In my case, helped establish the properties of DataContext.ObjectTrackingEnabled to false.
But it works only in the case of iterating through the rows as follows:
using (var db = new DataContext())
{
db.ObjectTrackingEnabled = false;
var documents = from d in db.GetTable<T>()
select d;
foreach (var doc in documents)
{
...
}
}
If, for example, in the query to use the methods ToArray() or ToList() - no effect

Why is my WPF Treeview bound to LinqToSql classes being a memory hog?

I have a WPF App which is grinding to a halt after running out of memory...
It is basically a TreeView displaying nodes, which are instances of Linq To Sql OR Generated class ICTemplates.Segment. There around 20 tables indirectly linked via associations to this class in the OR designer.
<TreeView Grid.Column="0" x:Name="tvwSegments"
ItemsSource="{Binding}"
SelectedItemChanged="OnNewSegmentSelected"/>
<HierarchicalDataTemplate DataType="{x:Type local:Segment}" ItemsSource="{Binding Path=Children}">
...
// code behind, set the data context based on user-input (Site, Id)
KeeperOfControls.DataContext = from segment in tblSegments
where segment.site == iTemplateSite && segment.id == iTemplateSid
select segment;
I've added an explicit property called Children to the segment class which looks up another table with parent-child records.
public IEnumerable<Segment> Children
{
get
{
System1ConfigDataContext dc = new System1ConfigDataContext();
return from link in this.ChildLinks
join segment in dc.Segments on new { Site = link.ChildSite, ID = link.ChildSID } equals new { Site = segment.site, ID = segment.id }
select segment;
}
}
The rest of it is data binding coupled with data templates to display each Segment as a set of UI Controls.
I'm pretty certain that the children are being loaded on-demand (when I expand the parent) going by the response time. When I expand a node with around 70 children, it takes a while before the children are loaded (Task manager shows Mem Usage as 1000000K!). If I expand the next node with around 50 children, BOOM! OutOfMemoryException
I ran the VS Profiler to dig deeper and here are the results
Summary Page
Object Lifetimes
Allocation
The top 3 are Action, DeferredSourceFactory.DeferredSource and EntitySet (all .Net/LINQ classes). The only user-classes are Segment[] and Segment come in at #9 an #10.
I can't think of a lead to pursue.. What could be the reason ?
maybe a using surrounding that DataContext ?
using(System1ConfigDataContext dc = new System1ConfigDataContext()){
.... ?
}
also, have you tried using an sql profiler? might shed some light on the matter.
Have you tried using a global DataContext instead of one for each element?
Creating all of the DataContext's each with there own query and results could be the cause of your memory bloat.
I don't know the exact solution but the new statement in join may cause this. Because for each relation a new object could be created(But as I mentioned, I don't know if it is correct).
Could you try this;
public IEnumerable<Segment> Children
{
get
{
System1ConfigDataContext dc = new System1ConfigDataContext();
return from link in this.ChildLinks
join segment in dc.Segments on link.ChildSite == segment.site && link.ChildSID == segment.id
select segment;
}
}
The issue seems to be the creation of multiple S1DataContext objects as Sirocco referred to.
I tried the using statement to force a Dispose and make it eligible for collection. However it resulted in an ObjectDisposedException that I can't make sense of.
The control goes from the line that sets the data context of the DockPanel KeeperOfAllControls.
[External Code] (shown in call stack)
Segment.Children.get (has a using block with dc)
Back at the Line in Step 1... the Linq query uses tblSegments which is retrieved from a local instance of S1DataContext
Anyways so i assume that there is something that prevents multiple DataContexts from being created and disposed. So I tried a Singleton DataContext.
And it works!
the TreeView control is significantly more responsive, every node I tried loads in 3-4 secs max.
I put in a GC.Collect (for verification) before every fetch/search and now the memory usage stays between 200,000-300,000K.
The OR generated System.Data.Linq.DataContext doesn't seem to go away unless it is disposed explicitly (eating memory). Trying to Dispose it in my case, didn't pan out.. even though both functions had their own using blocks (no shared instance of DataContext). Though I dislike Singletons, I'm making a small internal tool for devs and hence don't mind it as of now.. None of the LinqToSql samples I saw online.. had Dispose calls mandated.
So I guess the problem has been fixed. Thanks to all the people that acted as more eyeballs to make this bug shallow.

Resources