Eliminate flickering from a user control [duplicate] - c#

I would like to update some or all of my listview's items and subitems contents with a timer (1 second refresh) But the listview flicker each one second. Sometimes the subitems are lost during redrawing. Because my listview contains data that is to be likely changed anytime, I use a timer.
Code:
I put this function in the timer's Tick method
void Refresh()
{
foreach(string s in lsttring)
{
lv.items.add(s);
lv.items[i].subitems.add(i);
}
}
I expect only items content (item text and subitem text) that are changed will be changed not the whole listview along with the timer tick.

The ListView control supports double buffering, it maps the DoubleBuffered property to the native control's LVS_EX_DOUBLEBUFFER style flag. It is quite effective but you can't get to it directly since it is a protected property. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form, replacing the old one.
using System;
using System.Windows.Forms;
class BufferedListView : ListView {
public BufferedListView() {
this.DoubleBuffered = true;
}
}

Try this:
void Refresh()
{
lv.BeginUpdate();
foreach(string s in lsttring)
{
lv.items.add(s);
lv.items[i].subitems.add(i);
}
lv.EndUpdate();
}
In this manner you update all the items and listview will be refreshed only at the end of this operation.
From Microsoft:
...if you want to add items one at a time using the Add method of the
ListView.ListViewItemCollection class, you can use the BeginUpdate
method to prevent the control from repainting the ListView every time
that an item is added. When you have completed the task of adding
items to the control, call the EndUpdate method to enable the ListView
to repaint. This way of adding items can prevent flickered drawing of
the ListView when lots of items are being added to the control.

Related

c# - listview does not add items when using a delegate

Using a worker thread, I am adding items to a ListView, however to do this I have implemented a delegate in the form as shown below in the code sample.
Problem:
When the ListView.Items.add() line is executed, nothing is added to the ListView
What I have tried:
I added a button, when clicked, it successfully adds a ListViewItem to the ListView object, as it should. (this is before the worker thread start, for testing/debugging)
I have also tried swapping the ListView to a RichEdit in case I had a bug in the code, but the items successfully display in the RichEdit, thus I added another ListView incase the first/previous one was buggy, and without renaming the ListView, I tried adding the items, but without success.
What happens in the Delegate:
Nothing, after the clear() method, the 4 columns each with headers disappear and nothing is added to the list view
Conclusion:
My only conclusion is that the delegate is not compatible with the ListView, since I was able to add the items to a RichEdit, but not to a ListView.
Is this a bug? Am I doing something wrong?
code sample
void connected_add_device()
{
string[] t = { "123", "-1", "sa.d.sdf.s.fg", "sda-f-sd-fgds-gf" };
if (display_connected_Devices.InvokeRequired)
display_connected_Devices.BeginInvoke((MethodInvoker)delegate ()
{
display_connected_Devices.Clear();
display_connected_Devices.Items.Add(new ListViewItem(t));
}
);
else
{
display_connected_Devices.Clear();
display_connected_Devices.Items.Add(new ListViewItem(t));
}
}
For what it is worth, I had a bad GIT commit. After everthing is fixed, this ListView (which before the GIT issue, had successfuly displayed the items) now doesn't display the items anymore.
Use display_connected_Devices.Items.Clear(); instead. Because display_connected_Devices.Clear(); will clear, like you noticed, the columns aswell.

Manually redrawing a custom control when WPF requests an arrangement

I have a custom control that has a refresh method, something similar to this:
public class MyControl : Canvas
{
// Dependency property for "data" used to draw the control here
public void Refresh()
{
Children.Clear();
// Using data, draw the control
Children.Add(new Line(...));
Children.Add(new Rectangle(...));
// etc.
}
}
Right now, I have to call Refresh() manually each time I want the look of the control to update. My dependency properties are set up for FrameworkPropertyMetadataOptions.AffectsArrange, so WPF knows that modifying the properties will affect the arrangement of the control and that it should be redrawn. So here's the question:
What does WPF use to tell a custom control that it should be redrawn? Is it an event, or an override, and how should it be used? I've tried handling various events and overrides and nothing seems to work. So, what's the correct way to do this? I want to replace / wrap the Refresh() method above in something "automatic" that WPF will handle automatically.

Why does changing the HeaderStyle of a ListView hang the application?

I've been trying to fix this issue and it seems to be a problem from the .Net framework. anyway, I have a listview which contains 5000+ items and a button used to do further processing to the selected items in the listview. now clicking this button should also set "listview.HeaderStyle" property of the listview to "ColumnHeaderStyle.Nonclickable".
now when I do that. the program hangs for like 10 seconds then continues its work. I have no idea what is causing and why this is happening. I hope you guys have a solution for this.
any ideas?
I've found a basic solution for now, all I need is to set
myListview.ColumnClick += new ColumnClickEventHandler(delegate{});
Now I don't need to change "listview.HeaderStyle" property anymore.
basically I was disabling the ColumnClick event from the HeaderStyle property and that's all. so instead of setting the HeaderStyle to nonClickable. I just remove/change the function inside event handler.
You can solve this problem using BackgroundWorker MSDN.
Note : Even using this solution your form will hang for some time. Because you have 5000+ items to be bind to the list, which will block your UI thread, hence winform will hang. But your listview.HeaderStyle will get modified.
Try this
On button click, you directly change the propert of listview.HeaderStyle to ColumnHeaderStyle.Nonclickable. Then call RunWorkerAsync of BackgroundWorker.
On DoWork event handler you do the processing, and once done bind data to list view. To do this you will need to add following extension class to your project.
Extension Class
public static class ControlExtensions
{
public static void Invoke(this Control control, Action action)
{
if (control.InvokeRequired) control.Invoke(new MethodInvoker(action), null);
else action.Invoke();
}
}
Using this you can bind data to listview
listview.Invoke(() => ( listview.DataSource = dataSource; });
Hope this works for you.

Listview flickers when I update it with a timer

I would like to update some or all of my listview's items and subitems contents with a timer (1 second refresh) But the listview flicker each one second. Sometimes the subitems are lost during redrawing. Because my listview contains data that is to be likely changed anytime, I use a timer.
Code:
I put this function in the timer's Tick method
void Refresh()
{
foreach(string s in lsttring)
{
lv.items.add(s);
lv.items[i].subitems.add(i);
}
}
I expect only items content (item text and subitem text) that are changed will be changed not the whole listview along with the timer tick.
The ListView control supports double buffering, it maps the DoubleBuffered property to the native control's LVS_EX_DOUBLEBUFFER style flag. It is quite effective but you can't get to it directly since it is a protected property. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form, replacing the old one.
using System;
using System.Windows.Forms;
class BufferedListView : ListView {
public BufferedListView() {
this.DoubleBuffered = true;
}
}
Try this:
void Refresh()
{
lv.BeginUpdate();
foreach(string s in lsttring)
{
lv.items.add(s);
lv.items[i].subitems.add(i);
}
lv.EndUpdate();
}
In this manner you update all the items and listview will be refreshed only at the end of this operation.
From Microsoft:
...if you want to add items one at a time using the Add method of the
ListView.ListViewItemCollection class, you can use the BeginUpdate
method to prevent the control from repainting the ListView every time
that an item is added. When you have completed the task of adding
items to the control, call the EndUpdate method to enable the ListView
to repaint. This way of adding items can prevent flickered drawing of
the ListView when lots of items are being added to the control.

What is the best way to sort controls inside of a flowlayout panel?

I am adding custom controls to a FlowLayoutPanel. Each control has a date property. I would like to sort the controls in the flowlayoutpanel based on the date property. I can't presort the controls before I add them because it is possible for the user to add more.
My current thought is when the ControlAdded event for the FlowLayoutPanel is triggered I loop through the controls and use the BringToFront function to order the controls based on the date.
What is the best way to do this?
I doubt this is the best but is what I have so far:
SortedList<DateTime,Control> sl = new SortedList<DateTime,Control>();
foreach (Control i in mainContent.Controls)
{
if (i.GetType().BaseType == typeof(MyBaseType))
{
MyBaseType iTyped = (MyBaseType)i;
sl.Add(iTyped.Date, iTyped);
}
}
foreach (MyBaseType j in sl.Values)
{
j.SendToBack();
}
BringToFront affects the z-order not the x/y position, I suspect you want to sort the FlowLayoutPanel.Controls collection when someone adds or deletes controls in the panel. Probably use SuspendLayout and ResumeLayout around the sorting code.

Categories

Resources