Резьбовая проблема приложения
У меня возникла проблема, когда первый элемент в коллекции отвечает на обновление, но нет других (из 40). Я искал ответы в сети, но, к сожалению, через пару дней я все еще ничего не получаю.
Код вызова, который запускает поток для цикла обнаружения:
_detectionThread = new Thread(() => _x.StartDetection());
_detectionThread.Start();
Я получил следующий код в одном из моих вспомогательных классов, который просто опрашивает, и когда что-то обнаруживается, посредством события вызывается View-Model:
public event EventHandler SomethingIsDetected;
private void OnSomethingDetected()
{
if (SomethingIsDetected!= null)
{
SomethingIsDetected(this, new EventArgs());
}
}
Код для обнаружения петли:
var startCheckTime = DateTime.Now;
var nextCheck = startCheckTime.AddSeconds(PollingInterval.TotalSeconds);
while (_performDetection)
{
startCheckTime = DateTime.Now;
if (startCheckTime >= nextCheck)
{
nextCheck = startCheckTime.AddSeconds(PollingInterval.TotalSeconds);
{
var detectionTask = Task.Factory.StartNew(() => IsXConnected());
IsXPresent = detectionTask.Result;
Thread.Sleep(TimeSpan.FromSeconds(1));
if (IsXPresent)
{
Application.Current.Dispatcher.Invoke(new Action(OnSomethingDetected));
}
}
}
Thread.Sleep(10);
}
Код для обновления предметов. Вид привязан к свойствам здесь (особенно CurrentItem). Предметы - это ObservableCollection
foreach (var item in Items) //loop through 40 items
{
//do some operation then set the current item
Application.Current.Dispatcher.Invoke(new Action(() => CurrentItem = item));
}
Пока я прохожу (с помощью отладочного конвертера), я замечаю, что элемент обновляется только в первый раз. Остальное просто проходит. У меня есть свойство CurrentItem с DependencyProperty.
Я пытался использовать CheckAccess, чтобы использовать свойство Delegate и udpate, и это тоже не помогло.
Любая помощь приветствуется и спасибо!
1 ответ
Ваша проблема не имеет ничего общего с многопоточностью, она связана с тем, как замыкания захватывают переменные в вашем последнем фрагменте кода. Вы все лямбы разделяете одну переменную, то есть item
переменная. Так как ваша лямда бежит после окончания цикла item
всегда будет установлен последний элемент в коллекции элементов. (Хотя они могут запускаться с любым предметом, в зависимости от того, когда именно он будет запущен)
Компилятор преобразует:
foreach (var item in Items) //loop through 40 items
{
//do some operation then set the current item
Application.Current.Dispatcher.Invoke(new Action(() => CurrentItem = item));
}
к чему-то морально эквивалентному этому:
class closuseCapture {
private ItemType itemCapture;
public void Loop() {
foreach (var item in Items) //loop through 40 items
{
itemCapture = item;
//do some operation then set the current item
Application.Current.Dispatcher.Invoke(new Action(ActionMethod));
}
}
public void ActionMethod() {
CurrentItem = itemCapture;
}
Исправление состоит в том, чтобы объявить переменную внутри вашего цикла, чтобы каждое взаимодействие цикла получало свою собственную копию элемента:
foreach (var item in Items) //loop through 40 items
{
var localItem = item;
//do some operation then set the current item
Application.Current.Dispatcher.Invoke(new Action(() => CurrentItem = localItem ));
}
Посмотрите любой или все из них для получения дополнительной информации или выполните поиск Google для "Доступ к измененному закрытию"
http://devnet.jetbrains.net/thread/273042