I'm having an eventHandler on mouseEnter in which I have simple linear complexity code, where I add and remove some values to and from List. The thing is, that when I tick the event slowly, everything works, but when I tick it at normal speed ( as a user will do ) or fast, the program skips a part of a code(I can see it visualy as its drawing some objects) causing the List being unstable.
I heard that there isn't way to do this via locking, because all UI calls are processed in a single thread.
I need the code to be executed whole and correctly for the price of some events(mouse enter) being unnoticed.
Here's the handler function:
public static void HandleMouseEnter(object sender)
{
for (int i = 0; i < currentlyPrebuilt.Count; i++)
{
currentlyPrebuilt[i].Image = null;
}
currentlyPrebuilt.Clear();
for (int i = 1; i <= sender.x - startingPoint.x; i++)
{
currentlyPrebuilt.Add(pictures[i]);
pictures[i].Image = "sth.jpg";
}
}
}
It just doesn't set null to all Images in the List if moving too fast with mouse
Related
I have an event handler on a button that runs some lines of code. All the code does is run bubble sort on a list but also does some changes to some rectangles on a canvas. My problem is those changes only appear once it has exited the event handler. A similar question has been asked before however that only does one change instead of multiple in concession UI update in WPF elements event handlers.
This is a similar goal to what I'm trying to achieve.
If you're interested in what exactly the code is:
private void Run_btt_Click(object sender, RoutedEventArgs e)
{
Key hold = new Key();
var converter = new System.Windows.Media.BrushConverter();
double hold2, hold3;
//for inside a for loop(bubble sort)
for (int i = 0; i < Sequence.Count; i++)
{
for (int c = 0; c < Sequence.Count-i-1; c++)
{
//changes the colour of the 2 that are being compared
Sequence[c].shape.Fill =(Brush)converter.ConvertFromString("#FFFF00");
Sequence[c+1].shape.Fill = (Brush)converter.ConvertFromString("#FFFF00");
//pause for a bit so that you can see what the algorithm is doing
Thread.Sleep(delay);
if (Sequence[c].Value > Sequence[c + 1].Value)
{
// swap the 2 rectangles
hold2 = Canvas.GetLeft(Sequence[c].shape);
hold3 = Canvas.GetLeft(Sequence[c + 1].shape);
hold = Sequence[c];
Sequence[c] = Sequence[c + 1];
Sequence[c + 1] = hold;
Canvas.SetLeft(Sequence[c].shape, hold2);
Canvas.SetLeft(Sequence[c + 1].shape, hold3);
}
//set colour back to normal
Sequence[c].shape.Fill = (Brush)converter.ConvertFromString(Sequence[c].Colour);
Sequence[c + 1].shape.Fill = (Brush)converter.ConvertFromString(Sequence[c + 1].Colour);
}
}
}
I'm sorry if this question is too vague or not enough detail but I don't know much about this topic and really just starting out.
Just putting #Clemens comment as answer.
If you give the method the async like:
public void async methodname()
and then once you need to update the UI you add:
await Task.Delay(1);
This will act like break point in your code that will update the UI with the changes you made. The 1 represents how long in millisecond the delay will be.
I have a CustomControl called PlaylistView. It displays elements in a playlist with name and thumbnail. The method DisplayPlaylist ensures that a thread is started, in which the individual elements are added one by one and the thumbnails (30th frame) are read out:
public void DisplayPlaylist(Playlist playlist)
{
Thread thread = new Thread(() => DisplayElements(playlist));
thread.Start();
}
private void DisplayElements(Playlist playlist)
{
for (int i = 0; i < playlist.elements.Count; i++)
DisplayElement(playlist.elements[i], i);
}
private void DisplayElement(IPlayable element, int index)
{
VideoSelect videoSelect = null;
if (element is Audio)
//
else if (element is Video)
videoSelect = new VideoSelect(index, element.name, GetThumbnail(element.path, SystemData.thumbnailFrame));
videoSelect.Location = GetElementsPosition(index);
panel_List.BeginInvoke(new Action(() =>
{
panel_List.Controls.Add(videoSelect);
}));
}
private Bitmap GetThumbnail(string path, int frame)
{
VideoFileReader reader = new VideoFileReader();
try
{
reader.Open(path);
for (int i = 1; i < frame; i++)
reader.ReadVideoFrame();
return reader.ReadVideoFrame();
}
catch
{
return null;
}
}
But there is a problem.
It is much too slow (about 10 elements/sec). With a playlist length of 614, you would have to wait more than a minute until all are displayed. Each time you change the playlist, such as adding or deleting an item, the procedure starts with the new item. Adding 2 or more will make it even more complicated.
I now had the approach to use multiple threads and the number of threads used for this to be specified by the user (1 to max 10). The implementation in the code currently looks like this (only changed parts compared to the previously posted code)
public void DisplayPlaylist(Playlist playlist)
{
for (int i = 0; i < SystemData.usedDisplayingThreads; i++)
{
Thread thread = new Thread(() => DisplayElements(playlist, i));
thread.Start();
}
}
private void DisplayElements(Playlist playlist, int startIndex)
{
for (int i = startIndex; i < playlist.elements.Count; i += SystemData.usedDisplayingThreads)
DisplayElement(playlist.elements[i], i);
}
The problem is that now very often null is returned by the GetThumbnail function, so an error occurs. In addition, a System.AccessViolationException is often thrown out.
In my opinion, the reason for this is the presence of multiple, simultaneously active VideoFileReaders. However, I do not know what exactly triggers the problem so I cannot present any solution. Maybe you know what the actual trigger is and how to fix the problem or maybe you also know other methods for speed improvement, which maybe even more elegant.
I would start with logging what exception is raised in GetThumbnail method. Your code hides it and returns null. Change to catch (Exception exc), write exception details in log or at least evaluate in debugger. That can give a hint.
Also I'm pretty sure your VideoFileReader instances are IDisposable, so you have to dispose them by invoking reader.Close(). Maybe previous instances were not disposed and you are trying to open same file multiple times.
Update: video frame has to be disposed as well. Probably you will need to do a copy of bitmap if it is referenced with reader and prevents disposion.
I have an WinRT application that fires notifications everytime it recieves data from a device. I also have a UI control that is databound to an observable collection which I wish to add the new data to
While I have made it capable of updating the observable collection, it causes the UI to become very laggy, as the amount of data generated it fast. It would therefore be better to batch the update, maybe every few hundred milliseconds.
Below shows a snippet of the code. First I create the periodic timer
TimerElapsedHandler f = new TimerElapsedHandler(batchUpdate);
CreatePeriodicTimer(f, new TimeSpan(0, 0, 3));
Below is my event handler for when new data comes in, along with the temporary list that stores the information
List<FinancialStuff> lst = new List<FinancialStuff>();
async void myData_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
var data = new byte[args.CharacteristicValue.Length];
DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);
lst.Add(new FinancialStuff() { Time = "DateTime.UtcNow.ToString("mm:ss.ffffff")", Amount = data[0] });
}
Then my batch update, which is called peroidically
private void batchUpdate(ThreadPoolTimer source)
{
AddItem<FinancialStuff>(financialStuffList, lst);
}
Then finally, for testing I want to clear the observable collection and items.
public async void AddItem<T>(ObservableCollection<T> oc, List<T> items)
{
lock (items)
{
if (Dispatcher.HasThreadAccess)
{
foreach (T item in items)
oc.Add(item);
}
else
{
Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
oc.Clear();
for (int i = 0; i < items.Count; i++)
{
items.Count());
oc.Add(items[i]);
}
lst.Clear();
});
}
}
}
While this seems to work, after a few updates the UI locks up and it updates very slowly/if not at all. For testing, it's only getting a few hundred items in the list by the time the timer is fired.
Can anybody enlighten me as to why as to why this is happening - I'm presuming my design is very poor.
Thanks
You're not locking your list in the event handler
// "lst" is never locked in your event handler
List<FinancialStuff> lst = new List<FinancialStuff>();
lst.Add(new FinancialStuff() { Time = "DateTime.UtcNow.ToString("mm:ss.ffffff")", Amount = data[0] });
Passing "lst" above to your async method
AddItem<FinancialStuff>(financialStuffList, lst);
You're locking "items" below, which is really "lst" above. However, you're adding to the list while your processing it. I assume the event handler has a higher priority so your processing is slower than your add. This can lead to "i < items.Count" being true forever.
public async void AddItem<T>(ObservableCollection<T> oc, List<T> items)
{
// "lst" reference is locked here, but it wasn't locked in the event handler
lock (items)
{
if (Dispatcher.HasThreadAccess)
{
foreach (T item in items)
oc.Add(item);
}
else
{
Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
oc.Clear();
// This may never exit the for loop
for (int i = 0; i < items.Count; i++)
{
items.Count());
oc.Add(items[i]);
}
lst.Clear();
});
}
}
}
EDIT:
Do you need to view every piece of data? There is going to be some overhead when using a lock. If you're getting data quicker than the speed of how fast you can render it, you'll eventually be backed up and/or have a very large collection to render, which might also cause some problems. I suggest you do some filtering to only draw the last x number of items (say 100). Also, I'm not sure why you need the if (Dispatcher.HasThreadAccess) condition either.
Try the following:
public async void AddItem<T>(ObservableCollection<T> oc, List<T> items)
{
// "lst" reference is locked here, but it wasn't locked in the event handler
lock (items)
{
// Change this to what you want
const int maxSize = 100;
// Make sure it doesn't index out of bounds
int startIndex = Math.Max(0, items.Count - maxSize);
int length = items.Count - startIndex;
List<T> itemsToRender = items.GetRange(startIndex, length);
// You can clear it here in your background thread. The references to the objects
// are now in the itemsToRender list.
lst.Clear();
// Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
// Please verify this is the correct syntax
Dispatcher.Run(() =>
{
// At second look, this might need to be locked too
// EDIT: This probably will just add overhead now that it's not running async.
// You can probably remove this lock
lock(oc)
{
oc.Clear();
for (int i = 0; i < itemsToRender.Count; i++)
{
// I didn't notice it before, but why are you checking the count again?
// items.Count());
oc.Add(itemsToRender[i]);
}
}
});
}
}
EDIT2:
Since your AddItem method is already on a background thread, I don't think you need to run the Dispatcher.RunAsync. Instead, I think it might be desirable for it to block so you don't end up with multiple calls to that section of code. Try using Dispatcher.Run instead. I've updated the code example above to show the changes. You shouldn't need the lock on the oc anymore since the lock on the items is good enough. Also, verify the syntax for Dispatcher.Run is correct.
I am just playing around with arrays of rectangles in c# everything is working fine until I want to cycle between "layers" of rectangles, after cycling a few times to application (Silverlight) becomes very slow.
My code is as follows, would it be possible to offer any advice on what could be causing this degradation?
private int worldHeight = 20;
private int currentLayerNo = 0;
private int keypressCounter = 0;
public MainPage()
{
InitializeComponent();
createGrid();
}
private void createGrid()
{
blockCanvas.Children.Clear();
int x = 0, y = 0;
Layer generateWorld = new Layer();
generateWorld.z = worldHeight;
generateWorld.x = 50;
generateWorld.y = 50;
generateWorld.Gen();
Rectangle[,] currentLayer = generateWorld.createLayer(currentLayerNo);
for (int a = 0; a < currentLayer.GetLength(0); a++)
{
for (int b = 0; b < currentLayer.GetLength(1); b++)
{
Rectangle currentBlock = new Rectangle();
currentBlock = currentLayer[a, b];
blockCanvas.Children.Add(currentBlock);
Canvas.SetTop(currentBlock, x);
Canvas.SetLeft(currentBlock, y);
y = y + 32;
}
x = x + 32;
y = 0;
}
currentLayer = null;
this.KeyDown += new KeyEventHandler(onKeyDown);
}
private void onKeyDown(object sender, KeyEventArgs e)
{
//Code here cycles between layers, each time calling the createGrid() method after altering currentLayerNo
}
}
Each time you call createGrid() you are also calling this.KeyDown += new KeyEventHandler(onKeyDown); which adds a new event listener.
On the first call to createGrid() this means that on key down createGrid() will be called once, which will then register again for KeyDown, meaning will now be called twice. On the next KeyDown event createGrid() is called twice and each time it adds itself to the KeyDown event.
Repeat until slow down.
You can put the registration in the MainPage constructor.
Clearing and adding children on Canvas is performance intensive operation. If you want to improve performance, use caching. By this I mean instead of recreating all those rectangles, simply reuse them.
Reposition the ones you need, add extras if you need some or hide those that were created in the previous step, but will not be needed now.
Another reason for performance problem is that you have added the same event handler over and over again whenever you call creategrid. This means that when you press the key for the second time, you will call createGrid 2 times. On the each subsequent key press, you double the number of calls to createGrid.
Try to remove that line first and see if you need to use caching. I needed it in visually heavy WPF application and it worked like a charm.
This is the code in the NumericUpDown ValueChanged event:
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
DoThresholdCheck();
}
And this is the DoThresholdCheck() code:
private void DoThresholdCheck()
{
List<int> f;
List<string> fts;
const string D6 = "000{0}.bmp";
if (Directory.Exists(subDirectoryName))
{
if (!File.Exists(subDirectoryName + "\\" + averagesListTextFile + ".txt"))
{
return;
}
else
{
f = new List<int>();
fts = new List<string>();
Bitmap myFiles;
int counter = 0;
double thershold = (double)numericUpDown1.Value;
double max_min_threshold = (thershold / 100) * (max - min) + min;
_fi = new DirectoryInfo(subDirectoryName).GetFiles("*.bmp");
for (int i = 0; i < myNumbers.Count; i++)
{
if (myNumbers[i] >= max_min_threshold)
{
string t = i.ToString("D6") + ".bmp";
if (File.Exists(subDirectoryName + "\\" + t))
{
button1.Enabled = false;
myTrackPanelss1.trackBar1.Enabled = true;
}
else
{
button1.Enabled = true;
myTrackPanelss1.trackBar1.Enabled = false;
pictureBox1.Image = Properties.Resources.Weather_Michmoret;
label5.Visible = true;
break;
}
}
}
if (myTrackPanelss1.trackBar1.Maximum > 0)
{
SetPicture(0);
myTrackPanelss1.trackBar1.Scroll += new EventHandler(trackBar1_Scroll);
}
if (_fi.Length >= 0)
{
label15.Text = _fi.Length.ToString();
label15.Visible = true;
}
}
}
else
{
button1.Enabled = true;
}
}
What I want to do is; each time I change the NumericUpDown value in the program it will call the function in the event. In the event I create a new temp list each time and perform operations and make some checks on that list.
The problem is when I'm changing the NumericUpDown value a few times up and down in the program and then try to use the trackBar1 to move between the images again, the trackbar1 moves very slowly. When initially running the program, the slide bar in the trackbar1 moves quickly and moves quickly between images, but when I change the NumericUpDown values the trackbar moves slowly for some reason.
I tried to add a Timer2 and maybe use it in the NumericUpDown to make it call the function only after 500ms, for example, but it didn't solve it.
I can't figure out why its moving so slow.
I'am not shore if it is the problem, but seems you adding event handler myTrackPanelss1.trackBar1.Scroll += new EventHandler(trackBar1_Scroll); but never removing it. So you always adding event handler and after a wile trackBar1_Scroll will be fired many times. Set breakpoint in trackBar1_Scroll and you will see how many times event handler is raised. Solution could be remove event handler or add it just one time.
For starters, you are performing quite a few IO operations. This can be a costly operation, particularly when you are running it frequently (i.e. on the NumericUpDown's ValueChanged event). I would advise performing as much of this as possible in some initialization operation, not on each event firing.
Secondly, I'm not sure if it will actually affect the performance, but you keep attaching an event handler to the trackBar1.Scroll event. Since I don't see anywhere where you detach from this event, I would say that this is unnecessary. Either you need to better control the attachment and detachment, or simply attach once during control setup. It might also be worth creating a test program to see if attaching the same event handler multiple times does affect performance.
Finally, you could go about this operation by creating a background worker, on which you perform this operation each time it is signalled. If you make use of a wait handle, you can run the operation in a queue-like fashion. This would then not affect your UI operations, but you would have to be careful with what UI functions you call, as they can only be invoked on the UI thread. If you wish to know more about this, let me know and I will give you a brief example.