-3

I'm just getting started with WPF in C#, currently using Visual Studio 2019, WPF application in .NET Framework 4.7.2.

I've been struggling with data binding for a few days now, going through numerous tutorials and websites, trying to figure out what I'm missing. At this point, I have placed my current project on hold and started a fresh, new WPF .NET Framework application (no MVVM or any other add-in packages, just C# and WPF XAML) to see if I can get this sorted out, and I am not having any luck.

For the life of me, I cannot get a single public variable that is declared in the MainWindow.xaml.cs file to be bindable in the XAML file. If, for example, I add a public string property (TestString) to the CS file, with a getter and setter, it does not show up when I try to set a textbox Binding to it, whether I use Binding TestString, or Binding Path=TestString, it always shows "No DataContext found for Binding 'TestString', and it has been this way for every other type and control I have tried.

I have tried adding "this.DataContext = this;" to the MainWindow CS file's constructor, and that makes no difference, the binding does not occur when the program is running either. Something I had noticed in other tutorial videos is that when people add the binding statements to the controls, they have intellisense showing the available options, but I have never seen that, the only intellisense I get when adding a Binging to a textbox, or any other type of control, is a list of things like AsyncState, BindingGroupName, BindsDirectlyToSource, Converter, ConverterCulture, and so on. If I select Path from those options, there is no intellisense for any available public properties in the code-behind file.

Below is what I have in the XAML:

<Window x:Class="WPFTest.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:WPFTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="20"/>
        </Grid.ColumnDefinitions>
        
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>
        
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Path=TestString}"></TextBox>
        
    </Grid>
</Window>

And this is what I have in the MainWindow.xaml.cs file:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Forms;

namespace WPFTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : INotifyPropertyChanged

    {
        private string _testString;
        public string TestString
        {
            get
            {
                return _testString;
            }
            set
            {
                _testString = value;
                OnPropertyChanged();
                MessageBox.Show(_testString);
            }
        }

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

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}

I added a message box to the setter of the TestString just to see if it was ever getting set, and it is not. The program compiles and runs, but the binding does not occur. In my main project, which has a GridView, the only way I can get it to show the data from the C# collection is if I force it into the GridView from the code behind file.

Any help you can provide would be greatly appreciated.

NateLFO
  • 9
  • 2
  • Your `MainWindow` doesn't even inherit from `Window`. No clue why it compiles in the first place. However, you set the `DataContext` just fine and access the property as you should. I don't see any issue here. I have to assume you override the DataContext somewhere else. – Bin4ry Apr 27 '22 at 23:26
  • @Bin4ry The base class declaration is also in the generated MainWindow.g.cs, so the code does compile. Besides that, OP is confusing a complaint of the XAML Designer with a compiler error. Their code is ok and just runs, they just did not set UpdateSourceTrigger=PropertyChanged to make sure to see text input immediately in the source property of the Binding. – Clemens Apr 28 '22 at 06:06

1 Answers1

-2

Update: I had also posted this question on Reddit r/csharp and I received some really good replies. There is a two part answer to this question:

  1. Why can't I bind a control to the properties in my code-behind file?
  • I needed to add a DataContext reference to the XAML file in the Window definition.
  • I added DataContext="{Binding RelativeSource={RelativeSource Self}" in the Window parameters and now I have my intellisense and bindings are working as they should.
  1. Why is the TextBox not outputting to the string property in my code behind?
  • It would have if I made the textbox lose focus. There is a fix to this, which is to add in the Binding statement: UpdateSourceTrigger=PropertyChanged. This makes it send the PropertyChanged event every time it is altered, not just when it loses focus.

Example of corrected items:

<Window x:Class="WPFTest.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:WPFTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="20"/>
        </Grid.ColumnDefinitions>
        
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>
        
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding TestString, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></TextBox>
        
    </Grid>
</Window>
NateLFO
  • 9
  • 2
  • Note that `Mode=TwoWay` on the TextBox.Text Binding is redundant. The Text property binds TwoWay by default. Besides that, it makes no difference whether you set the DataContext in XAML or code behind, at least not at runtime. The XAML Designer may of course complain, but that does not mean the Binding isn't working. Maybe you just forget to set an initial value for the TestString property. The TextBox would obviously not show a null string. – Clemens Apr 27 '22 at 22:02