C# WPF Xaml 绑定不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18060268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:11:21  来源:igfitidea点击:

WPF Xaml Binding not working

c#wpfbinding

提问by oimitro

Ok i have a WPF project in which i have 4 TexBlock. What i want is to change the Textof each TextBlockvia Binding.

好的,我有一个 WPF 项目,其中有 4 个TexBlock. 我想要的是改变Text每个TextBlockvia Binding

So far i have my XAML :

到目前为止,我有我的 XAML:

    <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock x:Name="First" Text="{Binding FirstString}" Grid.Row="0"/>
    <TextBlock x:Name="Second" Text="{Binding SecondString}" Grid.Row="1"/>
    <TextBlock x:Name="Third" Text="{Binding ThirdString}" Grid.Row="2"/>
    <TextBlock x:Name="Fourth" Text="{Binding FourthString}" Grid.Row="3"/>
</Grid>

And in my code i have :

在我的代码中,我有:

public partial class MainWindow : Window
{
    public string FirstString { get; set; }
    public string SecondString { get; set; }
    public string ThirdString { get; set; }
    public string FourthString { get; set; }

    public MainWindow()
    {
        InitializeComponent();    

        FirstString = "First";
        SecondString = "Second";
        ThirdString= "Third
        FourthString= "Fourth";
    }
}

But the Bindingdoesnt work at all. Am i doing something to wrong? Please help. Thanks in advance.

Binding根本不起作用。我做错了什么吗?请帮忙。提前致谢。

EDIT:

After following Chris Mantle suggestion looking at the debbuger (I had is set to Warning sor the Binding) i get the following error:

按照 Chris Mantle 建议查看调试器(我已设置为警告或绑定)后,我收到以下错误:

System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=FirstString; DataItem=null; target element is 'TextBlock' (Name='First'); target property is 'Text' (type 'String')

采纳答案by Simon Belanger

There are a few things that are incorrect. The Bindingmarkup will look at the object in the DataContextproperty of the control. This property inherits the DataContextfrom the declaring parent unless otherwise specified. Out of the box, this is nullfor a Windowcontrol.

有几件事是不正确的。该Binding标记将着眼于对象的DataContext控制的财产。DataContext除非另有说明,否则此属性从声明的父级继承。开箱即用,这是null一个Window控件。

There are two options for this problem. You can either set the DataContextexplicitely in the code-behind or the XAML

这个问题有两种选择。您可以DataContext在代码隐藏或 XAML 中显式设置

// In XAML
<Window DataContext={Binding RelativeSource={RelativeSource Self}}>

or

// In the code-behind
DataContext = this;

Another problem is that the binding is applied at initialization. Initially, your properties are empty. After the InitializeComponentphase, the controls will "bind" to the properties (which are empty). When you set your properties afterward, the controls have no way to know it has changed. There are two mechanism to allow this. On the control level, you can make these properties as DependencyPropertyor implement the INotifyPropertyChangedinterface and raise the changes. If you want to go the INPC route, you can implement your properties and Window as such:

另一个问题是绑定是在初始化时应用的。最初,您的属性是空的。在InitializeComponent阶段之后,控件将“绑定”到属性(为空)。之后设置属性时,控件无法知道它已更改。有两种机制可以实现这一点。在控件级别,您可以将这些属性作为DependencyProperty或实现INotifyPropertyChanged接口并引发更改。如果你想走 INPC 路线,你可以这样实现你的属性和窗口:

public partial class MainWindow : INotifyPropertyChanged
{
    private string firstString;
    private string secondString;
    private string thirdString;
    private string fourthString;

    public string FirstString
    {
        get { return firstString; }
        set
        {
            firstString = value;
            RaisePropertyChanged("FirstString");
        }
    }

    public string SecondString
    {
        get { return secondString; }
        set
        {
            secondString = value;
            RaisePropertyChanged("SecondString");
        }
    }

    public string ThirdString
    {
        get { return thirdString; }
        set
        {
            thirdString = value;
            RaisePropertyChanged("ThirdString");
        }
    }

    public string FourthString
    {
        get { return fourthString; }
        set
        {
            fourthString = value;
            RaisePropertyChanged("FourthString");
        }
    }

    public MainWindow()
    {
        DataContext = this;
        InitializeComponent();

        FirstString = "First";
        SecondString = "Second";
        ThirdString = "Third";
        FourthString = "Fourth";
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    private void RaisePropertyChanged(string propertyName)
    {
        var handlers = PropertyChanged;

        handlers(this, new PropertyChangedEventArgs(propertyName));
    }
}

回答by Thomas Levesque

Unless specified otherwise, the path of the binding is relative to the DataContextof the element. In your case, I suspect you didn't specify a DataContextat all...

除非另有说明,绑定的路径是相对于DataContext元素的。在您的情况下,我怀疑您根本没有指定DataContext...

Since the properties are declared in the MainWindowclass itself, the easiest fix is to add:

由于属性是在MainWindow类本身中声明的,最简单的解决方法是添加:

DataContext = this;

at the end of the constructor.

在构造函数的末尾。

回答by Nicolas Voron

Since your aren't notifying that FirstString, SecondString, ThirdStringand FourthStringchanged, the change will not be reflected in the UI. You can either implement INotifyPropertyChanged, or deal with DependencyProperty

由于您没有通知FirstStringSecondStringThirdStringFourthString改变,这种变化不会反映在UI中。您可以实施INotifyPropertyChanged或处理DependencyProperty

Set your Datacontext, too.

也设置你的Datacontext

IMHO DependencyPropertyis better for this use. Here is an example :

恕我直言DependencyProperty,更适合这种用途。这是一个例子:

public partial class MainWindow : Window
{
    #region Public
    public string FirstString
    {
        get { return (string)GetValue(FirstStringProperty); }
        set { SetValue(FirstStringProperty, value); }
    }
    public string SecondString
    {
        get { return (string)GetValue(SecondStringProperty); }
        set { SetValue(SecondStringProperty, value); }
    }
    public string ThirdString
    {
        get { return (string)GetValue(ThirdStringProperty); }
        set { SetValue(ThirdStringProperty, value); }
    }
    public string FourthString
    {
        get { return (string)GetValue(FourthStringProperty); }
        set { SetValue(FourthStringProperty, value); }
    }

    #region Dependency Properties
    public static readonly DependencyProperty FirstStringProperty = DependencyProperty.Register("FirstString", typeof(string), typeof(MainWindow), new PropertyMetadata("default value"));
    public static readonly DependencyProperty SecondStringProperty = DependencyProperty.Register("SecondString", typeof(string), typeof(MainWindow), new PropertyMetadata("default value"));
    public static readonly DependencyProperty ThirdStringProperty = DependencyProperty.Register("ThirdString", typeof(string), typeof(MainWindow), new PropertyMetadata("default value"));        
    public static readonly DependencyProperty FourthStringProperty = DependencyProperty.Register("FourthString", typeof(string), typeof(MainWindow), new PropertyMetadata("default value"));
    #endregion
    #endregion

    public MainWindow()
    {
        InitializeComponent();    

        FirstString = "First";
        SecondString = "Second";
        ThirdString= "Third";
        FourthString= "Fourth";

        this.DataContext = this;
    }
}

回答by Zenchovey

I would suggest that you create another class MainWindowViewModel.

我建议您创建另一个类 MainWindowViewModel。

public class MainWindowViewModel
{
    public string FirstString { get; set; }
    public string SecondString { get; set; }
    public string ThirdString { get; set; }
    public string FourthString { get; set; }

    public MainWindowViewModel()
    {    
        FirstString = "First";
        SecondString = "Second";
        ThirdString= "Third";
        FourthString= "Fourth";
    }
}

Then set the DataContext of the MainWindow object before calling show on the window class.

然后在窗口类上调用 show 之前设置 MainWindow 对象的 DataContext。

MainWindow wnd = new MainWindow();
wnd.DataContext = new MainWindowViewModel();
wnd.Show();

You can do this last bit by removing StartupUri="MainWindow.xaml" from your App.xaml and create and show the main window manually by overriding OnStartup in App.xaml.cs.

您可以通过从 App.xaml 中删除 StartupUri="MainWindow.xaml" 并通过覆盖 App.xaml.cs 中的 OnStartup 手动创建和显示主窗口来完成最后一点。

回答by A.T.

it should be something like this to work,

它应该是这样的工作,

<Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <TextBlock x:Name="First" Text="{Binding FirstString}" Grid.Row="0"/>
            <TextBlock x:Name="Second" Text="{Binding SecondString}" Grid.Row="1"/>
            <TextBlock x:Name="Third" Text="{Binding ThirdString}" Grid.Row="2"/>
            <TextBlock x:Name="Fourth" Text="{Binding FourthString}" Grid.Row="3"/>
        </Grid>

and c# code will be like,

和 c# 代码会像,

public string FirstString { get; set; }
public string SecondString { get; set; }
public string ThirdString { get; set; }
public string FourthString { get; set; }

public MainWindow()
{
    InitializeComponent();    

    FirstString = "First";
    SecondString = "Second";
    ThirdString = "Third";
    FourthString= "Fourth";
    this.DataContext = this;  //here you set the context to current instance of window

}