C# Dispatcher仅从数组中提取最后一个对象
我有一个多维的C# Dispatcher仅从数组中提取最后一个对象,c#,wpf,multidimensional-array,C#,Wpf,Multidimensional Array,我有一个多维的Tile对象数组 我的程序首先在随机位置(例如(0,0))选择一个磁贴,访问一个随机的邻居磁贴,将其标记为已访问并移动到下一个邻居,直到没有未访问的邻居可用 这是我的代码: while (HasUnvisitedNeighbours()) { Task.Run(() => { Application.Current.Dispatcher.BeginInvoke(new Action(() => {
Tile
对象数组
我的程序首先在随机位置(例如(0,0))选择一个磁贴
,访问一个随机的邻居磁贴
,将其标记为已访问并移动到下一个邻居,直到没有未访问的邻居可用
这是我的代码:
while (HasUnvisitedNeighbours())
{
Task.Run(() =>
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
CurrentTile.Draw();
}));
Thread.Sleep(500);
});
//1. Choose randomly a neighbour
List<char> Keys = new List<char>(CurrentTile.Neighbours.Keys);
char randomKey = Keys[rnd.Next(Keys.Count)];
CurrentTile = CurrentTile.Neighbours[randomKey];
CurrentTile.HasBeenVisited = true;
}
正确地将每个循环更改为正确的邻居,并且当其旁边没有未访问的邻居时,循环将停止
但在:
Task.Run(() =>
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
CurrentTile.Draw();
}));
Thread.Sleep(500);
});
CurrentTile.Draw()
在调试器中似乎总是具有相同的值(CurrentTile=CurrentTile.Neights[randomKey];
。因此,调度程序似乎等待整个循环完成,然后绘制最后一个Tile
对象
我的意图是绘制当前的
磁贴
->移动到邻居->将其标记为当前磁贴->绘制当前磁贴->。您的BeginInvoke
正在安排(排队)某些“工作”由特定的调度器来完成,即通常是您的主UI消息循环/处理线程
当您处于“while循环”中时,您已经在Dispatcher
线程上处理/执行工作(但它是针对不同的/以前的消息)
(通常情况下,调度程序
无法处理队列中的下一条“调度”消息,直到您完成所做的操作并控制返回到调度程序
…然后调度程序
可以选择下一条要处理的消息(可能是您的消息,也可能是其他人的消息,取决于优先级)
(有关windows消息循环/调度程序工作方式的更深入的描述,请参阅:)
这段代码将启动一个任务
,该任务将持续导致随机分幅被访问,直到所有hasunvisitedneights()
返回false
您也可以使用.Invoke
(同步版本),而不是.BeginInvoke
和.Wait
组合
注意:人们常说最好使用.BeginInvoke
,而不是。在某些情况下调用。调用可能会死锁……但我认为在这种情况下,您可以使用其中一种
您可以执行hasunvisitednights();
,然后执行.Draw
,如果愿意,只需一次“调用”即可选择下一个磁贴
但是,我将其拆分为2个“调用”,因为您可以重新构造它,以便只获得一次未访问的tile列表(通过查询所有tiles.HasBeenVisited属性),然后只修改该列表,而不是再次询问所有互动程序-这是因为您是访问互动程序的人…因此您知道他们现在是否已被访问
void VisitAllNeighbours()
{
Task.Run(() =>
{
while (true)
{
bool bHasUnvisitedNeighbours = false;
DispatcherOperation dispopunvisitedtiles = Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
bHasUnvisitedNeighbours = HasUnvisitedNeighbours();
};
dispopunvisitedtiles.Wait();
if (!bHasUnvisitedNeighbours)
break;
DispatcherOperation dispopvisitnext = Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
CurrentTile.Draw();
//1. Choose randomly a neighbour
List<char> Keys = new List<char>(CurrentTile.Neighbours.Keys);
randomKey = Keys[rnd.Next(Keys.Count)];
CurrentTile = CurrentTile.Neighbours[randomKey];
CurrentTile.HasBeenVisited = true;
}));
// Take out this "wait" if you want multiple "visits" to be
// pending/scheduled instead of only one at a time - be
// careful that your "random visiting" selection code
// doesn't cause too many "visits" to be outstanding though!
//
// Note: each visit never occurs at the same time as another
// one as the "Dispatcher"/message loop is providing the
// serialization.
dispopvisitnext.Wait();
Thread.Sleep(500); // if you want a "delay" between each Tile visit
);
}
}
void visitallneights()
{
Task.Run(()=>
{
while(true)
{
bool BhasunVisitedNeights=假;
DispatcherOperation DispatpopunVisitedTiles=Application.Current.Dispatcher.BeginInvoke(新操作(()=>
{
bhasunVisitedNeights=hasunVisitedNeights();
};
dispopunvisitedtiles.Wait();
如果(!BhasunVisitedNeights)
打破
DispatcherOperation DispatchepVisitNext=Application.Current.Dispatcher.BeginInvoke(新操作(()=>
{
CurrentTile.Draw();
//1.随机选择一个邻居
列表键=新列表(CurrentTile.neights.Keys);
随机键=键[rnd.Next(键数)];
CurrentTile=CurrentTile.Neights[randomKey];
CurrentTile.HasBeenVisited=true;
}));
//如果你想进行多次“访问”,请去掉这个“等待”
//挂起/计划,而不是一次仅一个-可能
//小心你的“随机访问”选择代码
//但不会导致太多的“访问”变得杰出!
//
//注意:每次访问不会与另一次同时进行
//一个是“Dispatcher”/消息循环提供
//序列化。
dispopvisitnext.Wait();
Thread.Sleep(500);//如果您想在每次访问之间获得“延迟”
);
}
}
因此,调度器似乎等待整个循环完成,然后绘制最后一个平铺对象
是的,Dispatcher.BeginInvoke
计划最终在Dispatcher线程上执行委托。但是为什么启动新任务只是为了调用Dispatcher.BeginInvoke
?这没有多大意义
您可以使用synchronousInvoke
方法等待,直到在dispatcher线程上执行该方法:
while (HasUnvisitedNeighbours())
{
Application.Current.Dispatcher.Invoke(new Action(() => CurrentTile.Draw()));
Thread.Sleep(500);
List<char> Keys = new List<char>(CurrentTile.Neighbours.Keys);
char randomKey = Keys[rnd.Next(Keys.Count)];
CurrentTile = CurrentTile.Neighbours[randomKey];
CurrentTile.HasBeenVisited = true;
}
while(hasunVisitedNeights())
{
Application.Current.Dispatcher.Invoke(新操作(()=>CurrentTile.Draw());
睡眠(500);
列表键=新列表(CurrentTile.neights.Keys);
char randomKey=Keys[rnd.Next(Keys.Count)];
CurrentTile=CurrentTile.Neights[randomKey];
CurrentTile.HasBeenVisited=true;
}
编辑:
UI线程无法同时执行循环和更新UI。您可以尝试在后台线程上运行代码:
private void Method()
{
Task.Run(async () =>
{
while (HasUnvisitedNeighbours())
{
await Application.Current.Dispatcher.BeginInvoke(new Action(() => CurrentTile.Draw()));
await Task.Delay(500);
List<char> Keys = new List<char>(CurrentTile.Neighbours.Keys);
char randomKey = Keys[rnd.Next(Keys.Count)];
CurrentTile = CurrentTile.Neighbours[randomKey];
CurrentTile.HasBeenVisited = true;
}
});
}
private void方法()
{
Task.Run(异步()=>
{
while(hasunVisitedNeights())
{
等待Application.Current.Dispatcher.BeginInvoke(新操作(()=>CurrentTile.Draw());
等待任务。延迟(500);
列表键=新列表(CurrentTile.neights.Keys);
char randomKey=Keys[rnd.Next(Keys.Count)];
CurrentTile=CurrentTile.Neights[randomKey];
CurrentTile.HasBeenVisited=true;
}
});
}
啊,我明白了,但是为什么它只将最后一个磁贴排成队列,而不说第一个。还有,这是错误的吗
private void Method()
{
Task.Run(async () =>
{
while (HasUnvisitedNeighbours())
{
await Application.Current.Dispatcher.BeginInvoke(new Action(() => CurrentTile.Draw()));
await Task.Delay(500);
List<char> Keys = new List<char>(CurrentTile.Neighbours.Keys);
char randomKey = Keys[rnd.Next(Keys.Count)];
CurrentTile = CurrentTile.Neighbours[randomKey];
CurrentTile.HasBeenVisited = true;
}
});
}