ورود

View Full Version : مشکل در استفاده از یک شی در thread ای که در آن ساخته نشده



ronix3
یک شنبه 04 مهر 1395, 19:13 عصر
سلام من با wpf کار می کنم شاید بگین خیلی پیش پا افتادس ولی هم تو سایت های داخلی و هم خارجی گشتم اون چیزی که کارمو راه بندازه پیدا نکردم
می خوام در نخ جدیدی که می سازم از شی مثل تکست باکس که در یک نخ دیگر ساخته شده استفاده کنم اگه یک یا ۲ شی باشه مشکلی ندارم و با کد زیر کار می کنم

new Thread(() =>
{
Dispatcher.Invoke(() =>
{
for (int i = 0; i < 1000000; i++)
{
textBox1.Text = i.ToString();
}
});
}).Start();


کد بالا مشکلی نداره و با اولین بار شروع نخ بدون هنگ کردن برنامه کار می کنه
ولی کد زیر در اولین بار شروع نخ بعد از اجرای برنامه هنگ می کنه تا انتهای پروسس و در دفعات بعد مشکلی نداره

new Thread(() =>
{
Dispatcher.Invoke(() =>
{
for (int i = 0; i < 1000000; i++)
{
textBox1.Text = i.ToString();
textBox2.Text = (2 * i).ToString();
}
});
}).Start();


حالا اگه به صورت زیر بنویسم مشکل حل می شه

new Thread(() =>
{
for (int i = 0; i < 1000000; i++)
{
Dispatcher.Invoke(() =>
{
textBox1.Text = i.ToString();
});
Dispatcher.Invoke(() =>
{
textBox2.Text = (2 * i).ToString();
});
}
}).Start();

مشکل من اینه که تعداد اشیاء زیاد هست و نمی شه این کارو برای هر شی کرد کد خیلی شلوغ و گیج کننده می شه
از کد زیر هم استفاده کردم و مشکل بالا رو داشتم
ممنون می شم راهنماییم کنید
void test()
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.Invoke(test);
}
else
{
for (int i = 0; i < 100000000; i++)
{
textBox1.Text = i.ToString();
textBox2.Text = (2 * i).ToString();
}
}
}

Mahmoud.Afrad
دوشنبه 05 مهر 1395, 01:41 صبح
زمانی از thread مجزا استفاده میشه که عملیات زمانبری نیاز به انجام باشه اما کد شما فاقد عمل زمانبر هست. در اینصورت نخی که شما ایجاد کردید بدون وقفه زمانی، درخواست تغییر در UI را به نخ اصلی میده، و نخ اصلی هم به صورت پی در پی سعی در بروزرسانی کنترل ها میکنه، اما به دلیل اینکه این درخواست ها با فاصله زمانی بسیار کم به نخ اصلی میرسد، نمی توان نتیجه تغییر قبلی را مشاهده کرد و به اصطلاح UI فریز میشه. در اینصورت میتوان به صورت مصنوعی وقفه زمانی را توسط متد Sleep ایجاد کرد.
Thread t = new Thread(delegate()
{
for (int i = 0; i < 1000000; i++)
{
Thread.Sleep(1);

if (Application.Current == null) continue;
Dispatcher.Invoke(delegate
{
textBox1.Text = i.ToString();
textBox2.Text = (2*i).ToString();
});
}
});

t.IsBackground = true;
t.Start();
اما به جای Thread.Sleep(1); می توان کدهای زمانبر دیگری را قرار داد که بسته به برنامه شماست.

ronix3
چهارشنبه 28 مهر 1395, 18:37 عصر
به خاطر گذاشتن وقفه پنجره فریز می شه وقفه تو یه نخ دیگس چه ربطی به پنجره داره؟
loading = new Thread(delegate ()
{
if (Application.Current == null) return;
Task.Factory.StartNew(() =>
{
Dispatcher.Invoke(new Action(delegate ()
{

animatedImage.StartAnimate();
stack.Visibility = Visibility.Visible;
group.IsEnabled = false;
name.IsEnabled = false;
family.IsEnabled = false;

Dbs db = new Dbs();

loadgroup(db.Group.ToList());
loadnameandfamily(db.Persen.ToList());


Thread.Sleep(3000);


group.IsEnabled = true;
name.IsEnabled = true;
family.IsEnabled = true;
animatedImage.StopAnimate();
stack.Visibility = Visibility.Collapsed;
starttime = false;
}));
});
});
loading.Start();

Mahmoud.Afrad
چهارشنبه 28 مهر 1395, 20:04 عصر
کدهایی که با Dispatcher.Invoke اجرا میکنید در ترد اصلی اجرا میشن. این کدی که نوشتید با خالتی که بدون ترد بنویسید فرقی نداره.
لود داده ها رو قبل از Invoke انجام بدید.

ronix3
چهارشنبه 28 مهر 1395, 21:13 عصر
نمی شه باید داده ها به کنترل داده بشه و کنترل تو نخ اصلی ساخته شده
یعنی واسه استفاده از انتیتی استفاده از نخ تآثیری نداره؟؟

Mahmoud.Afrad
پنج شنبه 29 مهر 1395, 18:50 عصر
برای دریافت اطلاعات میتونید از ترد مجزا استفاده کنید اما برای اینکه این داده های بدست آمده رو به کنترل ها منتقل کنید بایست از طریق ترد اصلی اقدام کنید که با Invoke این کار رو بایست انجام بدید.
loading = new Thread(delegate()
{
Task.Factory.StartNew(() =>
{
Dispatcher.Invoke(new Action(delegate
{
animatedImage.StartAnimate();
stack.Visibility = Visibility.Visible;
group.IsEnabled = false;
name.IsEnabled = false;
family.IsEnabled = false;
}));

Dbs db = new Dbs();
var groups = db.Group.ToList();
var persons = db.Persen.ToList();

Dispatcher.Invoke(new Action(delegate
{
loadgroup(groups);
loadnameandfamily(persons);
group.IsEnabled = true;
name.IsEnabled = true;
family.IsEnabled = true;
animatedImage.StopAnimate();
stack.Visibility = Visibility.Collapsed;
starttime = false;
}));
});
});
loading.Start();

توجه داشته باشید که هر چه داده ها زیادتر باشند، متدهای loadgroup و loadnameandfamily زمان بیشتری رو به خود اختصاص میدن. البته شاید بتونید با حلقه و ایجاد وقفه کمی این کار رو روانتر کنید که باید این متدها هم کدشون رو قرار بدید.