Why won't my WPF bound Visibility property update? - wpf

I have a textblock in my XAML where the Visibility is bound to a property in my viewmodel. When the window first loads, the value from the viewmodel determines the visibility correctly (I tried manually overriding the backing store variable value and it works great, hiding the control as I need). However, when I change the property value the visibility doesn't change.
Here's the XAML for the control:
<TextBlock Text="Click the button" Style="{StaticResource Message}" Visibility="{Binding NoResultsMessageVisibility}" />
The "NoResultsMessageVisibility" property that I bind to is this:
public Visibility NoResultsMessageVisibility
{
get { return _noResultsMessageVisibility; }
set
{
_noResultsMessageVisibility = value;
NotifyPropertyChanged("NoResultsMessageVisibility");
}
}
NotifyPropertyChange raises a PropertyChanged event for the provided name using standard INotifyPropertyChanged.
Can anyone spot my mistake?
EDIT
In response to the comments / answer so far.
The program is super simple so there's no parallelism / multithreading used.
The DataContext is set only once when the window loads, using:
new MainWindow { DataContext = new MainWindowViewModel() }.ShowDialog();
The binding does seem to work when first loaded. I've noticed as well that a textbox I have bound to a property isn't updating when I change the property. However, the property is definitely updating when I change the textbox as the value is used as the basis for a command that's bound to a button. As the text changes, the button is enabled and disabled correctly and when I click it the value from the property is correct. Again, if I set a value against the backing store variable, this shows in the textbox when the window first loads.

Don't see anything wrong with this, is it possible that the DataContext gets changed, so the binding breaks? (You only specify the path, so it's relative to the current DataContext)

Solved it. I'm a dozy dork :)
I have copied some code from another class and for some reason I'd added the PropertyChanged event to my viewmodel's interface, rather than implementing INotifyPropertyChanged on the interface. D'Oh!

Related

c# wpf Binding Command - access value of textbox from command

I want to call a simple Command which adds values from my GUI into the database.
My Command:
private ICommand addSpeechCommand;
public ICommand AddSpeechCommand
{
get
{
if (addSpeechCommand == null)
{
addSpeechCommand = new RelayCommand(param => AddSpeech());
}
return addSpeechCommand;
}
}
public void AddSpeech()
{
// TODO add
OrganizerBL.InsertSpeech(new Speech(maxSpeechId, currentSpeech.Title, currentSpeech.Summary, currentSpeech.Start, currentSpeech.End, currentSpeech.TrackId, currentSpeech.SpeakerId, currentSpeech.ConferenceId, currentSpeech.Room));
this.LoadSpeeches();
}
-- this commented out row shows how i dealt with it when a row of my datagrid was selected. but i want it to work without a currentSpeech
My XAML:
<Label x:Name ="lblTitle" Content="Title"/>
<TextBox x:Name="txtTitle" Text="{Binding CurrentSpeech.Title, Mode=TwoWay}" Margin="2,144,0,0" Height="20" VerticalAlignment="Top"/>
and other textboxes...
I really don't know how to access the values of the textboxes from the command to call my insertSpeech method...
Sorry for my english :)
UPDATE:
I'm getting a nullreference exception because my currentSpeech is null.
Is there a way to solve this without the currentSpeech?
The reason you get the NullReferenceException is probably because it's instanced in the property itself. When you cerate a binding, it's created to the property as it is at that stage. And you bind to the property when it's NULL. IT's actually created inside the property, but the Binding will never know that.
First of all, I would remove all logic from properties.
I would also implement the INotifyPropertyChanged to the class, and call the PropertyChanged in the property's "set". This means that the UI will know of any changes to the porperty.
Then I would create a depencency property for the property, if it's used in any Binding ot XAML.
Last, I would instance the command in the class's constructor.
Logic don't (in my book) belong to properties.
How to do
1. Bind TextBox.Text to View model property
2. Use View model property in Command Handler.
In your case, You have binded TextBox.Text to CurrentSpeech.Title, but using this.Title.
In you command, change this.Title to currentSpeech.Title

How can the ViewModel request an update in the View in WPF/MVVM?

I have a dependency property on a control in my View that is bound to a field on my ViewModel. When the user clicks a menu item I want the control to update the value of that property so the ViewModel can save it in an XML file. What is the correct mechanism to have the ViewModel request that the View update that property?
Generally with MVVM controls update their bound properties (not fields) immediately as they are edited. The ViewModel is the "state", the View is just one way of seeing that state.
Your control should update the ViewModel whenever it is edited. Your ViewModel can then save it to XML when the menu command is invoked.
I had the problem that the viewmodel was not updated when clicking on a menuitem right after writing in a TextBox.
With the parameter UpdateSourceTrigger=PropertyChanged, it worked for TextBoxes:
<TextBox Grid.Column="5" Grid.Row="7" Text="{Binding SelectedPerson.Room, UpdateSourceTrigger=PropertyChanged}"></TextBox>
But unfortunately not for DatePickers...
The strange thing is that when clicking on a button instead of the menuitem, the DatePicker is updating the viewmodel.
As I don't have more time to look for a bugfix right now, I'll just change my menuitems into buttons.
Edit: the Problem is not the menuitem but the menu itself. When I move the menuitems out of the menu, it works.
Your object must implement INotifyPropertyChanged interface and your properties should look like this
private string _property;
public string Property
{
get { return _property; }
set
{
if(_property == value) return;
_property = value;
RaisePropertyChanged("Property");
}
}
so every change made to the property will be cascaded to view through the binding mechanism.
The menu item command property will be bound to a command declared in the view model and it will trigger a method on view model and set the property value. The change will be cascaded to view:
menuItem.Click -> menuItem.Command.Execute -> viewModel.method -> change the view model property -> raise property changed event -> view property changed through binding

DataBinding Text Property of UserControl to ObservableCollection does not update

I have created a UserControl, which is to display a converted string value based on the contents of a bound ObservableCollection. Everything works when the application loads; my IValueConverter is called and produces the correct string result, which is displayed correctly in my UserControl. However if the ObservableCollection contents change, my control is not updated.
Also, before I created this control, I had the same behaviour, but binding the Content property of a regular Button control, and this also worked correctly and updated as expected.
Any ideas what I am missing to get the same thing with my UserControl?
The control property looks like;
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MyUserControl));
public string Text
{
get { return GetValue(TextProperty) as string; }
set { SetValue(TextProperty, value);
}
The relevant section in the UserControl XAML (which displays the converted string value) is;
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:MyUserControl}}, Path=Text}" />
And the control is created in a separate Window like so;
<CoreControls:MyUserControl
Name="myControl"
Text="{Binding Path=ObservableCollectionInstance, Converter={StaticResource MyValueConverter}, Mode=OneWay}" />
I would use ElementName instead of RelativeSource in your binding, since you have named your user control. Also, you are trying to bind a collection to a <Textbox>. a <Textbox> is designed to display a single item. this is probably why its not working. ObservableCollection fires CollectionChanged events, not PropertyChanged. Even if it did respond, you are still going to have problems because ObservableCollection does not notify when an item contained in it has property changes--only when items are added/removed etc (think, the collection itself changes). If this is the behavior you want, you are going to have to write some code.
EDIT
after your comments, it sounds to me like even though you set it to OneWay binding mode, its acting like OneTime binding mode.
I would try this to help you debug it:
add this xmlns:
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"
and then, in your binding add this:
diagnostics:PresentationTraceSources.TraceLevel=High
here is an article on debugging bindings.
the other thing you could do is set breakpoints in your converter. see if its actually updating when you add/remove things to your collection. I would be willing to bet that its bc the ObservableCollection is NOT firing PropertyChanged events and that the initial update occurs because its not based on an update event.
ObservableCollection notifies only in case if items get added or removed. It is used to observe a collection. They are more suited for content controls. Read about it here. You are talking about observing a property, which needs INotifyPropertyChanged. Posting more code might help, like how are you changing the value of the collection.
Thanks for the tips guys.
I managed to work out a solution; I can handle the CollectionChanged event on the ObservableCollection and then explicitly update the target with something like;
BindingExpression exp = myControl.GetBindingExpression(MyUserControl.TextProperty);
if (null != exp) exp.UpdateTarget();
As noted, most likely, binding on the Text property is only listening to PropertyChanged events, not NotifyCollectionChanged events, but this solution does the trick.

WPF CheckBox's IsChecked property doesn't match binding source's value

In my WPF application I have a CheckBox whose IsChecked value is bound to a property in my viewmodel. Notice that I have commented out the actual line which sets the value in my viewmodel. It's the standard pattern:
View.xaml
<CheckBox IsChecked="{Binding Path=SomeProperty}" />
ViewModel.cs
public bool SomeProperty
{
get { return this.mSomeProperty; }
set
{
if (value != this.mSomeProperty)
{
//this.mSomeProperty = value;
NotifyPropertyChanged(new PropertyChangedEventArgs("SomeProperty"));
}
}
}
When I click the CheckBox I expect nothing to happen, since the value of this.mSomeProperty does not get set. However the observed behavior is that the CheckBox is being checked and unchecked regardless of the value of this.mSomeProperty.
What is going on? Why isn't my binding forcing the CheckBox to show what the underlying data model is set to?
Because WPF does not automatically reload from the binding source after updating the source. This is probably partly for performance reasons, but mostly to handle binding failures. For example, consider a TextBox bound to an integer property. Suppose the user types 123A. WPF wants to continue showing what the user typed so that they can correct it, rather than suddenly resetting the TextBox contents to the old value of the property.
So when you click the CheckBox, WPF assumes that it should continue to display the control state, not to re-check the bound property.
The only way I've found around this, which is not very elegant, is to raise PropertyChanged after WPF has returned from calling the property setter. This can be done using Dispatcher.BeginInvoke:
set
{
// ...actual real setter logic...
Action notify = () => NotifyPropertyChanged(...);
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, notify);
}
This could be made a bit less horrible by consolidating it into the NotifyPropertyChanged implementation so that you wouldn't have to pollute individual properties with this implementation concern. You might also be able to use NotifyOnSourceUpdated and the SourceUpdated attached event, but I haven't explored this possibility.

Two-way binding in WPF

I cannot get a two-way bind in WPF to work.
I have a string property in my app's main window that is bound to a TextBox (I set the mode to "TwoWay").
The only time that the value of the TextBox will update is when the window initializes.
When I type into the TextBox, the underlying string properties value does not change.
When the string property's value is changed by an external source (an event on Click, for example, that just resets the TextBox's value), the change doesn't propagate up to the TextBox.
What are the steps that I must implement to get two-way binding to work properly in even this almost trivial example?
Most probably you're trying to bind to a .net CLR property instead of a WPF dependencyProperty (which provides Change Notification in addition to some other things).
For normal CLR property, you'd need to implement INotifyPropertyChanged and force update on the textbox in the event handler for PropertyChanged.
So make your object with the property implement this interface, raise the event in the property setter. (So now we have property change notification)
Make sure the object is set as the DataContext property of the UI element/control
This threw me off too when I started learning about WPF data binding.
Update: Well OP, it would have been a waste of time if i was barking up the wrong tree.. anyways now since you had to dig a bit.. you'll remember it for a long time. Here's the code snippet to round off this answer. Also found that updating the textbox happens automatically as soon as I tab-out.. You only need to manually subscribe to the event and update the UI if your datacontext object is not the one implementing INotifyPropertyChanged.
MyWindow.xaml
<Window x:Class="DataBinding.MyWindow" ...
Title="MyWindow" Height="300" Width="300">
<StackPanel x:Name="TopLevelContainer">
<TextBox x:Name="txtValue" Background="AliceBlue" Text="{Binding Path=MyDotNetProperty}" />
<TextBlock TextWrapping="Wrap">We're twin blue boxes bound to the same property.</TextBlock>
<TextBox x:Name="txtValue2" Background="AliceBlue" Text="{Binding Path=MyDotNetProperty}" />
</StackPanel>
</Window>
MyWindow.xaml.cs
public partial class MyWindow : Window, INotifyPropertyChanged
{
public MyWindow()
{
InitializeComponent();
this.MyDotNetProperty = "Go ahead. Change my value.";
TopLevelContainer.DataContext = this;
}
private string m_sValue;
public string MyDotNetProperty
{
get { return m_sValue; }
set
{
m_sValue = value;
if (null != this.PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("MyDotNetProperty"));
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
I feel the need to add some precision:
"Two ways" data binding is more than "One way" data binding.
"One way" data binding is a binding from a source to a dependency property. The source must implement INotifyPropertyChanged, in order to get change propagation from source to target.
To get the " 2 way" , so to get a propagation from Target to Source, it depends on the binding mode which you set on the Binding . If you don't set any BindingMode for your binding, the default Binding mode will be used, and this default mode is a characteristics for your target Dependency Property.
Example:
A Textbox bound to a string property, called "MyTextProperty".
In the code, you bind Textbox.Text DependencyProperty to "MyTextProperty" on object "MyObject"
--> "one way" binding : the setter of "My TextProperty" must raise an event Property Changed,and "MyObject" must implement INotifyPropertyChanged.
--> "2 ways data binding": in addition to what is needed for "One way", bindingMode must be set to "2 ways". In this special case, the Text DependencyProperty for Textbox does have "2 ways" as default mode, so there is nothing else to do !
We might need to see the code. Does your string property raise a PropertyChanged event? Or (even better) is it implemented as a DependencyProperty? If not, the bound TextBox won't know when the value changes.
As for typing into the TextBox and not seeing the property's value change, that may be because your TextBox isn't losing focus. By default, bound TextBoxes don't write their values back to the source property until focus leaves the control. Try tabbing out of it and seeing if the property value changes.
Make sure that the binding specifies two way and when the property has a change, it is immediately transmitted to the holding property.
<TextBox Text="{Binding TextBuffer,
UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay}"/>
The above assures that the TextBox input control Text property binds to, then sends the changes back to the string property named TextBuffer in an immediate, PropertyChanged, and TwoWay fashion.

Resources