0
votes

I'm new to WPF framework. Data binding for property 'Text' of textbox is not working. Not sure if there's anything wrong with the code?

I have a listbox named 'ConfigListBox' and a textbox named 'NameTextBox'.

<ListBox x:Name="ConfigListBox" Grid.Row="0" Loaded="ConfigListBox_OnLoaded">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="MyApp:Config">
            <WrapPanel>
                <CheckBox Margin="0, 0, 2, 0"/>
                <TextBlock Text="{Binding Name}" />
            </WrapPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<TextBox Name="NameTextBox" Grid.Column="1" Grid.Row="0" Text="{Binding SelectedConfig.Name}"></TextBox>

Object _selectedConfig is the instance of the selected item of ConfigListBox. _selectedConfig will be updated when ConfigListBox is on selected index changed event.

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private List<Config> _configs = new List<Config>();

    private Config _selectedConfig;

    public Config SelectedConfig
    {
        get => _selectedConfig;
        set
        {
            _selectedConfig = value;
            OnPropertyChanged();
        }
    }

    public MainWindow()
    {
        InitializeComponent();
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

Config class has implemented the INotifyPropertyChanged interface.

class Config : INotifyPropertyChanged
{
    public string Name { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

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

Found data context element: ? DataItem=null?, Detailed logs:

System.Windows.Data Warning: 67 : BindingExpression (hash=55056607): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=55056607): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 :     Lookup name _selectedConfig:  queried TextBox (hash=14620943)
System.Windows.Data Warning: 67 : BindingExpression (hash=55056607): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=55056607): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 :     Lookup name _selectedConfig:  queried TextBox (hash=14620943)
System.Windows.Data Warning: 67 : BindingExpression (hash=55056607): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=55056607): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 :     Lookup name _selectedConfig:  queried TextBox (hash=14620943)
System.Windows.Data Warning: 67 : BindingExpression (hash=55056607): Resolving source  (last chance)
System.Windows.Data Warning: 70 : BindingExpression (hash=55056607): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 :     Lookup name _selectedConfig:  queried TextBox (hash=14620943)
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=_selectedConfig'. BindingExpression:Path=Name; DataItem=null; target element is 'TextBox' (Name='NameTextBox'); target property is 'Text' (type 'String')

enter image description here

1
Name property doesn't use OnPropertyChangedstyx
Sorry @styx, I didn't get you. You mean _selectedConfig = ConfigListBox.SelectedItem as Config; doesn't trigger property changed event that defined in Config object?Raphael Xue
please take a look herestyx
Thanks @styx. I've tried your article, doesn't work. But I found someone mentioned namescopes in other questions.Raphael Xue

1 Answers

0
votes

There is no element named _selectedConfig in your example. There is indeed a field with that name but you cannot bind to fields, only to public properties.

So you should turn _selectedConfig into a property and change its name to SelectedConfig.

You also need to implement INotifyPropertyChanged on the object whose property you intend to set dynamically, i.e. MainWindow in this case: Try this:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }

    private Config _selectedConfig;
    public Config SelectedConfig
    {
        get { return _selectedConfig; }
        set { _selectedConfig = value; OnPropertyChanged(); }
    }

    private void ConfigListBox_OnLoaded(object sender, RoutedEventArgs e)
    {
        _configs = ConfigHelper.ReadConfig();

        ConfigListBox.ItemsSource = _configs;

        ConfigListBox.SelectionChanged += ConfigListBoxOnSelectionChanged;
    }

    private void ConfigListBoxOnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        SelectedConfig = ConfigListBox.SelectedItem as Config;
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

XAML:

<ListBox x:Name="ConfigListBox" Grid.Row="0" Loaded="ConfigListBox_OnLoaded">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="MyApp:Config">
            <WrapPanel>
                <CheckBox Margin="0, 0, 2, 0"/>
                <TextBlock Text="{Binding Name}" />
            </WrapPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<TextBox Name="NameTextBox" Text="{Binding SelectedConfig.Name}"></TextBox>