2009-03-19 17 views
9

DataContextを変更した直後にオブジェクトを測定しようとしていますが、オブジェクトのバインディングがすぐに更新されません。ここに私のコードは次のとおりです。DataContextが変更されたときすぐにバインドを更新する

// In MeasureOverride(Size) 
m_inputWidth = 0.0; 

Size elemSize = new Size(double.PositiveInfinity, RowHeight); 
MapElementView ruler = new MapElementView(); 

// Measure inputs 
foreach (MapElementViewModel elem in m_vm.InputElements) 
{ 
    ruler.DataContext = elem; 
    ruler.Measure(elemSize); 
    m_inputWidth = Math.Max(m_inputWidth, ruler.DesiredSize.Width); 
} 

私はビュービューモデルを表示するようにする必要がありますどのように大規模な測定ができるように私が更新にViewオブジェクトのバインディングをしたいです。私はデータを仮想化しているため、同じViewを再利用して測定します。

DataContextが変更されたときにバインディングを強制的に更新する方法を知っている人はいますか?

最終的にバインディングが更新されることに注意してください。

Viewには、ViewModelに基づいてサイズを変更する主な要素であるTextBlockが含まれています。 DataContextを変更した直後に、この要素のTextPropertyのBindingExpressionを調べましたが、UpdateTarget()を呼び出すと問題が解決されず、BindingExpression.DataItemがnullと表示されます。

EDIT: BindingExressionのステータスはUnattachedです。そのトリックは、どのようにそれをつけるかを理解することです。

答えて

5

DataContextを設定した後で、DataBind優先度でディスパッチャのInvokeを実行した場合、すべてが更新されるはずです。

このコードはMeasureOverrideメソッド内で実行されているため、ディスパッチャでInvokeを実行することはできません。代わりに、私は、ルーラの幅が測定されたかどうかを示すフラグを作成し、そうでない場合は、それらの幅を計算するメソッドでBeginInvokeを実行します。次に、幅が計算されると、InvalidateMeasureを呼び出して2番目のレイアウトパスを強制します。

これは、これらの幅のいずれかが変更されるたびに、追加のレイアウトのパスが必要になります。テキストボックスを再測定する必要があるときは、フラグをfalseにリセットする必要があります。

private bool isRulerWidthValid = false; 

protected override Size MeasureOverride(Size available) 
{ 
    ... // other code for measuring 
    if (!isRulerWidthValid) 
    { 
     Dispatcher.BeginInvoke(new Action(CalculateRulerSize)); 
     ... // return some temporary value here 
    } 

    ... // do your normal measure logic 
} 

private void CalculateRulerSize(Size available) 
{ 
    Size elemSize = new Size(double.PositiveInfinity, RowHeight); 
    m_inputWidth = 0.0; 

    foreach (MapElementViewModel elem in m_vm.InputElements) 
    { 
     ruler.DataContext = elem; 
     ruler.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.DataBind); 
     ruler.Measure(elemSize); 
     m_inputWidth = Math.Max(m_inputWidth, ruler.DesiredSize.Width); 
    } 

    // invalidate measure again, as we now have a value for m_inputwidth 
    isRulerWidthValid = true; 
    InvalidateMeasure(); 
} 
+0

いい考えです。私はそれを試みます。 –

+0

次の例外があります。ディスパッチャの処理が中断されている間はこの操作を実行できません。 レイアウト中にWPFがDispatcherをロックするようです。 MeasureOverride()でこのコードを実行しています –

関連する問題