2011-11-18 64 views
0

我是一個C#新手,他在理解爲什麼他第一次嘗試理解XAML綁定時無法正常工作。我正在關注微軟的Data Binding OverviewXAML從一個字符串綁定到TextBox不起作用

我有一個單獨的文本框,最終將作爲一個狀態窗口。現在我只想寫入任意文本字符串。我也有一個我正在測試的命令模式的實例。我的命令包括向累加器添加一個隨機數並將結果打印到狀態視圖。

這裏是我的XAML應用程序主窗口:

<Window x:Class="Experiment.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:c="clr-namespace:Experiment" 
     Title="Test" Height="500" Width="700" Name="Test" Closing="Test_Closing" DataContext="{Binding ElementName=statusText}" xmlns:my="clr-namespace:Experiment"> 
    <Window.Resources> 
     <c:StatusViewText x:Key="statusViewText" /> 
    </Window.Resources> 
    <DockPanel HorizontalAlignment="Stretch" Margin="0,0,0,0" Width="Auto"> 
     <!-- Elements deleted for brevity. --> 
     <TextBox Margin="5,5,5,5" Name="statusText" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" AcceptsReturn="True" AcceptsTab="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" FontFamily="Courier New" FontSize="12" 
       Text="{Binding Source={StaticResource statusViewText}, Path=statusTextString, Mode=OneWay}"/> 
    </DockPanel> 
</Window> 

和類代表我的數據:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Experiment { 
    public class StatusViewText { 
     public StringBuilder statusText { get; set; } 
     public String statusTextString { get; set; } 

     public StatusViewText() { 
      statusText = new StringBuilder(); 
     } 

     public void Append(string s) { 
      if (s != null) { 
       statusText.Append(s); 
      } 

      statusTextString = statusText.ToString(); 
     } 

     public void AppendLine(string s) { 
      if (s != null) { 
       statusText.AppendLine(s); 
      } 

      statusTextString = statusText.ToString(); 
     } 
    } 
} 

最終,我會在這裏用一個適當的轉換器從StringBuilder的,但我想在探索這種複雜性之前先解決這個問題。

如果我的理解是正確的(顯然它不是),這一切應該工作。綁定目標是TextBox,目標屬性是Text屬性。綁定源是StatusViewText類的statusTextString屬性。然而,當我運行該命令(並調試並查看正在更新的StatusViewText.statusTextString)時,TextBox不會更新。

我認爲我可能需要顯式地添加綁定自己,所以我試圖在主窗口構造InitializeComponent()後添加此:

 statusViewText = new StatusViewText(); 
     Binding statusViewTextBinding = new Binding("statusTextString"); 
     statusViewTextBinding.Source = statusViewText; 
     statusText.SetBinding(TextBlock.TextProperty, statusViewTextBinding); 

但也不能工作。

我是否需要觸發PropertyChanged事件?我認爲綁定框架的全部要點是事件在幕後自動啓動和消耗;但也許我錯了。

沒有明顯的錯誤出現在輸出窗口中,這導致我相信我的綁定語法是正確的;我只是想念別的東西。

Halp!

EDIT 13:14 EDT感謝mben

好吧,我這樣做。添加以下內容:

public class StatusViewText : INotifyPropertyChanged { 
    public void Append(string s) { 
     if (s != null) { 
      statusText.Append(s); 
     } 

     statusTextString = statusText.ToString(); 
     NotifyPropertyChanged("statusTextString"); 
    } 

    public void AppendLine(string s) { 
     if (s != null) { 
      statusText.AppendLine(s); 
     } 

     statusTextString = statusText.ToString(); 
     NotifyPropertyChanged("statusTextString"); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void NotifyPropertyChanged(String info) { 
     if (PropertyChanged != null) { 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
     } 
    } 
} 

我調試,以驗證它是通過此代碼路徑,它是。但仍然沒有運氣。任何其他想法?

+0

嘗試使用DynamicResource代替StaticResource –

+0

@PankajUpadhyay:不編譯。這裏不是「資源」這個有效的指針嗎?我的意思是,我總是希望這個TextBox指向相同的屬性。這永遠不會改變,所以我應該可以在編譯時設置它。 – Tenner

+0

將TextBlock更改爲綁定中的TextBox,並從XAML中刪除所有綁定 – MBen

回答

2

您仍然需要在StatusViewText上實現INotifyPropertyChanged。 綁定系統不會持續檢查值,您需要在事情發生變化時通知它。

+0

謝謝...請參閱原始帖子中添加的編輯。 – Tenner

+1

這是工作:statusText.SetBinding(TextBox.TextProperty,statusViewTextBinding); (TextBox代替TextBlock),並且我從XAML中刪除了所有的綁定(如果你想讓我發佈它,我的代碼就可以工作了。 – MBen

+0

完美...它是TextBox與TextBlock。非常感謝你的幫助! – Tenner

1

請注意,您在代碼中創建的實例與您的Xaml中的實例不同。您可以通過在StatusViewText的構造函數中設置斷點來證明這一點。

將這個片段放到MainWindow的構造函數中...

 StatusViewText o = (StatusViewText)FindResource("statusViewText") as StatusViewText; 
     if(o!=null) 
     { 
      o.Append("hello"); 
     } 

這會影響你班級的正確實例。

你也應該改變你的類是這個樣子......

public class StatusViewText:INotifyPropertyChanged 
{ 
    public StringBuilder statusText { get; set; } 
    private string _statusTextString; 
    public String statusTextString 
    { 
     get { return _statusTextString; } 
     set 
     { 
      _statusTextString = value; 
      OnPropertyChanged("statusTextString"); 
     } 
    } 
    public StatusViewText() 
    { 
     statusText = new StringBuilder(); 
    } 
    public void Append(string s) 
    { 
     if (s != null) 
     { 
      statusText.Append(s); 
     } 
     statusTextString = statusText.ToString(); 
    } 
    public void AppendLine(string s) 
    { 
     if (s != null) 
     { 
      statusText.AppendLine(s); 
     } 
     statusTextString = statusText.ToString(); 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string prop) 
    { 
     if(PropertyChanged!=null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(prop)); 
     } 
    } 
} 
3

這裏是你必須適用於有工作的變化。

這裏是你的視圖模型的代碼:

public class StatusViewText : INotifyPropertyChanged 
{ 
    public StatusViewText() 
    { 
     // At least, I have a default value 
     this.StatusTextString = "Hello world"; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    private string statusTextString; 
    public string StatusTextString 
    { 
     get { return this.statusTextString; } 
     set 
     { 
      this.statusTextString = value; 
      this.OnPropertyChanged("StatusTextString"); 
     } 
    } 
} 

你必須指定窗口的DataContext的。後面的代碼是一個解決方案:在主窗口的構造函數,填充數據方面:

this.DataContext = new StatusViewText(); 

在XAML,你應該說在財產StatusTextString你的綁定。它的工作原理是數據上下文是StatusViewText的一個實例。

Text="{Binding Path=StatusTextString}"