استخدام مؤشر ترابط واجهة المستخدم WPF يجب أن يضمن دائمًا وضع شقة STA ، أليس كذلك؟
-
24-09-2019 - |
سؤال
في تطبيق WPF الخاص بي ، أتواصل بشكل غير متزامن مع خادم. لن يتم تشغيل رد الاتصال في مؤشر ترابط واجهة المستخدم ، ولأنني بحاجة إلى القيام ببعض الأشياء WPF هناك (إنشاء كائن Inkpresenter) أحتاج إلى تشغيله على مؤشر ترابط واجهة المستخدم. حسنًا ، في الواقع ، يكون الشرط هو تشغيل مؤشر ترابط مع وضع شقة STA. حاولت إنشاء سلسلة رسائل جديدة مع وضع STA ، لكن النتيجة هي أن مؤشر ترابط واجهة المستخدم لا يمكنه الوصول إلى inkpresenter لأنه كان "مملوكًا لخيط مختلف".
ما أريد القيام به في رد الاتصال هو استخدام المرسل لاستدعاء وظيفتي التي تتطلب STA. هل هذا يبدو مثل النهج الصحيح؟ أفعل هذا الآن ، لكنه لا يزال يفشل. في وظيفة رد الاتصال ، أقوم بإعداد الوظيفة التالية ، والتي تحاول الآن التأكد من تشغيل الوظيفة المعالجة على مؤشر ترابط واجهة المستخدم.
private void UpdateAnnotationsForCurrentFrameCollection()
{
if (Dispatcher.CurrentDispatcher.CheckAccess())
{
DoSomethingIncludingInkPresenter();
}
else
{
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal,
new Action(DoSomethingIncludingInkPresenter));
}
}
private void DoSomethingIncludingInkPresenter()
{
var inkPresenter = XamlReader.Parse(_someXamlString) as InkPresenter;
// Do something with the inkPresenter..
}
كما ترى من العينة ، أستخدم CheckAccess () للتأكد من أنني استحوذت على الوظيفة فقط إذا لم يتم تشغيلها بالفعل على مؤشر ترابط واجهة المستخدم. عندما يستدعي رد الاتصال الخاص بي ، يكون CheckAccess () صحيحًا دائمًا ، ولكن Dispatcher.CurrentDispatcher.Thread.ApartmentState
هو MTA. لماذا ا؟ حاولت إزالة CheckAccess () والقيام دائمًا بالاستدعاء ، ولكن لا يزال شقة MTA ، وإنشاء فشل Inkpresenter.
هل يمكن لأي شخص أن يشرح لي ما أفعله خطأ هنا؟ هل لدي مرسل خاطئ أو شيء من هذا القبيل؟ هل هذا هو النهج الصحيح لضمان تشغيل شيء ما على موضوع واجهة المستخدم؟
المحلول
أعتقد أنك مربكة 2 متطلبات. تم وضع علامة على المواضيع الرئيسية و WPF لتمكين مكالمات COM (وقد تحدث داخل عناصر التحكم).
يبدو أن مشكلتك هي مشكلة "واجهة المستخدم ليست آمنة الخيط" ، ويجب حلها عن طريق إرسال الأجزاء التي تلمس واجهة المستخدم.
ولكن يجب ألا تتصل بـ CheckAccess على CurrentDispatche ولكن على هدفك:
someControl.Dispatcher.CheckAccess
نصائح أخرى
أعتقد أن المشكلة هي أنك تستخدم المرسل الخطأ. واحدة من الطريقة المجربة والحقيقية التي استخدمتها هي تمرير مرسل عنصر التحكم الذي ينفذ فيه الرمز.
private void SomeMethod(Dispatcher dispatcher)
{
DoOtherThingsThatCanDoMTA();
dispatcher.Invoke(new Action(()=>
{
DoSomethingThatRequiresSTA();
}));
}
إذا لم يكن من الممكن تمرير المرسل بطريقة ما ، فيمكنك فضحه في خاصية أو أي طرق أخرى. أتمنى أن يساعد ذلك.