|
I updated the previous post. Please read it again.
|
|
|
|
|
Take a look here: ListView.BeginUpdate Method (System.Windows.Forms)[^]
You could call that before you start the background worker and call EndUpdate when the background worker is done (another event which you haven't utilized yet I assume).
If you want to see the items being listed while the background worker is still working you would have to "batch" the Bitmaps (in a List<bitmap> or an array for example) before calling ReportProgress and then pass that List/array/batch for UserState. Then use BeginUpdate at the start of BackgroundWorker1ProgressChanged and EndUpdate at the end. And then play around with the batch size to find a value you're comfortable with.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
I declared a global const int batchSize = 10 and a global variable counter .
BackgroundWorker1DoWork sends a new batch of thumbnails every batchSize times or if the i counter already reached the limit (fileList.Count - 1 ):
void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
List<Bitmap> thumbnailList = new List<Bitmap>();
for (var i = 0; i < fileList.Count; i++)
{
Bitmap thumbnail = MakeThumbnail(fileList[i], 200, 200);
thumbnailList.Add(thumbnail);
if (((thumbnailList.Count == batchSize) && (batchSize < fileList.Count)) ||
(i == (fileList.Count - 1)))
{
backgroundWorker1.ReportProgress(i, thumbnailList);
thumbnailList.Clear();
}
}
}
And the second function:
void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
List<Bitmap> list = (List<Bitmap>)e.UserState;
listView1.BeginUpdate();
if (list.Count > 0)
{
foreach (Bitmap tn in list)
{
imageList1.Images.Add(tn);
ListViewItem caption = new ListViewItem(Path.GetFileName(fileList[counter]));
caption.ImageIndex = counter;
listView1.Items.Add(caption);
counter++;
}
}
listView1.EndUpdate();
}
Unfortunatelly it doesn't work. thumbnailList.Count from the second function reports 0, so apparently thumbnailList.AddRange((List<Bitmap>)e.UserState); is one of the problems. Any ideas?
PS: I uploaded the test project here: TinyUpload.com[^] If you want to test it, drag and drop pictures over the form.
modified 4-Nov-17 16:37pm.
|
|
|
|
|
List<Bitmap> thumbnailList = new List<Bitmap>();
backgroundWorker1.ReportProgress(i, thumbnailList);
Bitmap thumbnail = (Bitmap)e.UserState;
..... = (notbitmapbutsomethingelse)e.UserState;
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
I updated the previous post. The app still doesn't work.
|
|
|
|
|
When you pass the list via ProgressChangedEventArgs you pass a reference to the (currently) one and only existing instance of it which you immediately Clear() afterwards (I missed that previously). Instead of clearing it, create a new List<Bitmap> for the next batch.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Thanks. Unfortunately sometimes I get this error after I drag and drop some files:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at test1.MainForm.BackgroundWorker1ProgressChanged(Object sender, ProgressChangedEventArgs e)
at System.ComponentModel.BackgroundWorker.OnProgressChanged(ProgressChangedEventArgs e)
at System.ComponentModel.BackgroundWorker.ProgressReporter(Object arg)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.UnsafeInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at System.Delegate.DynamicInvoke(Object[] args)
at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at test1.Program.Main(String[] args)
Any idea how to fix this bug? I think it's related to those Bitmap lists.
By the way, this is the current code:
void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
List<Bitmap> thumbnailList = new List<Bitmap>();
for (var i = 0; i < fileList.Count; i++)
{
Bitmap thumbnail = MakeThumbnail(fileList[i], thumbnailSize, thumbnailSize);
thumbnailList.Add(thumbnail);
if (((thumbnailList.Count == batchSize) && (batchSize < fileList.Count)) ||
(i == (fileList.Count - 1)))
{
backgroundWorker1.ReportProgress(i, thumbnailList);
thumbnailList = new List<Bitmap>();
}
}
}
void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
List<Bitmap> thumbnailList = (List<Bitmap>)e.UserState;
listView1.BeginUpdate();
if (thumbnailList.Count > 0)
{
foreach (Bitmap thumbnail in thumbnailList)
{
imageList1.Images.Add(thumbnail);
ListViewItem caption = new ListViewItem(Path.GetFileName(fileList[counter]));
caption.ImageIndex = counter;
listView1.Items.Add(caption);
counter++;
}
}
listView1.EndUpdate();
}
|
|
|
|
|
Two minor things first:
This:
&& (batchSize < fileList.Count) ..isn't neccessary because it's covered already by this:
|| (i == (fileList.Count - 1)
And this:
if (thumbnailList.Count > 0) ..isn't neccessary because if the list is empty then the foreach-loop will just do nothing.
Now, to the problem at hand - these lines of the exception stack trace:
at System.Collections.Generic.List`1.get_Item(Int32 index)
at test1.MainForm.BackgroundWorker1ProgressChanged(Object sender, ProgressChangedEventArgs e) ..tell you that the problem occurs when trying to access a List<> with its indexer in BackgroundWorker1ProgressChanged . The only candidate for this is:
fileList[counter] So it seems somehow your counter gets out of sync with the "actual progress". No idea why; maybe it's in the code you haven't shown here.
But that's a point I planned to suggest to you to improve anyway: Change it so that BackgroundWorker1ProgressChanged doesn't need to assume the index of the "delivered" bitmap in fileList by delivering not only the bitmaps but the bitmaps with their index. Either create a class for that (with Bitmap and Index as properties) and store instances of that class in the list (instead of just the Bitmap) or use a Tuple<Bitmap, int> instead of the custom class. Or, instead of using the index, use the filename and ListViewItem.ImageKey[^] instead of ImageIndex . That way you wouldn't need fileList in BackgroundWorker1ProgressChanged at all.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Thanks for help. I already fixed the minor issues, now I'm trying to improve that index thing.
|
|
|
|
|
Again, thanks a lot for your help.
I created a class Thumbnail :
public class Thumbnail
{
public Bitmap thumbnail;
public string filename;
public int index;
}
I added also a new feature: progress update. The last version of those functions:
void LoadThumbnails()
{
backgroundWorker1.RunWorkerAsync();
}
void BackgroundWorker1DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
List<Thumbnail> thumbnailList = new List<Thumbnail>();
for (var i = 0; i < fileList.Count; i++)
{
Thumbnail item = new Thumbnail();
item.thumbnail = MakeThumbnail(fileList[i], thumbnailSize, thumbnailSize);
item.filename = Path.GetFileName(fileList[i]);
item.index = i;
thumbnailList.Add(item);
if ((thumbnailList.Count == batchSize) || (i == (fileList.Count - 1)))
{
backgroundWorker1.ReportProgress(i, thumbnailList);
thumbnailList = new List<Thumbnail>();
}
}
}
void BackgroundWorker1ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
List<Thumbnail> thumbnailList = (List<Thumbnail>)e.UserState;
listView1.BeginUpdate();
for (var i = 0; i < thumbnailList.Count; i++)
{
imageList1.Images.Add(thumbnailList[i].thumbnail);
ListViewItem caption = new ListViewItem(thumbnailList[i].filename);
caption.ImageIndex = thumbnailList[i].index;
listView1.Items.Add(caption);
}
listView1.EndUpdate();
if (thumbnailList.Count > 0)
{
Text = "Loading " + thumbnailList[thumbnailList.Count - 1].index + " of " + fileList.Count + " pictures - Thumbnails";
}
}
void BackgroundWorker1RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (fileList.Count == 1) Text = "1 picture - Thumbnails";
else if (fileList.Count > 1) Text = fileList.Count + " pictures - Thumbnails";
}
modified 5-Nov-17 19:39pm.
|
|
|
|
|
Looks good to me. Is it now working like you want it to?
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Yes.
|
|
|
|
|
Cheers
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
The "progress" handler has the same scope as the "worker" method.
"State" is one way to pass a "result" (object, string, whatever; % being used almost never since it implies determinism) to the "progress" handler.
The progress handler (as well as "completed") run on the UI thread.
"Worker" can actually put say 10 images on a cuncurrent queue and then invoke "progress" every 10 to post the queue to the UI; so "state" is only one way to report "progress".
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
I'm unsure of the syntax for this..
Assume I have 3 bool methods.. I want to run them in order MethodA(), MethodB(), then MethodC().
As each completes I want to check the return value. If it's true, run the next task. If it's false, stop right there.
Can someone show me how this is done?
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
A real simple way is like this:
if (MethodA()){
if (MethodB(){
if (MethodC(){
}
}
}
There are two kinds of people in the world: those who can extrapolate from incomplete data.
There are only 10 types of people in the world, those who understand binary and those who don't.
|
|
|
|
|
If you don't need the information which method returned false first then this would be the shortest way (while still executing them sequentially A > B > C as long as they return true):
if (!MethodA() || !MethodB() || !MethodC())
{
}
else
{
}
This would be an alternative to the above and to nested if's - as long as you don't need the nested if's then to examine the results, anyway:
bool methodAsuccess = MethodA();
bool methodBsuccess = methodAsuccess && MethodB();
bool methodCsuccess = methodBsuccess && MethodC();
And then there's the scalable method, provided the methods all have the same signature:
List<Func<bool>> methods = new List<Func<bool>>() { MethodA, MethodB, MethodC };
int step = 0;
for (; step < methods.Count && methods[step](); step++);
if (step == methods.Count)
else
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
I think if you use this forum as a code-writing service, not taking the time to give minimal information about your intent, and the context your code is used in, you will not grow, intellectually, technically.
«While I complain of being able to see only a shadow of the past, I may be insensitive to reality as it is now, since I'm not at a stage of development where I'm capable of seeing it. A few hundred years later another traveler despairing as myself, may mourn the disappearance of what I may have seen, but failed to see.» Claude Levi-Strauss (Tristes Tropiques, 1955)
|
|
|
|
|
You will see that there have been a few different responses to your question. They could be correct or they could not; know way for any of us to know what is the right way because your question does not say what needs to be done after any of the methods; with the exception of go onto B if A is true, and then again onto C if B was true.
What I would recommend is to document out the functions and methods in an old school outline or flowchart. Once that is done you can start filling in the blocks with code.
Director of Transmogrification Services
Shinobi of Query Language
Master of Yoda Conditional
|
|
|
|
|
Good time of day!:).Net 4.0, console. I need to write a parser page in console mode to get the code page in the form in which it is displayed to the user after download, without clicking the buttons, scrolling, and other events. I use this code, but it returns absolutely not what you need. In what ways can I get my desired result? I use other methods or components?
Доброе время суток!:).Net 4.0, консоль. Мне необходимо для написания парсера страницы сайта в консольном режиме получить код страницы в том виде, в каком ее видит пользователь после загрузки - без нажимания на кнопки, прокрутки и других событий. Я использую такой код, однако он возвращает совершенно не то, что нужно. Какими способами я могу получить нужный мне результат? Мне использовать другие методы или компоненты?
try
{
wb = new WebBrowser();
wb.Navigate(linkNorm);
wb.ScriptErrorsSuppressed = true;
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(w_DocumentCompleted);
while (wb.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
originalText = wb.DocumentText;
wb.Dispose();
}
catch (Exception ex1)
{
}
void w_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
Trace.WriteLine(wb.DocumentText);
}
Change method to
wb.Document.Body.OuterHtml - not help me. Result is so bad.
I think this is a pretty simple task, probably someone already solved
|
|
|
|
|
you want to download the javascript ?
|
|
|
|
|
No, i want see full HTML after work all script. When user see on screen after load. In my example it`s online-shop and price maked JS. I see true price on screen, but other price in wb.Document.Body.OuterHtml or other method. In developer tools Chrome is all OK
|
|
|
|
|
We have 2 files with settings in them.
The first is a constants file that has all kinds of data in it:
public struct General
{
public static float FAIL_CODE = -999999;
public static int BayPort = 0xc000;
}
public struct Thermal
{
public static float Gi = 1;
public static float Gv = 4.0875f;
public static int Resistance = 1;
public static int Temp = 0;
}
public struct BlisterMotor
{
public static uint MIN_BLISTER_POSITION = 0;
public static uint MAX_BLISTER_POSITION = 56250;
}
The other is an embedded xml file resource:
<Parameter>
<Name>Effector</Name>
<Value>150</Value>
</Parameter>
<Parameter>
<Name>SampleHeaterSetPoint</Name>
<Value>66</Value>
</Parameter>
<Parameter>
<Name>SampleHeaterSamples</Name>
<Value>18</Value>
</Parameter>
We want to make all of this user editable with a UI, so I want to serialize all of them to XML.
I'm trying to find a way to do this with generics, so...
public class Setting<T>
{
public T SettingValue { get; set; }
public T MinValue { get; set; }
public T MaxValue { get; set; }
public string Key { get; set; }
public string Description { get; set; }
}
Then a class to hold all of them:
public List<Setting> MySettings { get; set; }
But this won't compile because the Setting class in the List<> requires a type argument.
But I don't see how this would work with generics. That really only leave overriding the base class with a different type for each:
public List<SettingBase> MySettings { get; set; }
public class SettingBase
{
public string Key { get; set; }
public string Description { get; set; }
}
public class SettingInt : SettingBase
{
public int SettingValue { get; set; }
public int MinValue { get; set; }
public int MaxValue { get; set; }
}
public class SettingDouble : SettingBase
{
public double SettingValue { get; set; }
public double MinValue { get; set; }
public double MaxValue { get; set; }
}
Anyone have a better idea?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Too fine-grained / over-engineered. When you start "coding against it", you will know what I mean (and as you are already experiencing).
Just use a single class with all your "parm properties"; serialize / deserialize that; and bind selected parts to one or more "views" based on context.
You can even have different "instances" of your "parm class" for test vs production; etc.
"(I) am amazed to see myself here rather than there ... now rather than then".
― Blaise Pascal
|
|
|
|
|
One of the best answers I've read!
Regards,
Rob Philpott.
|
|
|
|
|