我是一个C#新手,他在理解为什么他第一次尝试理解XAML绑定无效时遇到了问题。我正在关注微软的Data Binding Overview。
我有一个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,target属性是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!
编辑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 :(得分:3)
以下是您必须应用的更改才能让它正常工作。
以下是ViewModel的代码:
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。代码隐藏是一个解决方案:在MainWindow的ctor中,填写数据上下文:
this.DataContext = new StatusViewText();
在XAML中,您应该说明对属性StatusTextString的绑定。它的工作原理是因为数据上下文是StatusViewText的一个实例。
Text="{Binding Path=StatusTextString}"
答案 1 :(得分:2)
您仍需要在StatusViewText上实现INotifyPropertyChanged。 绑定系统不会持续检查值,您需要在事情发生变化时通知它。
答案 2 :(得分: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));
}
}
}