从字符串到文本框的XAML绑定不起作用
本文关键字:XAML 绑定 不起作用 字符串 文本 | 更新日期: 2023-09-27 18:15:03
我是一个c#新手,在理解为什么他第一次尝试理解XAML绑定不工作时遇到了问题。我遵循微软的数据绑定概述。
我有一个单一的文本框,这将最终作为一个状态窗口。现在我只想在里面写入任意的文本字符串。我还有一个正在测试的命令模式实例。我的命令包括向累加器中添加一个随机数,并将结果打印到状态视图中。
下面是我的主应用程序窗口的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被更新),文本框不更新。
我想我可能需要自己显式地添加绑定,所以我试着在主窗口构造函数的InitializeComponent()
之后添加这个:
statusViewText = new StatusViewText();
Binding statusViewTextBinding = new Binding("statusTextString");
statusViewTextBinding.Source = statusViewText;
statusText.SetBinding(TextBlock.TextProperty, statusViewTextBinding);
但这也不起作用。
我需要触发PropertyChanged事件吗?我认为绑定框架的全部意义在于事件是在幕后自动触发和消耗的;但也许我也错了。
没有明显的错误出现在输出窗口,这使我相信我的绑定语法是正确的;我只是缺了点别的。
想买!
编辑13:14美国谢谢 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));
}
}
}
我对进行了调试,以验证它是否经过这个代码路径,结果确实如此。但还是没有运气。还有其他想法吗?
下面是你需要做的修改
下面是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的元素中,填充数据上下文:
this.DataContext = new StatusViewText();
在XAML中,你应该说你对属性StatusTextString的绑定。它工作是因为数据上下文是StatusViewText的一个实例。
Text="{Binding Path=StatusTextString}"
你仍然需要在StatusViewText上实现INotifyPropertyChanged。绑定系统不会持续检查这些值,当情况发生变化时,您需要通知它。
请注意,您在代码中创建的实例与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));
}
}
}