2009-06-05 34 views
13

DependencyObjectを継承できないオブジェクトがある、またはNotifyPropertyChangedを使用しているため、かなりの数のコントロールにバインドしているため、プロパティが変更されたときに各コントロールに移動したいそれがコードに値ですので、私が代わりに行くのそれは、コードの1行か2行でにバインドされていることすべてを、「再バインド」するXAMLを指示する方法がなければならないと思っています:WPF強制的に再バインドする

label1.Content = myObject.DontNotifyThis; 
label2.Content = myObject.DontNotifyThisEither; 
label3.Content = myObject.DontEvenThinkOfNotifyingThis; 
label4.Content = myObject.NotSoFastPal; 

ように、等々...

これは単純化しすぎている例:

XAML:

<Window x:Class="StackOverflowTests.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" x:Name="window1" Height="300" Width="300" Loaded="window1_Loaded"> 
    <Grid x:Name="gridMain"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <Label Grid.Row="0" Content="{Binding Status}" ContentStringFormat="Today's weather: {0}" /> 
     <Label Grid.Row="2" Content="{Binding Temperature}" ContentStringFormat="Today's temperature: {0}" /> 
     <Label Grid.Row="1" Content="{Binding Humidity}" ContentStringFormat="Today's humidity: {0}" /> 
    </Grid> 
</Window> 

のC#:

using System.Windows; 

namespace StackOverflowTests 
{ 
    /// <summary> 
    /// Interaction logic for Window1.xaml 
    /// </summary> 
    public partial class Window1 : Window 
    { 
     Weather weather = new Weather("Cloudy", "60F", "25%"); 

     public Window1() 
     { 
      InitializeComponent(); 
      this.DataContext = weather; 
     } 

     private void window1_Loaded(object sender, RoutedEventArgs e) 
     { 
      weather.Status = "Sunny"; 
      weather.Temperature = "80F"; 
      weather.Humidity = "3%"; 
     }  
    } 

    class Weather 
    { 
     public string Status { get; set; } 
     public string Temperature { get; set; } 
     public string Humidity { get; set; } 

     public Weather(string status, string temperature, string humidity) 
     { 
      this.Status = status; 
      this.Temperature = temperature; 
      this.Humidity = humidity; 
     } 
    } 
} 

私はそれを行う方法を見つけたが、それがすべてでエレガントではありません、と生憎、私はちょうど天気の新しいインスタンスへのDataContextを設定することはできません、それ(それがnullに設定され、変更されるのはそのためです):

private void window1_Loaded(object sender, RoutedEventArgs e) 
{ 
    weather.Status = "Sunny"; 
    weather.Temperature = "80F"; 
    weather.Humidity = "3%"; 

    // bad way to do it 
    Weather w = (Weather)this.DataContext; 
    this.DataContext = null; 
    this.DataContext = w; 
} 

ありがとうございます!

+0

興味:ここ

はそれを示して単純な例だ理由あなたはINPCを実装できませんか? –

+0

私たちのアプリでUndo/Redoを使用しています。INotifyPropertyChangingはオブジェクトの以前の状態をシリアル化し、INotifyPropertyChangedはオブジェクトを新しいXmlSerializedファイルに保存することを可能にします。しかし、私が変更する必要があるこれらの特定のプロパティは、オブジェクトの保存状態(フォント、色、背景、境界線を変更しない)またはユーザーが保存したいものを変更しません。 NotifyPropertyChanging /これらのプロパティで変更された場合、システムはオブジェクトが変更されたと考えますが、ユーザーには変更されていません。 これは私がそれを使うことができない理由です。 – Carlo

+0

わかりましたが、それは私に欠陥のあるデザインのように思えます。あなたはINPCの一般的なプロパティ変更の通知として、そして元に戻す/やり直しを気にする状態の変化を追跡するもう1つのメカニズムを使う方が良いでしょう。しかし、あなたのデザインを変更するには遅すぎるかもしれないので、ポイントを取った。 –

答えて

20

バインディングを更新する要素にアクセスできる場合は、バインディングを明示的に更新できます。要素のバインディング式を取得し、UpdateTarget()を使用してUIを更新するか、UpdateSourceを使用してバッキングプロパティを更新します(TextBoxのように編集可能なものにバインドする場合)。

<StackPanel> 
    <TextBlock x:Name="uiTextBlock" Text="{Binding MyString}" /> 
    <Button Click="Button_Click" 
      Content="Rebind" /> 
</StackPanel> 

public partial class Window1 : Window 
{ 
    public string MyString { get; set; } 

    public Window1() 
    { 
     MyString = "New Value"; 

     InitializeComponent(); 
     this.DataContext = this; 
    } 
    int count = 0; 
    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     MyString = "Rebound " + ++count + " times"; 

     var bindingExpression = uiTextBlock.GetBindingExpression(TextBlock.TextProperty); 
     bindingExpression.UpdateTarget(); 
    } 
} 

(。。全く可能であればその方法は、あなたが背後にあるコードからロジックを抽出することができますけれども、私はINotifyPropertyChangedのを使用することをお勧めします)

+0

これは機能しますが、唯一の問題は更新する必要のあるすべてのコントロールに対して行う必要があることです。 – Carlo

+0

INotifyPropertyChangedを実装できない場合は、yesを指定します。必要なBindingExpressionsのコレクションを作成し、linq拡張子.ForEach(b => b.UpdateTarget())を使用できます。しかし、多くのことを更新しなければならない場合や、一度にいくつかのコントロールにしかアクセスできない場合、既に見つかったようにDataContextを '循環させる'方が簡単かもしれません。 – rmoore

+0

私はすべてのコントロールを更新することが可能だと思います。私がそのアプローチについて気に入らないのは、新しいコントロールを追加するとコードを追加してターゲットを更新する必要があるということだけです。しかし、それほど大きな問題ではありません。ありがとう! – Carlo

関連する問題