|
We have some code which receives images of a document from a C++ DLL, and displays them in a WPF application. The C# code stores the images in an array, which it flushes each time a new document is placed on the scanner. The code converts the image from a Bitmap to a BitmapImage, which is the image type for display in WPF:
private BitmapImage CreateBitmapImage(Bitmap bitmap)
{
using (MemoryStream memory = new MemoryStream())
{
bitmap.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
BitmapImage bitmapimage = new BitmapImage();
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
bitmapimage.Freeze();
return bitmapimage;
}
}
The above code leaks, but only on some PCs. On most it is okay. It can be fine on one Windows 10 PC, and leak on another that has Windows 10 on the same hardware.
A key point to note is that the DLL module is also passing the bitmap handle to a third party validation DLL, and if we remove that DLL, the memory leak disappears.
If I remove the Freeze() call, the code does not leak, but the images are not displayed.
If I comment out the return call, and return null instead, the code still leaks. Therefore the issue is not that we do not clear the stored images.
That this only occurs on some PCs, might suggest a timing issue associated with the validation DLL.
Thoughts?
Note: Edited to correct the code. For some reason I'd copied it with a key line missing!
modified 22-Feb-18 11:29am.
|
|
|
|
|
Are all machines running exactly the same version of .Net?
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
|
As previously suggested, check the .NET versions on the machines; there have been a few issues that vary by version.
I would probably try moving the creation of the BitmapImage outside of the using block, or try some garbage collection routines, or object disposal to see what kind of response you get from what methods
Director of Transmogrification Services
Shinobi of Query Language
Master of Yoda Conditional
|
|
|
|
|
Oh, I was hoping .Net would be solid. How on earth do we ensure that customers have a bug free version, if that is the cause?
|
|
|
|
|
First you must ensure that your code in itself is bug free.
Director of Transmogrification Services
Shinobi of Query Language
Master of Yoda Conditional
|
|
|
|
|
MadMyche wrote: First you must ensure that your code in itself is bug free.
If I simply discard the BitmapImage created by the quoted code, rather than saving it, the memory leak is present.
|
|
|
|
|
You're trying to create an image from an "empty" memory stream; key statement missing:
bitmap.Save( memory, System.Drawing.Imaging.ImageFormat.Bmp );
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
Thanks for spotting that, it actually isn't missing in our code, but it is missing from the sample I pasted here. Ooops. Sorry about that.
|
|
|
|
|
Then maybe you're also running "different" versions of the app ...
(I like to put the version # in the title bar).
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
No, just stupidity on my part when copying code to this forum.
|
|
|
|
|
Thank you to everyone for your thoughts. It appears to be unrelated to the version of .Net.
I found the source for MemoryStream and the Dispose method does NOT set the buffer reference to null. I tried assigning a static buffer to the MemoryStream instance instead of allowing it to allocate its own buffer but that caused a crash.
I created test WPF and WinForms apps and the results are bizarre.
We have a small C# class - VideoOCRWrapper - which drives an attached OCR document scanner. It essentially makes calls to a C++ DLL, and has a callback which receives a IntPtr containing a HWND. On receipt of a bitmap, it converts it to a BitmapImage and fires an event to provide a client with the BitmapImage isntance.
I created a WinForms app, which initialises VideoOCRWrapper and displays the received bitmap. It has converts the BitmapImage to a Bitmap for display.It shows no memory leaks.
I created a WPF app, which initialises VideoOCRWrapper and displays the received bitmap. It shows a huge memory leak consistent with the bitmap buffer leaking.
The two apps use almost the same code, except that the WinForms overrides the form's WndProc, whereas the WPF app hooks its own WndProc onto the main window.
I memory profiled the WPF test app, and it said that "22 types have instances that are queued for finalization. This can indicate that a Finalizer method is stuck, which will prevent instances from being finalized and cause memory leaks.".
There is an extra factor. We use a third party DLL for document verification, which receives bitmaps from us. If I remove that DLL, our code shows no leaks. If I add that DLL, we have leaks but only when running our WPF test app, or our WPF application. When running the WinForms test app, we have no leaks.
|
|
|
|
|
I am working on a WPF application handling lists too long to fit in the window, so it needs a scroll bar. But elements of the list (a vertical stack panel) may flash up indicators that preferably should be acted on without too much delay; they should not be outside the window.
So I imagine a modified scrollbar mechanisms: A certain fraction of the contents is displayed in normal size (or even normal++, for those of us who are not as young as we used to be). Lines above or below this area is gradually reduced in size, so that more of them would fit above/below the "reading zone" of the window (with the attention indicators visible), without scrolling out. The reading zone would be somewhat like a cylinder lens, except with a central flat area of constant magnification.
Preferably, the size falloff outside the reading zone should be configurable, as well as the fraction of the window making up the reading zone. It would also be nice if it could be applied to columns of a table one-by-one, so that the columns remain straight from top to bottom, even though the cell contents is reduced in size.
I tried to google for 'cylinder lens scrollbar', without much success. Has anyone around here seen such a scrolling mechanism? Do you have hits for other google terms? Or should I just sit down and start implementing it myself?
(I suspect that my implmentation would be too much tailored to my specific needs at the moment; if there is anything like this out in the wild, it is probably of far more general use!)
|
|
|
|
|
You want "dynamic" font sizes relatived to the position of an item in the "view port".
Nothing really to do with "scroll bars" per se.
You need "code behind" to assign "font sizes" to each item (e.g. user control) in your observable collection based on your view port and item position.
Or, create a fixed set of "panes", of different font size; and "pass" items through them. Simulates a list and probably easier to grok.
(Or use a vertical "carousel" control).
WPF: Carousel Control
CodePlex Archive
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
modified 19-Feb-18 13:03pm.
|
|
|
|
|
Gerry Schmitz wrote: You want "dynamic" font sizes relatived to the position of an item in the "view port". That is one way to describe it. But also non-text, like check boxes etc. should be scaled down.
Gerry Schmitz wrote: Nothing really to do with "scroll bars" per se. Except the way you use it, and handle it. By moving the slider at the right side of the window, you pull up and down not the text within the entire window, but the text within the reading area. The implementation will not have much in common with the standard scrollbar, but the use will.
Yes, for my specific application, I could write class specific code behind that will probably not be useful to any other application. My hope was that someone had created a more general solution. (If you are lucky, that "someone" may be myself during the next couple weeks )
|
|
|
|
|
I have been up almost all night reading on this subject. I have my main ViewModel (ShellViewModel), when the user selects a button a new window opens for the user to type something and a file chooser to select the file to read.
All I want to do is pass the Text typed in and the file path (as a string) back to the main view model for processing.
I believe I understand the concept of using EventAggregator to pass an event containing the data I want from the second window to the first. My problem is all the examples are showing the main VM creating two separate VM and the data is passed between the two individual VM's.
My ShellViewModel has the following method when the button is selected (I know using WindowManager in this fashion is not "best practice", but works for now:
public void LoadSchedule()
{
WindowManager windowManager = new WindowManager();
SelSchedViewModel vm = new SelSchedViewModel();
windowManager.ShowDialog(vm);
}
I have added a Handle to the ShellViewModel as well as Implimented "IHandle<scheduleinfo>"
Handle Code in ShellViewModel:
public void Handle(ScheduleInfo message)
{
ScheduleName = message.ScheduleName;
FileInfo = message.FileLocation;
}
I have created the class "SheduleInfo" to hold the data for the event
public class ScheduleInfo
{
public string ScheduleName
{
get;
private set;
}
public string FileLocation
{
get;
private set;
}
public ScheduleInfo(string SN, string FL)
{
ScheduleName = SN;
FileLocation = FL;
}
}
SheduleName and FileLocation have been added to ShellViewModel:
public string ScheduleName
{
get { return _scheduleName; }
set {
_scheduleName = value;
NotifyOfPropertyChange(() => ScheduleName);
}
}
public string FileInfo
{
get { return _fileInfo; }
set {
_fileInfo = value;
NotifyOfPropertyChange(() => FileInfo);
}
}
The second window "SelSchedViewModel" has a load button that when text is written in the text box and a file has been selected, is supposed to pass that data back and close this windows.
I am stuck on how to set up the SelShedViewModel to send the data back and how to properly initialize EventAggregator in the ShellViewModel and in the second view model. All the tutorials I found use the constructor of the receiving View Model (I tried) adding below to my ShellViewModel but I cant access "events"
public ShellViewModel()
{
IEventAggregator events = new EventAggregator();
}
I was thinking I need to move below to the ShellViewModel constructor and just use Windows Manager to call it, adding the "events" (will try this in a bit):
SelSchedViewModel vm = new SelSchedViewModel(events);
I don't know why this concept is confusing me so much. I have made the entire project public on gitHub for now. Any help would be appreciated.
And if y'all (yes I live in Texas) want to supply constructive criticism on my project be my guess. Remember the project was private until no so the commit messages were intended for me and might be a little rough
[Link to my project on GitHub]
BTW, I am self-learning so I am looking for help to get this done not for anyone to do it for me. This project is a tool I want to use to make one of my normal day to day operations quicker at work, this is not a "for sale" project.
Thank You all for the help! Sorry for the length (here's a potatoe[some might get this old comment] - stress enduced humor)
|
|
|
|
|
I do MVVM if I had no choice.
My "personal" projects are allowed to "fly" and change is part of the process.
What you're describing is pain for a "possible" future (employment) gain ... the 2 never coincide.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
What I am describing is using work situations to learn. There is a chance I will be asked to work with our development/IT department on our in house application because I have been a hobby programmer and have more than 20 years experience in the companies primary focus industry.
If I get offered a position in the development team, I'll jump all over it.
Other than that, not sure what your post is getting at.
|
|
|
|
|
That's good ... learning MVVM in this case has a specific goal.
I often see people struggling over some aspect literally "for days" because of the "rules".
Most apps will live and die never needing to "switch out the UI".
Spending half your time "engineering" instead of "shipping" serves no one.
And you will never convince me that MVVM is a "productivity booster" for the majority.
In MVVM, you're always struggling with the "plumbing", rarely the "business rules" (which is the point of IT; not "patterns").
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
In a way I do agree with you, however, unless you are the top dog in a situation, you must follow others concepts.
Here I have 2 issues, one I am trying to learn this concept because my company does use an MVVM framework, albeit custom fabbed.
I have also learned a long time ago to learn more than one way to accomplish your goals, this provides you the ability to adapt and overcome when required.
The second issue is more a personal one. I hate it when I have trouble solving something!!
You Gerry, In ways I agree but I (being still an amateurs amateur, there is little I can do with changing the mind of the person who has spent the past 4 years developing, maintaining and upgrading the companies SW.
|
|
|
|
|
Ask them "why" they are using MVVM. (Most people can't).
The answer (or lack of one) will tell you volumes about what drives the "standards" people in your organization.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
I have implemented custom sort for a ListCollection view. The data is displayed in a DataGrid. The actual sorting is functioning. I have this code:
ObservableCollection<ConnectionViewModel> _connections;
private ICollectionView CV { get; set; }
public ConnectionsTabViewModel()
{
_connections = new ObservableCollection<ConnectionViewModel>();
CV = CollectionViewSource.GetDefaultView(_connections);
}
public void Sort()
{
if (CV is ListCollectionView view)
{
view.CustomSort = new ConnectionViewModelComparer();
}
}
public void StopSorting()
{
if (CV is ListCollectionView view)
{
view.IsLiveSorting = false;
}
}
I want to be able to turn on/off real time sorting when data is edited or added. I thought that setting the ListCollectionView property IsLiveSorting to false would achieve this but if I edit data in the DataGrid the rows are still sorted in real time. Have I misunderstood something?
I tried to solve this issue by setting view.CustomSort to null but by doing so the data is returned to the original state/order before sorting. Is there a simple way to turn off sorting and keeping the data in the same order as it was before sorting is turned off?
|
|
|
|
|
Can't you just use a different "view" to get "not-sorting"; realizing you would need to "pre-sort" to have it sorted when not sorting.
Or, why not just let the user sort (by clicking the "sortable" column header).
You "implemented" the custom sort; meaning, you should be able to "turn it off" / un-implement it for a given instance.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
I decided that I will not use live sorting in the application. Still I couldn't turn it off. Instead of using an ICollectionView for sorting I transfererd the ObservableCollection data using ObservableCollection.ToList() to a List and sorted the list data. I then used the list as a constructor argument to create a new ObservableCollection. Not a very efficient solution but it is good enough for now.
|
|
|
|
|
In the end, "results" is what really matters.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|