Я лично предпочитаю не видеть, чтобы указатель мыши много раз переключался с песочных часов на стрелку.
Чтобы предотвратить такое поведение при вызове встроенных функций, которые занимают некоторое время, и каждая пытается управлять указателем мыши, я использую стек (счетчик), который я называю LifeTrackerStack. И только когда стопка пуста (счетчик 0), я ставлю песочные часы обратно на стрелку.
Я также использую MVVM. Я также предпочитаю потокобезопасный код.
В моем корневом классе модели я объявляю свой LifeTrackerStack, который я либо заполняю в дочерних модельных классах, либо использую напрямую из дочерних модельных классов, когда у меня есть к ним доступ.
Мой жизненный трекер имеет 2 состояния / действия:
- Alive (counter> 0) => превратить Model.IsBusy в true;
- Готово (счетчик == 0) => превратить Model.IsBusy в false;
Затем, на мой взгляд, я вручную связываюсь со своим Model.IsBusy и делаю:
void ModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsBusy")
{
if (this._modelViewAnalysis.IsBusy)
{
if (Application.Current.Dispatcher.CheckAccess())
{
this.Cursor = Cursors.Wait;
}
else
{
Application.Current.Dispatcher.Invoke(new Action(() => this.Cursor = Cursors.Wait));
}
}
else
{
Application.Current.Dispatcher.Invoke(new Action(() => this.Cursor = null));
}
}
Это мой класс LifeTrackerStack:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
namespace HQ.Util.General
{
/// <summary>
/// Usage is to have only one event for a recursive call on many objects
/// </summary>
public class LifeTrackerStack
{
// ******************************************************************
protected readonly Action _stackCreationAction;
protected readonly Action _stackDisposeAction;
private int _refCount = 0;
private object _objLock = new object();
// ******************************************************************
public LifeTrackerStack(Action stackCreationAction = null, Action stackDisposeAction = null)
{
_stackCreationAction = stackCreationAction;
_stackDisposeAction = stackDisposeAction;
}
// ******************************************************************
/// <summary>
/// Return a new LifeTracker to be used in a 'using' block in order to ensure reliability
/// </summary>
/// <returns></returns>
public LifeTracker GetNewLifeTracker()
{
LifeTracker lifeTracker = new LifeTracker(AddRef, RemoveRef);
return lifeTracker;
}
// ******************************************************************
public int Count
{
get { return _refCount; }
}
// ******************************************************************
public void Reset()
{
lock (_objLock)
{
_refCount = 0;
if (_stackDisposeAction != null)
{
_stackDisposeAction();
}
}
}
// ******************************************************************
private void AddRef()
{
lock (_objLock)
{
if (_refCount == 0)
{
if (_stackCreationAction != null)
{
_stackCreationAction();
}
}
_refCount++;
}
}
// ******************************************************************
private void RemoveRef()
{
bool shouldDispose = false;
lock (_objLock)
{
if (_refCount > 0)
{
_refCount--;
}
if (_refCount == 0)
{
if (_stackDisposeAction != null)
{
_stackDisposeAction();
}
}
}
}
// ******************************************************************
}
}
using System;
namespace HQ.Util.General
{
public delegate void ActionDelegate();
public class LifeTracker : IDisposable
{
private readonly ActionDelegate _actionDispose;
public LifeTracker(ActionDelegate actionCreation, ActionDelegate actionDispose)
{
_actionDispose = actionDispose;
if (actionCreation != null)
actionCreation();
}
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this._disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
_actionDispose();
}
// Note disposing has been done.
_disposed = true;
}
}
}
}
И использование его:
_busyStackLifeTracker = new LifeTrackerStack
(
() =>
{
this.IsBusy = true;
},
() =>
{
this.IsBusy = false;
}
);
Везде, где у меня длинная пробежка, я делаю:
using (this.BusyStackLifeTracker.GetNewLifeTracker())
{
// long job
}
Это работает для меня.
Надеюсь, что это может помочь любому!
Eric