Chenxiao
Chenxiao

Reputation: 383

WPF databinding cannot get data

I am writting a login window using WPF and C#,but got stuck when I attempted to retrive username from the TextBox.The class property which I bind to the TextBox always get a null value,and I cannot figure out why.

MainWindow.xaml

<Window x:Class="Databinding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="256*"/>
        <ColumnDefinition Width="261*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Label Grid.Row="0" Grid.Column="0" Content="Username" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" FontSize="20"/>
    <Label Grid.Row="1" Grid.Column="0" Content="Password" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" FontSize="20"/>
    <Button Content="Confirm" Click="Confirm_Click" IsDefault="True" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" FontSize="20"/>
    <Button Content="Cancel" Click="Cancel_Click" IsCancel="True" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" FontSize="20"/>
    <TextBox x:Name="TextUsername" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,0,0,0" TextWrapping="Wrap"  VerticalAlignment="Stretch" ToolTip="Enter your username"/>
    <PasswordBox x:Name="Password" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" Margin="0,0,0,0"  VerticalAlignment="Stretch" ToolTip="Enter your password"/>

</Grid>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace Databinding
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Confirm_Click(object sender, RoutedEventArgs e)
        {
            Login LoginInfo = new Login();

            Binding bindingLogin = new Binding();
            bindingLogin.Source = LoginInfo;
            bindingLogin.Path = new PropertyPath("Username");
            bindingLogin.Mode = BindingMode.TwoWay;
            bindingLogin.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            BindingOperations.SetBinding(this.TextUsername, TextBox.TextProperty,    bindingLogin);

        if(LoginInfo.Username=="admin" && this.Password.Password=="admin")
        {
            MessageBox.Show("Welcome!","Login Status");
        }
        else
        {
            MessageBox.Show("Something is wrong!","Login Status");
        }
    }

    private void Cancel_Click(object sender, RoutedEventArgs e)
    {
        this.Close();
    }
}
public class Login:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private string username;
    public string Username
    {
        get
        {
            return username;
        }
        set
        {
            username = value;
            if(this.PropertyChanged!=null)
            {
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Username"));
                }
            }
        }
    }
}

I know databinding is not a wise option in this case,and I can get things done more efficently by just using

string Username = this.TextUsername.Text

Anyway,this is a some demo,and I have to use databinding in my project.What's wrong with my code?

Upvotes: 1

Views: 210

Answers (3)

Bolu
Bolu

Reputation: 8786

The problem is when user entering/changing Text in the TextUsername, your binding is not there yet, (your binding will only be there after the Confirm_Click, and will be reset with each Confirm_Click) so you need to move it to the constructor.

namespace Databinding
{

    public partial class MainWindow : Window
    {
        Login LoginInfo;
        public MainWindow()
        {
            InitializeComponent();
            LoginInfo = new Login();
            Binding bindingLogin = new Binding();
            bindingLogin.Source = LoginInfo;
            bindingLogin.Path = new PropertyPath("Username");
            bindingLogin.Mode = BindingMode.TwoWay;
            bindingLogin.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            BindingOperations.SetBinding(this.TextUsername, TextBox.TextProperty, bindingLogin);
        }
      //... rest
   }


}

And you could easily apply the binding in XAML, and avoid all of these code behind if you can set the DataContext of your window correctly e.g.:

<TextBox x:Name="TextUsername" Text="{Binding Username}" ..../>

Upvotes: 1

SuicideSheep
SuicideSheep

Reputation: 5550

The below code will works, not sure if it's a good practice thou:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace Databinding
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Login LoginInfo;
        Binding bindingLogin;
        public MainWindow()
        {
            InitializeComponent();
            LoginInfo = new Login();
            bindingLogin = new Binding();
            bindingLogin.Source = LoginInfo;
            bindingLogin.Path = new PropertyPath("Username");
            bindingLogin.Mode = BindingMode.TwoWay;
            bindingLogin.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        }
        private void Confirm_Click(object sender, RoutedEventArgs e)
        {            
            BindingOperations.SetBinding(this.TextUsername, TextBox.TextProperty,    bindingLogin);

            if(LoginInfo.Username=="admin" && this.Password.Password=="admin")
            {
                MessageBox.Show("Welcome!","Login Status");
            }
            else
            {
                MessageBox.Show("Something is wrong!","Login Status");
            }
        }

        private void Cancel_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
    }
    public class Login:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private string username;
        public string Username
        {
            get
            {
                return username;
            }
            set
            {
                username = value;
                if(this.PropertyChanged!=null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Username"));
                }
            }
        }
    }
}

Upvotes: 0

GazTheDestroyer
GazTheDestroyer

Reputation: 21251

At the point you attach your binding, Login.Username is null, and since the binding is two way WPF will update your textbox to null to match.

Bindings are supposed to be active all the time, and declared in the XAML, rather than bound at the point you want data. You are defeating the object of using bindings. Like you say, it would be far easier to just grab the text directly if you are going to do it explicitly.

Upvotes: 3

Related Questions