我正在尝试构建一个显示加载圈的按钮,并在C#应用程序中加载一些数据。
我有一个名为Loading
的布尔值,用于跟踪正在加载的当前数据的状态。
我有一个名为LoadHandler
的委托,它根据加载是否完成返回一个布尔值,我还有一个事件可以在一个单独的类中订阅,该类接受LoadHandler
签名并处理实际加载。
我有一个private Load()
函数,当在基类中调用输入的事件处理程序时调用该函数,这在new Thread
上调用。
以下是LoadEntry
类的代码(请记住,这只是一个按钮,在按下时显示加载圈,并委托加载到单独的类中)
public class LoadingEntry : ButtonEntry
{
private readonly object objLock = new object();
/// <summary>
/// The loading circle texutre
/// </summary>
Texture2D loadingReticle;
/// <summary>
/// Tracks the rotation of the loading reticle.
/// </summary>
float loadingRotation;
/// <summary>
/// Tells whether we are loading or not
/// </summary>
public bool Loading { get; private set; }
public LoadingEntry(string buttonText)
: base(buttonText)
{
}
/// <summary>
/// Handler that will return true when loading information is complete
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <returns>True if loading is complete</returns>
public delegate bool LoadHandler(object sender, EventArgs e);
/// <summary>
/// The LoadHandler event that should be subscribed to in a menu class
/// </summary>
public event LoadHandler onLoad;
private void Load()
{
if (onLoad != null)
{
lock (objLock)
{
Loading = true;
while (true)
{
Loading = onLoad(this, EventArgs.Empty);
if (!Loading)
break;
}
}
}
}
protected internal override void OnSelectEntry(PlayerIndex playerIndex)
{
Thread t = new Thread(new ThreadStart(Load));
t.Start();
base.OnSelectEntry(playerIndex);
}
public override void Draw(MenuScreen screen, bool isSelected, GameTime gameTime, bool fade)
{
if (Loading)
{
loadingReticle = screen.ScreenManager.LoadingReticle;
Vector2 origin = new Vector2(loadingReticle.Width / 2, loadingReticle.Height / 2);
loadingRotation += 0.01f;
screen.ScreenManager.SpriteBatch.Draw(loadingReticle, position, null, Color.White, loadingRotation, origin, 1f, SpriteEffects.None, 1f);
}
else base.Draw(screen, isSelected, gameTime, fade);
}
基类ButtonEntry
不应该很重要。
以下是在另一个类中订阅onLoad
的内容:(仅用于练习,这是实际加载代码的去处)
int sampleTics = 0;
bool sampleLoad_onLoad(object sender, System.EventArgs e)
{
sampleTics++;
if (sampleTics < 1000)
return true;
return false;
}
我的问题是我是否正确使用多线程?代码甚至没有显示圆圈,我还没有做太多测试,因为我要睡觉了。在这种情况下锁定是否必要?有没有更好的方法来做到这一点,我没有看到?
答案 0 :(得分:1)
bool
是线程安全的。有关类似问题,请参阅documentation。根据帖子的建议,您还需要声明布尔变量volatile
,以便不缓存其值。您无法声明属性volatile
,因此您需要添加支持属性并声明该属性。
答案 1 :(得分:0)
事实证明我需要致电Thread.Sleep(1);
才能看到结果。这是完整的代码:
private void Load()
{
if (onLoad != null)
{
loading = true;
while (true)
{
loading = onLoad(this, EventArgs.Empty);
if (!loading)
break;
Thread.Sleep(1);
}
}
}