ラベルを更新するたびに、このエラーが発生しました:別のスレッドが所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません。起動しようとしましたが、失敗しました。 WPFフォームを使用しています。
delegate void lostfocs(string st);
private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Thread t = new Thread(modi);
t.Start();
}
void modi()
{
try
{
label1.Content = "df";
}
catch
{
lostfocs ld = new lostfocs(up);
// ld.Invoke("df");
object obj=new object();
ld.Invoke("sdaf");
}
}
void up(string st)
{
label1.Content = st;
}
Dispatcher.Invoke メソッドを使用します。
Dispatcherが関連付けられているスレッドで、指定されたデリゲートを同期的に実行します。
また
WPFでは、DispatcherObjectを作成したスレッドのみがそのオブジェクトにアクセスできます。たとえば、メインUIスレッドからスピンオフされたバックグラウンドスレッドは、UIスレッドで作成されたボタンのコンテンツを更新できません。バックグラウンドスレッドがButtonのContentプロパティにアクセスするには、バックグラウンドスレッドがUIスレッドに関連付けられたDispatcherに作業を委任する必要があります。これは、InvokeまたはBeginInvokeのいずれかを使用して実現されます。呼び出しは同期で、BeginInvokeは非同期です。操作は、指定されたDispatcherPriorityでDispatcherのイベントキューに追加されます。
ラベルがUIスレッドで作成され、別のスレッドを介してそのコンテンツを変更しようとしているため、エラーが発生しています。これは、Dispatcher.Invokeを必要とする場所です。
この記事をご覧ください WPFスレッドはディスパッチャーを使用して応答性の高いアプリを構築します
これにはDispatcherを使用できます。あなたのコードは...
private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() =>
{
try
{
label1.Content = "df";
}
catch
{
lostfocs ld = new lostfocs(up);
// ld.Invoke("df");
object obj=new object();
ld.Invoke("sdaf");
}
}
));
例
void modi()
{
if(!Dispatcher.CheckAccess())
{
Dispatcher.Invoke(
()=>label1.Content = "df",DispatcherPriority.Normal);
}
else
{
label1.Content = "df";
}
}
1つの非UIスレッドを開始し、このスレッド内で1つのUIスレッドも開始しました。したがって、私の要件は、非UIスレッド内でUIスレッドを実行するようなものです。このシナリオを処理すると、次の例外が発生しました。 "例外:別のスレッドが所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません。"
この場合、UI要素のDispatcher.Invokeメソッドを次のように使用し、うまく機能しました。
if (m_contextWindow == null)
{
System.Threading.Thread newWindowThread = new System.Threading.Thread(new ThreadStart( () =>
{
// Create and show the Window
m_contextWindow = new ContextWindow();
m_contextWindow.DataContext = this;
m_contextWindow.Show();
// Start the Dispatcher Processing
System.Windows.Threading.Dispatcher.Run();
}));
// Set the apartment state
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();
}
else
{
this.m_contextWindow.Dispatcher.Invoke(new ThreadStart(() =>
{
m_contextWindow.DataContext = this;
if (m_contextWindow.Visibility == System.Windows.Visibility.Collapsed
|| m_contextWindow.Visibility == System.Windows.Visibility.Hidden)
m_contextWindow.Visibility = System.Windows.Visibility.Visible;
}));
}
BeginInvokeを使用するためのいくつかの提案がありますが、EndInvokeについては言及されていません。良い習慣は、「すべてのBeginInvokeに一致するEndInvokeがある」ことであり、確かに競合状態に対する何らかの保護手段が必要です(考えてみてください:コードの複数のBeginInvokeで何が起こるか、まだ処理が完了していないものはありますか?)
忘れがちであり、MSDNの例とWinFormsで出版された本の両方で、このエラーを見ました(そして、はい、それはisエラーです)
private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() =>
{
try
{
label1.Content = "df";
}
catch
{
lostfocs ld = new lostfocs(up);
object obj = new object();
ld.Invoke("sdaf");
}
}));
}