从字符串到文本框的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));
        }
    }
}
我对

进行了调试,以验证它是否经过这个代码路径,结果确实如此。但还是没有运气。还有其他想法吗?

从字符串到文本框的XAML绑定不起作用

下面是你需要做的修改

下面是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));
        }
    }
}