Home > Software engineering >  Trying to access DataContext class from code-behind
Trying to access DataContext class from code-behind

Time:06-23

I'm following this question on how to access your DataContext class from code-behind. Implemeting it the way it says doiesn't work for me (apparently I'm doing something wrong).

What I'm trying to do:

I have a button that is trying to read a Text property from a class that is binded to TextBox:

        private void myButton_Click(object sender, RoutedEventArgs e)
        {
            
            var dataContext = myWindow.DataContext as myClass;
            System.Windows.MessageBox.Show(dataContext.Text);
        }

For some reason dataContext is always null.

XAML:

<Window x:Class="TestApp.MainWindow"
        x:Name="myWindow"
        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:TestApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <Window.Resources>
        <local:myClass x:Key="myDataSource"/>
    </Window.Resources>
    <Window.DataContext>
        <Binding Source="myDataSource"/>
    </Window.DataContext>
    <Grid Margin="0,0,0,2">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBox HorizontalAlignment="Stretch" Margin="5,5,5,5" TextWrapping="Wrap" Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
        <Button x:Name="myButton" Content="Button" HorizontalAlignment="Stretch" Margin="5,5,5,5" Grid.Row="1" VerticalAlignment="Stretch" Click="myButton_Click"/>

    </Grid>
</Window>

Code-behind:

namespace TestApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //var dataContext = myWindow.DataContext as myClass;
        }

        private void myButton_Click(object sender, RoutedEventArgs e)
        {
            var dataContext = myWindow.DataContext as myClass;
            System.Windows.MessageBox.Show(dataContext.Text);
        }
    }

    public class myClass : INotifyPropertyChanged
    {
        private string text;
        public string Text
        {
            get { return text; }
            set { 
                text = value;
                OnPropertyChanged("Text");
            }
        }
        public event PropertyChangedEventHandler? PropertyChanged;

        // Create the OnPropertyChanged method to raise the event
        // The calling member's name will be used as the parameter.
        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}

The full code is also in this question (that was closed since it was "answered" in the question linked above, but the solution still doesn't work for me). What am I doing wrong?

CodePudding user response:

The expression

<Window.DataContext>
    <Binding Source="myDataSource"/>
</Window.DataContext>

binds the DataContext to the string "myDataSource". It should instead be

<Window.DataContext>
    <Binding Source="{StaticResource myDataSource}"/>
</Window.DataContext>

You do however not have to declare the DataContext object as resource at all. Just write

<Window.DataContext>
    <local:myClass/>
</Window.DataContext>

Also be aware that your conclusion that the "DataContext is always null" is incorrect. It is the result of the expression DataContext as myClass which was null, because DataContext did not contain an object of type myClass. In general, when you use the as operator, you should always check the result for null before accessing it. Or use the is operator like

if (DataContext is myClass dataContext)
{
    MessageBox.Show(dataContext.Text);
}

You may also notice that using the myWindow field was redundant, since the code behind methods belong to the MainWindow class.

  • Related