編集
解決策が機能しているため、最初はなぜこれが機能しているのかという最初の疑問から完全に脱却することがありました。結局、項目はビジュアル ツリーの一部ではありません。結局、それは完全に理にかなっています:
- そのコレクションのボタンはビジュアル ツリーにないため、要素バインディングは機能しません。
- テンプレートを適用すると、テンプレートがビジュアル ツリーに配置され、バインドがこの時点で適用されている場合は、作業が開始されます。
- これにより、疑わしい競合状態が確認されます。
私の同僚は、問題を示す拡張デバッグをいくつか行いました。バインディングが成功した場合、OnApplyBinding が最初に呼び出されました。したがって、論理ツリーを調整せずにコレクションを使用することは、単に欠陥がありました。
正しい道に戻った返信をありがとう!
元の投稿
ObservableCollection を公開するビュー コントロールがあります。ビューには、ボタンなどの任意の要素を含めることができます。ボタンのElementNameバインディングに注意してください。
<local:ViperView>
<local:ViperView.MenuItems>
<Button Content="{Binding ElementName=btn, Path=Content}" />
</local:ViperView.MenuItems>
<Grid>
<Button x:Name="btn" Content="HELLO WORLD" />
</Grid>
</local:ViperView>
コントロールの ControlTemplate は、ItemsControl を使用してコンテンツをレンダリングするだけです。
<ControlTemplate ...
...
<ItemsControl
x:Name="PART_NavigationMenuItemsHost"
ItemsSource="{Binding MenuItems, RelativeSource={RelativeSource TemplatedParent}}" />
</ControlTemplate>
上記のビューは、メイン ビュー モデルの ActiveView プロパティに割り当てられています。メイン ウィンドウは、データ バインディングを介してビューを表示するだけです。
ここでの問題:ビューが作成後にすぐにビュー モデルに割り当てられない場合、そのビュー内の ElementName バインディングは確実に機能しません。
ElementName バインディングは次のように機能します。
MainViewModel.ActiveView = new ViperView();
ElementName バインディングは、通常の優先度を使用して動作することがあります。
var view = new ViperView();
Dispatcher.BeginInvoke(() => MainViewModel.ActiveView view);
ビュー モデル プロパティが低い優先度に設定されている場合、ElementName バインディングは常に失敗します。
var view = new ViperView();
Dispatcher.BeginInvoke(DispatcherPriority.Render, () => MainViewModel.ActiveView = view);
ElementName バインディングは、プロパティがワーカー スレッドから設定されている場合に機能することがあります (バインディング エンジンは UI スレッドにマーシャリングします)。
var view = new ViperView();
Task.Factory.StartNew(() => MainViewModel.ActiveView = view);
ワーカー スレッドに遅延がある場合、ElementName バインディングは常に失敗します。
var view = new ViperView();
var view = new ViperView();
Task.Factory.StartNew(() =>
{
Thread.Sleep(100);
MainViewModel.ActiveView = view;
});
これに対する答えはありません。タイミングが関係しているようです。たとえば、上記の Task サンプルに短い Thread.Sleep を追加すると、常にバインドが壊れますが、スリープがないと、時々壊れるだけです。
これは私にとってかなりのショーストッパーです-どんなポインタでも大歓迎です...
アドバイスありがとうフィリップ