PropertyChanged member for INotifyPropertyChanged is always null - c#

I'm trying to bind a text block to my variable slctItem. I can see it contain the necessary data I need however my window does not show the data I'm expecting. Here is the code behind for my control. This control is used by a pop up window which will display the values of the control.
When walking the code I see that handler returns null every time in the OnPropertyChanged() method. Why? I must be doing something wrong here. Again slcItemdoes contain the data I'm wanting to use. The OnPropertyChanged() method also fires it just contains null for handler.
public partial class MetaData : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _slctItem;
public MetaData()
{
InitializeComponent();
}
public string slctItem
{
get
{
return _slctItem;
}
set
{
_slctItem = value;
OnPropertyChanged("slctItem");
}
}
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
internal void Refresh()
{
try
{
// If DataContext is Null or a detached DataRow, disable the view
if (DataContext != null && (DataContext is DataRow && ((DataRow)DataContext).RowState != System.Data.DataRowState.Detached))
{
if (DataContext is "Something Here")
{
slctItem = (("Something Here")this.DataContext).NAME;
}
}
}
catch (Exception e)
{
throw new Exception("MetaData -> Refresh(): " + e.Message);
}
}
Here is the XAML code for my control. Here I'm trying to bind to slctItem
<TextBox Grid.Column="2" Grid.Row="0" Text="{Binding Path=slctItem, Mode=OneWay, Converter={StaticResource myFirstCharToUpperConverter}}" Width="150" Height="25" HorizontalAlignment="Left" />

You need to set the DataContext to yourself:
public MetaData()
{
InitializeComponent();
this.DataContext = this;
}
This will allow the binding to find the appropriate property. Right now, if you look at the Debug Output in the Output Window at runtime, you should see binding errors since the data context is unset.

Related

Bound target not updating when button pressed to change value

I have some code which uses a form. The form is bound to my class, FormData. I have binding working well and updating my formData (local instance), but when I try to change the value of one of the variables in formData on button click/LostFocus trigger, it doesn't update.
Here's my relevant XAML:
<TextBox x:Name="friendly_name_textBox"
Style="{StaticResource TextErrorStyle}"
Text="{Binding
PrimaryUserName,
Mode=TwoWay,
ValidatesOnExceptions=True,
ValidatesOnDataErrors=True,
UpdateSourceTrigger=PropertyChanged,
NotifyOnValidationError=True}"
HorizontalAlignment="Left"
Margin="0,75,0,0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="120"/>`
The button trigger (which does get run):
private void Button_Click(object sender, RoutedEventArgs e)
{
formData.PrimaryUserName = "TEST";
}
And my FormData code:
public string PrimaryUserName
{
get
{
return primaryUserNameValue;
}
set
{
if(primaryUserNameValue != value)
{
primaryUserNameValue = value;
}
}
}
You need to implement the INotifyPropertyChanged interface and raise the PropertyChanged event in your formData class:
public class formData : INotifyPropertyChanged
{
private string primaryUserNameValue;
public string PrimaryUserName
{
get
{
return primaryUserNameValue;
}
set
{
if (primaryUserNameValue != value)
{
primaryUserNameValue = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Your Class needs to implement INotifyPropertyChanged, so that the target knows if the source property changes:
https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-property-change-notification
It's really easy, please have a look at the documentation and adjust your code accordingly. Your Property would have to look like this:
public string PrimaryUserName
{
get
{
return primaryUserNameValue;
}
set
{
if(primaryUserNameValue != value)
{
primaryUserNameValue = value;
OnPropertyChanged("PrimaryUserName");
}
}
}
But you also need the event and onPropertyChanged function to make it work.
Happy Coding!

WPF C# Binding behaving strangely

So I have a c# wpf application with a default layout and different UserControls to fill one part of that layout. So far everything worked like a charm with binding properties, but now that i created another UserControl the binding only seems to work OneWay.
View -> ViewModel works great, I can trace button clicks, comboboxes being checked and all that stuff, but ...
ViewModel -> View doesn't want to work at all.
I've tried setting the Mode of the Bindings to TwoWay and setting UpdateSourceTrigger to PropertyChanged, but nothing changes.
This is my View:
<UserControl ...
xmlns:vm="clr-namespace:Prueftool.BBCCreatorViewModel"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<vm:CreateDisplayTypeViewModel/>
</UserControl.DataContext>
<Grid>
<Button Content="Button" Width="75" Command="{Binding TestButtonClick}"/>
<CheckBox Content="CheckBox" IsChecked="{Binding TestIsChecked}"/>
</Grid>
</UserControl>
And here is my referenced ViewModel:
namespace Prueftool.BBCCreatorViewModel
{
class CreateDisplayTypeViewModel : ViewModelBase, ICreateDisplayViewModel
{
private bool _testIsChecked;
public bool TestIsChecked
{
get { return _testIsChecked; }
set
{
_testIsChecked = value;
OnPropertyChanged("TestIsChecked");
}
}
public void SetNewDisplayType(DisplayType selectedDisplayType)
{
if(selectedDisplayType.Name == "Default")
{
TestIsChecked = true;
}
}
private DelegateCommand _random;
public ICommand RandomButtonClick
{
get
{
if (_random == null)
{
_random = new DelegateCommand(randomButtonClick);
}
return _random;
}
}
private void randomButtonClick()
{
if(TestIsChecked)
{
MessageBox.Show("Hello World");
}
}
}
}
The SetNewDisplayType method is being called and the if statement is true, but it won't check my combobox in the view. On the other hand, checking the combobox manually and then pressing the button fires the randomButtonClick method and a MessageBox appears.
EDIT:
OnPropertyChanged method (not mine)
#region public virtual void OnPropertyChanged()
/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName">The property that has a new value.</param>
public virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
#endregion
I think you may be calling SetNewDisplayType on a different instance of CreateDisplayTypeViewModel than the one used as DataContext. The binding works and the checkbox is checked when I use your UserControl and change the Constructor to
public MyUserControl()
{
InitializeComponent();
((CreateDisplayTypeViewModel)DataContext).SetNewDisplayType();
}
and SetNewDisplayType to
public void SetNewDisplayType()
{
TestIsChecked = true;
}
It would help though if you could post how this function is called.
Edit: The fact that the handler in OnPropertyChanged is null (as you mentioned in the comments above) is also a hint that you might be using two instances of the VM.
I think you just need to implement INotifyPropertyChanged on your class.
class CreateDisplayTypeViewModel : ViewModelBase, ICreateDisplayViewModel, INotifyPropertyChanged
I see you have the OnPropertyChanged method but you would also need to implement to PropertyChangedEventHandler. Something like this should do it:
#region Public Events
public event PropertyChangedEventHandler PropertyChanged;
#endregion Public Events
#region Protected Methods
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
#endregion Protected Methods

WPF TextBox won't update to programmatic change in ViewModel

I have a WPF ViewModel
class MainWindowViewModel : INotifyPropertyChanged
{
private string _sql;
public string Sql
{
get { return _sql; }
set
{
if (value == _sql) return;
OnPropertyChanged("Sql");
_sql = value;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
I also have a XAML view with a TextBox
<Window.Resources>
<HbmSchemaExporter:MainWindowViewModel x:Key="viewModel"/>
</Window.Resources>
....
<TextBox Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Source={StaticResource ResourceKey=viewModel}, Path=Sql,Mode=OneWay}"/>
Code behind
private MainWindowViewModel ViewModel
{
get { return Resources["viewModel"] as MainWindowViewModel; }
}
The problem is that when in the code I do viewModel.Sql = SOMETHING the text box doesn't get updated. Debugger displays the correct value in the property but the textbox remains blank.
I also tried to change the binding to TwoWay but that only allows me to overwrite the property with a value I type in the textbox, which is something I don't really want (actually I still need to make it readonly, but it's currently out of scope).
How can I update the textbox after programmatically updating the property?
The application is basically a NHibernate DDL generator I'm writing after reading this. I need to press a "Generate SQL" button and it displays the code to run onto DB.
public string Sql
{
get { return _sql; }
set
{
if (value == _sql) return;
OnPropertyChanged("Sql");
_sql = value;
}
}
That does not make sense. At the point that any PropertyChanged event handler is called, reading Sql will still give the old value, because you haven't updated _sql yet. You need to first update the value, and only then raise the PropertyChanged event.

WPF TextBox Bind

I have a class called VoucherEntity, includes a Property named "Customer", a object of Class CustomerEntity, so I have bellow code,
<TextBox Height="23" IsReadOnly="False" HorizontalAlignment="Stretch" Margin="124,48,174,0" Name="txt_customer" VerticalAlignment="Top" Text="{Binding Path=Customer.Name}" />
in .cs file, I have bellow code
_voucher = new VoucherEntity();
this.DataContext = _voucher;
it means, at first, the Customer property is null, after clicked a button, I will give Customer property of _voucher a CustomerEntity object, then I hope the TextBox can display it immediately, but failed, what should I do?
If you want to except changes in your view you should notify the view about the changes.
So just implement the INotifyPropertyChanged interface in the VoucherEntity class and fire the PropertyChanged event after you set the Customer prop
public class VoucherEntity: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void FirePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private CustomerEntity _customer;
public CustomerEntity Customer
{
get {return _customer;}
set
{
if (_customer != value)
{
_customer= value;
FirePropertyChanged("Customer");
}
}
}
}

.NET: Difficulty with Events

Perhaps I don't understand events fully.
I'm building a Windows Phone 7 app in Silverlight.
I have a UserControl that wraps a ListBox, called EditableListBox. The ListBox has a data template. The items in the list box are wrapped by EditableListItem objects.
The data template is as follows:
<DataTemplate>
<Grid ManipulationCompleted="Grid_ManipulationCompleted">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding Path=IconSource}"
Grid.Column="0"
Width="96"
Height="96"
VerticalAlignment="Center"
Visibility="{Binding Path=Editing, Converter={StaticResource visibilityConverter}}"
/>
<TextBlock Text="{Binding Path=Name}" Grid.Column="1" />
</Grid>
</DataTemplate>
I'm binding the Visibility to a property of each EditableListItem, so I need to implement INotifyPropertyChanged so updates to the backing items are reflected in the UI. (Right? Or is there a simpler way to do it?)
EditableListItem:
public class EditableListItem : INotifyPropertyChanged
{
private EditableListBox _parentListBox;
public event PropertyChangedEventHandler PropertyChanged;
public bool Editing
{
get
{
return _parentListBox.Editing;
}
}
public EditableListItem(Section section, EditableListBox parentListBox)
{
_parentListBox = parentListBox;
// after this line, _parentListBox.PropertyChanged is still null.
// why is that?
_parentListBox.PropertyChanged += PropertyChanged;
_parentListBox.PropertyChanged += new PropertyChangedEventHandler(_parentListBox_PropertyChanged);
}
EditableListBox:
public partial class EditableListBox : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// NotifyPropertyChanged will raise the PropertyChanged event,
// passing the source property that is being updated.
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public void SetSectionsSource(ObservableCollection<Section> sectionsSource)
{
sectionsSource.CollectionChanged += new NotifyCollectionChangedEventHandler(sectionsSource_CollectionChanged);
ContentListBox.ItemsSource = sectionsSource.Select(section => new EditableListItem(section, this) { Enabled = true });
//ContentListBox.ItemsSource.Add(new EditableListItem(new Section("Section", 3)) { Enabled = true });
}
// ...
private bool _editing;
public bool Editing
{
get
{
return _editing;
}
set
{
_editing = value;
NotifyPropertyChanged("Editing");
}
}
}
The Editing property is stored in EditableListBox - EditableListItem just forwards it. I wanted to attached EditableListItem.PropertyChanged to EditableListBox.PropertyChanged directly, but the following didn't work:
// after this line, _parentListBox.PropertyChanged is still null.
// why is that?
_parentListBox.PropertyChanged += PropertyChanged;
The following did work:
_parentListBox.PropertyChanged += new PropertyChangedEventHandler(_parentListBox_PropertyChanged);
Why is this? Is the first attempt totally invalid (if so, why does the compiler allow it?)?
To begin with, you don't wire up the PropertyChanged to implement it. The idea is that WPF uses that event and it wires it up. The only thing you do is trigger the event when applicable.
And that's a part of the issue here. You have the Editing property, but it is not being fired. I do understand that you have wired the PropertyChanged of the parent listbox to get the event to fire, but that is not going to work.
If I get the idea right, what you want to accomplish is when the Editing property of the listbox gets changed, you want the PropertyChanged of the list item to be forced.
One of the things of PropertyChanged is that the sender has to be the object where the PropertyChanged is located. This means that you should implement it like this:
public partial class EditableListBox : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// You really should make this protected. You do not want the outside world
// to be able to fire PropertyChanged events for your class.
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool _editing;
public bool Editing
{
get
{
return _editing;
}
set
{
_editing = value;
NotifyPropertyChanged("Editing");
}
}
}
public class EditableListItem : INotifyPropertyChanged
{
private EditableListBox _parentListBox;
public EditableListItem(EditableListBox parentListBox)
{
_parentListBox = parentListBox;
_parentListBox.PropertyChanged += new PropertyChangedEventHandler(_parentListBox_PropertyChanged);
}
void _parentListBox_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Forward the event.
if (e.PropertyName == "Editing")
NotifyPropertyChanged("Editing");
}
public event PropertyChangedEventHandler PropertyChanged;
// You really should make this protected. You do not want the outside world
// to be able to fire PropertyChanged events for your class.
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public bool Editing
{
get
{
return _parentListBox.Editing;
}
}
}
I don't know how you get the reference to the editable listbox, but lets say you get it via the constructor. When you get the reference, you attach the the PropertyChanged event handler of the listbox. Because, when the Editing property of that object changes, actually, your Editing property changes too. This is how you simulate that.
One last thing: the reason why the PropertyChanged is still null after the += PropertyChanged is because the PropertyChanged of the object itself is null. You cannot wire the events in this way. The second way is the correct way of wiring up the events, and the above example shows what you do with this.

Categories