#c# #winforms #mouseevent #mouse #trackbar
#c# #winforms #mouseevent #мышь #трекбар
Вопрос:
У меня есть панель треков в моей программе WinForms, которая будет обновлена путем ее перемещения — огромный и трудоемкий метод. Взгляните на этот код:
trackBar_ValueChanged(object sender, EventArgs e)
{
this.RefreshData();
}
Эта панель треков состоит из 20 шагов. Если пользователь возьмет ползунок трекбара и переместит его с 20 на 0 в моем случае, ‘REFRESHHDATA’ будет выполняться 20 раз, хотя он показывает правильные данные, когда завершает процесс, который называется ‘REFRESHHDATA’ со значением 0, я хочу сделать что-то вроде того, что он вызывает ‘REFRESHHDATA’ только при отпускании ползунка трекбара, поэтому он не будет обрабатывать все шаги до точки отпускания на трекбаре.
Любая помощь и советы по достижению этого были бы полезны! Спасибо.
Комментарии:
1. мммм, WPF? Silverlight? Winforms? (и т.д.)
2. спасибо, теперь вы получите ответы получше 🙂
Ответ №1:
Как насчет:
Boolean user_done_updating = false;
private void MytrackBar_ValueChanged(object sender, EventArgs e)
{
user_done_updating = true;
}
private void MytrackBar_MouseUp(object sender, MouseEventArgs e)
{
if (user_done_updating)
{
user_done_updating = false;
//Do Stuff
}
}
Ответ №2:
Способ, которым я делал подобные вещи раньше, — это использовать таймер. Каждый раз, когда изменяется значение трекбара, сбрасывайте таймер, чтобы он срабатывал через 500 мс (или что-то другое, подходящее для вас). Если пользователь изменит значение до срабатывания таймера, оно снова будет сброшено, что означает, что даже если оно изменяется несколько раз, таймер сработает только один раз.
Единственное, на что здесь следует обратить внимание, это то, что таймер сработает в другом потоке, и вы не сможете обновить пользовательский интерфейс из этого потока, поэтому вам придется снова вызвать поток пользовательского интерфейса, чтобы внести там изменения. Тем не менее, если вы сможете перенести большую часть своей дорогостоящей работы в этот фоновый поток, вы дольше сохраните адаптивный пользовательский интерфейс.
Вот несколько примеров кода, которые должны дать вам некоторое представление о том, что я имею в виду.
public partial class Form1 : Form
{
private int updateCount;
private System.Threading.Timer timer;
public Form1()
{
this.InitializeComponent();
this.timer = new System.Threading.Timer(this.UpdateValue);
}
private void UpdateValue(object state)
{
// Prevent the user from changing the value while we're doing
// our expensive operation
this.Invoke(new MethodInvoker(() => this.trackBar1.Enabled = false));
// Do the expensive updates - this is still on a background thread
this.updateCount ;
this.Invoke(new MethodInvoker(this.UpdateUI));
}
private void UpdateUI()
{
this.label1.Text = this.updateCount.ToString();
// Re-enable the track bar again
this.trackBar1.Enabled = true;
}
private void trackBar1_ValueChanged(object sender, EventArgs e)
{
this.timer.Change(TimeSpan.FromMilliseconds(500), new TimeSpan(-1));
}
}
Редактировать: Вот решение, которое использует таймер win forms для определения времени. Разница здесь в том, что вы заблокируете пользовательский интерфейс во время выполнения вычисления; в вашей ситуации это может быть нормально, а может и нет.
public partial class Form1 : Form
{
private int updateCount;
private Timer timer;
public Form1()
{
this.InitializeComponent();
this.timer = new Timer();
this.timer.Interval = 500;
this.timer.Tick = this.Timer_Tick;
}
private void Timer_Tick(object sender, EventArgs e)
{
this.timer.Stop();
this.updateCount ;
this.label1.Text = this.updateCount.ToString();
}
private void trackBar1_ValueChanged(object sender, EventArgs e)
{
this.timer.Stop();
this.timer.Start();
}
}
Комментарии:
1. @Mike Спасибо, я попробую это, но я искал что-то более простое, может быть, просто с событиями на самом деле.
2. К сожалению, я не думаю, что вы найдете здесь событие, соответствующее вашим целям — по сути, вам нужно событие с именем «UserFinishedUpdating», которое срабатывает, когда пользователь перестает изменять значение, независимо от того, делали ли они это с помощью мыши или клавиатуры. В конечном итоге это то, что даст вам этот код. Дайте мне знать, как у вас дела, и если вам нужны какие-либо пояснения.
3. В чем преимущество запуска нового потока для таймера? Почему вы не можете просто запустить таймер в потоке пользовательского интерфейса (используя
System.Windows.Forms.Timer
) и вызывать метод обновления только тогда, когда пользователь закончит перемещать ползунок в течение заранее определенного количества миллисекунд?4. Я думаю, единственное преимущество здесь в том, что вы можете запускать любые дорогостоящие вычисления в фоновом потоке, но вы правы, если вы не возражаете заблокировать пользовательский интерфейс, вы могли бы просто использовать таймер форм — я обновил свой ответ и этой опцией, спасибо.
5. @Mike Еще раз спасибо. Я бы хотел, чтобы пользовательское обновление было доступным: P Ваш код работает хорошо!
Ответ №3:
Рассмотрите возможность выполнения продолжительного метода в новом потоке. Сохраните ссылку на этот поток и вызовите Thread.Прервать () перед повторным запуском.
Ответ №4:
Попробуйте KeyUp
событие:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keyup.aspx
Комментарии:
1. Проблема
MouseUp
в том, что он не запускается, когда пользователь изменяет значение трекбара с помощью клавиатуры. Вам все еще нужно будет обработатьValueChanged
для этого случая.