2011-11-18 32 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}" 
相关问题