【问题标题】:Binding Simple WPF TextBox Text TwoWay双向绑定简单的 WPF 文本框文本
【发布时间】:2016-12-28 00:56:25
【问题描述】:

很抱歉,这个问题非常基础。我刚刚学习了 WPF,但未能将简单的两种方式绑定到 textbox.text 到字符串属性。

XAML 代码:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid x:Name="StuInfo">
    <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="10,26,0,0" TextWrapping="Wrap" Text="{Binding Path=str,Mode=TwoWay}" VerticalAlignment="Top" Width="120"/>
    <Button x:Name="button" Content="Check" HorizontalAlignment="Left" Margin="10,67,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
</Grid>

C#代码

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        str = "OK";
    }

    public string str { get; set; }

    private void button_Click(object sender, RoutedEventArgs e)
    {
        Console.WriteLine(str);
    }
}

首先,文本框没有显示“OK”,而是空白。然后,我在文本框中输入了不同的文本,例如:“blablabla”,不带引号。然后我单击按钮检查我的 str 属性是否已更新。显然,str 仍然包含“OK”。

我在这里做错了什么?使绑定工作我错过了什么?

【问题讨论】:

    标签: c# wpf xaml binding textbox


    【解决方案1】:

    问题是,你没有绑定到 Window 的代码隐藏,而是绑定到 DataContext。

    试试这个:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new DC();
        }
    
        public class DC
        {
            public string str { get; set; }
    
            public DC()
            {
                str = "OK";
            }
        }
    }
    

    通常,您会有两个不同的文件,但对于测试,您可以在一个文件中进行。 之后,您的 DC (DataContext) 应该实现 INotifyPropertyChanged 接口。

    试着找一些像http://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial这样的关于MVVM的文章

    【讨论】:

    • 或者您可以将您的 DataContext 设置为此,但这确实是个坏主意。你应该把你的 ViewModel 和你的 View 分开。
    • 所以,设置 DataContext 解决了这个问题。无论如何我可以让它工作而不必实例化一个对象,只需直接使用字符串属性?这个问题的答案是将 DataContext 设置为这个吗?
    • 可以绑定到窗口后面的代码,没有错:public MainWindow { InitializeComponent(); **DataContext = this;** }
    • 好的,它确实可以将 DataContext 设置为此。谢谢@Jakub Čermoch,@slugster!我还考虑将模型和视图分开。这只是对我理解概念和代码的测试。
    • 但这只是为了向您展示如何以最简单的方式进行操作。如果你打算在 WPF 中做更大的项目,使用 MVVM 几乎是必要的。试着找一些关于它的文章。好的是使用 Prism 使用 WPF 实现 MVVM
    【解决方案2】:

    作为 WPF 的新手,所有这些 Binding 和 DataContext 爵士乐可能会让人很困惑。让我们先从您的绑定表达式开始...

    &lt;TextBox Text="{Binding Path=str, Mode=TwoWay}"/&gt;

    这是说你想将你的 Text 属性绑定到 DataContextTextBox 是什么。 DataContext 本质上是您的 TextBox 从中获取数据的“东西”。现在问题来了。 DataContext 如果未明确设置,则从可视树中“上方”的元素继承。在您的代码中,TextBoxGrid 元素继承它的 DataContext,而后者又从 Window 元素继承它的 DataContext。看到DataContext 未在您的Window 中设置,将应用DataContext 属性的默认值,即nullDataContext 也未在窗口的任何子元素中设置,通过继承,该窗口的所有子元素的 DataContext 将设置为 null

    请务必注意,您在绑定表达式中遗漏了 Source 属性。

    &lt;TextBox Text="{Binding Source=left_out, Path=str, Mode=TwoWay}"/&gt;

    当这个属性被忽略时,绑定的源被暗示为元素DataContext,在这种情况下它为空,原因如上所述。基本上,你的表达在这里说的是你想将你的文本属性绑定到DataContext.str,而 WPF 解析的是null.str

    好的,很酷。现在,我们如何将TextBox.Text 绑定的DataContext 设置为窗口的代码隐藏,以便我们可以获取str 属性?有几种方法可以做到这一点,但出于我们的目的,我们将专注于在TextBox.Text 属性的绑定中显式设置它。现在,绑定有三种不同的“源”类型属性。 “源”是我们希望我们的控件/元素的绑定从中获取数据的地方。我们有SourceRelativeSourceElementName。我们在这里只关注ElementName,但其他的对于研究和理解是必不可少的。

    所以,让我们命名 Window 元素,以便我们可以通过 ElementName 属性访问它。

    <Window x:Class="WpfApplication1.MainWindow"
            x:Name="_window"
            ...
    

    现在我们可以在TextBox.Text绑定上设置ElementName属性来引用窗口。

    &lt;TextBox Text="{Binding ElementName=_window, Path=str, Mode=TwoWay}"/&gt;

    这意味着绑定将在尝试解析其绑定时查找_window.str 属性。此时,您可能仍然看不到TextBox 中反映的str 值。这是因为它的值是在窗口构造函数中的InitializeComponent 方法之后设置的。这个函数是第一次解决绑定的地方。如果您在调用InitializeComponent 之前设置str 的值,您会看到TextBox 中反映的值。

    这将我们带到依赖属性。现在,只需知道 Dependency Properties 内置了更改通知,您的绑定需要它,以便它“知道”绑定何时更改以及何时再次解析绑定值。是的,您可以在后面的代码中使用INotifyPropertyChanged,但是在这种情况下使用 DependencyProperties 有很好的论据,这只会在这一点上混淆问题。但是,这是必须理解的另一件事。

    这是您的str 属性的DependencyProperty 代码。

    public static readonly DependencyProperty StrProperty 
        = DependencyProperty.Register("Str", typeof(string), typeof(MainWindow), 
            new FrameworkPropertyMetadata(FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    public string Str
    {
        get{return (string)GetValue(StrProperty);}
        set{SetValue(StrProperty,value);}
    }
    

    现在您可以像这样设置值,并通过绑定到您的TextBox 来反映它。

    public MainWindow()
    {
        InitializeComponent();
        Str = "OK";
    }
    

    在这一点上,一切都应该很好。我希望这会有所帮助。我花了一段时间来掌握 WPF 的窍门。我的建议是尽可能多地阅读DataContextBindingDependencyProperty,因为它们是 WPF 的核心。祝你好运!

    【讨论】:

    • 感谢您花时间向我解释。那么这是否意味着如果我将“DataContext”设置为`Binding Source`以使其作为替代方案工作?在您的示例中,我可以设置 {Binding Source=_window ...} 并使其工作吗?
    • 不客气。感谢您提供帮助的机会!至于你的问题,答案是否定的。 ElementName 属性是唯一可以与Windowx:Name 属性一起使用的属性。 Source用于静态和动态资源,高级一点。
    • Source 视为显式解析绑定对象或“源”的三种方法之一可能会有所帮助。我知道这很令人困惑。您可以使用SourceRelativeSourceElementName,它们都是互斥的。您也可以不使用这些,并将“源”区域留空,解析为DataContext。注意Source 和“来源”之间的区别。 Source 是绑定的实际属性,“Source”是用于引用绑定的底层源对象的语义。
    猜你喜欢
    • 2010-12-16
    • 2018-06-12
    • 2012-11-23
    • 2019-03-04
    • 2012-11-24
    • 2011-03-29
    • 1970-01-01
    • 2018-10-17
    • 2015-10-16
    相关资源
    最近更新 更多