Textbox - bound property value does not update immediately - c#

I have a textbox which is bound to a property ItemID like so.
private string _itemID;
public string ItemID {
get { return _itemID; }
set {
_itemID = value;
}
}
The XAML of the text box is as follows:
<TextBox Text="{Binding Path=ItemID, Mode=TwoWay}" Name="txtItemID" />
The problem is, the value of ItemID does not update immediately as I type,
causing the Add button to be disabled (command), until I lose focus of the text box by pressing the tab key.

Yes, by default, the property would be updated only on lost focus. This is to improve performance by avoiding the update of bound property on every keystroke. You should use UpdateSourceTrigger=PropertyChanged.
Try this:
<TextBox
Text="{Binding Path=ItemID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Name="txtItemID" />
You should also implement the INotifyPropertyChanged interface for your ViewModel. Else, if the property is changed in the ViewModel, the UI would not get to know about it. Hence it would not be updated. This might help in implementation.

You need to fire the OnPropertyChanged event in the setter, otherwise the framework has no way of knowing that you edited the property.
Here are some examples:
Implementing NotifyPropertyChanged without magic strings
Notify PropertyChanged after object update

Related

TextBlock binding to user property displays empty text

I've bound many things without issue, but this one isn't working for some reason. I have a base viewmodel that loads a property called User from the login window:
public void LoadUser()
{
if ((LoginState?)Application.Current.Properties["LoginState"] == LoginState.Success)
{
User = new UserModel((string)Application.Current.Properties["UserLName"], (string)Application.Current.Properties["UserFName"], (int)Application.Current.Properties["UserLevel"]);
RaisePropertyChanged("User");
}
}
This part works fine according to the breakpoint values. This property User is in the base of the viewmodel that is attached as the DataContext of my MainWindow. I bind it on the view with this:
<TextBlock Text="{Binding Path=Name, Source=User}"
Grid.Column="1" Grid.Row="1" Foreground="Black"/>
I know the text block works as I can bind other properties to it, but it won't display this property for some reason. Can you see why?
TextBlock's Default Binding MAY not be TwoWay. So Can you Set it to be TwoWay explicitly in xaml and check once.
Also, that RaisePropertyChanged is custom implementation right. Can you step into it during debug and see if the Event is Null?

Textbox updates itself while typing

I have the following textbox binded to a MVVM ViewModel
Textbox
<TextBox Height="71" Width="341"
Text="{Binding BalanceValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=N2}"
Margin="0,2,2,2" HorizontalAlignment="Right"/>
Below is my ImportPresenter Which handles the input.
Public Class ImportPresenter : ObservableObject
{
private double _BalanceValue = 0;
public double BalanceValue
{
get
{
return _BalanceValue;
}
set
{
_BalanceValue = double.Parse(value.ToString(),
System.Globalization.NumberStyles.Currency);
RaisePropertyChangedEvent("BalanceValue");
}
}//END BALANCEVALUE
}
For the most part, this works, except when testing, The TextBox is updating itself while I'm typing. Should I use a different event for the TextBox?
in some situations updating viewmodel on LostFocus and on every PropertyChanged is equally inconvenient. (e.g. typing key word for search - we don't want to run search after each letter, we want to do it when users stop typing - but they don't leave search field)
since .net 4.5 Binding class has Delay property (in milliseconds):
Text="{Binding BalanceValue, Mode=TwoWay, Delay=333, UpdateSourceTrigger=PropertyChanged, StringFormat=N2}"
To avoid updating the source object with every keystroke, set the Delay property to a reasonable value to cause the binding to update only after that amount of time has elapsed since the user stopped typing.
By default, the UpdateSourceTrigger for the TextBox is Lost Focus. By setting it to PropertyChanged it will update for every change made, e.g. every character.

WPF Two-Way Binding with custom gets and sets

I have a property:
private int myProperty;
public int MyProperty
{
get
{
return myProperty;
}
set
{
// do something special
}
}
I want to bind this property to a textbox like so:
<TextBox Text={Binding MyProperty, Mode=TwoWay} />
Such that when the user changes the value in the textbox, the set is invoked. But the binding doesn't seem to work at all. What am I doing wrong?
<TextBox Text={Binding MyProperty, UpdateSourceTrigger=PropertyChanged} />
You don't need to specify Mode=TwoWay as TwoWay is the default binding mode for TextBox controls. PropertyChanged as UpdateSourceTrigger will execute the setter on every keypress that modifies the text. You can also use the LostFocus UpdateSourceTrigger if you want to delay the setter until the user has finished inputting the value and tabs or clicks to the next control.

How to juggle multiple DataContexts on one XAML window?

I have an class, let's refer to it as SomeClass. SomeClass implements INotifyPropertyChanged and this is coded as follows:
public class SomeClass
{
.
.
.
private bool _isDirty;
public bool IsDirty
{
get { return this._isDirty; }
set
{
this._isDirty = value;
this.NotifyPropertyChanged("IsDirty");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I have a form that uses an instance of SomeClass, called instanceOfSomeClass
This property all fires correctly but onto the main issue which is where I have a Save button bound to that property viz.
<Button Content="Save" Height="23" Name="btnSave" IsEnabled="{Binding Path=IsDirty}" Width="60" Margin="10, 10" HorizontalAlignment="Right" Click="btnSave_Click" />
A combo box SelectionChanged event is supposed to change that property is defined as follows:
<ComboBox Name="cboListOfUsers" ItemsSource="{Binding}" SelectionChanged="cboSomeCombo_SelectionChanged"/>
(I have removed parts of the combo box definition that are not pertinent to the question such as styles etc)
Critically the DataContext of the combo box is not set to the instanceOfSomeClass, rather a List of a custom class.
The SelectionChanged event fires and I have code that looks like this:
instanceOfSomeClass.IsDirty = true;
instanceOfSomeClass.User = (ApplicationUser) cboSomeCombo.SelectedItem;
This runs and although it does change the property and raise the appropriate notification it doesn't enable the command button. I surmise that this is because the DataContext for the combo is different to the DataContext for the command button
I've tried changing the DataContext in the SelectionChanged event but this just results in nothing being selected in the combo (the Save button is enabled though!)
Any help would be greatly appreciated
I surmise that this is because the DataContext for the combo is
different to the DataContext for the command button
no i don't think so. You could try that by not binding the ItemsSource directly to the DataContext instead using a member on the datacontext or using RelativeSource, ElementName, directly specifying the source or another binding syntax. I greatly suggest to use a collection from a property and not set the collection as the datacontext (personally i think thats really bad style, {Binding} should only be used very rarely and i use it only when ContentControls are involved).
Check the Datacontext on the button, use snoop for that it helps greatly by finding bugs like these. Make sure the property is REALLY raised, i can't count how many times we didn't step in the actual NotifyPropertyChanged where the bug was.
Make sure your button doesn't use a command sowhere because commands change the IsEnabled property in some ways.
Make sure nobody is overwriting the IsEnabled property, like Triggers, Animations etc.
Check the output for binding errors or warnings, enable them if you use vs10.
I will update my answer if you can provide more info, was just to much for a comment.

Updating the DisplayMember of a ListBox

This question deals with a dinky little Winforms GUI. Let it be known that I have basic knowledge of data bindings and INotifyPropertyChanged and use both in my ViewModels in WPF. But I don't know Winforms. This is for a school assignment.
So I have a class that has a DisplayName property. I also have a ListBox whose Items are a sequence of instances of my class. I have pointed myListBox.DisplayMember = "DisplayName"; After changing a value in an instance of my class that will cause the DisplayName property to return a different value, how do I tell my ListBox to pull the DisplayName property again to refresh its value?
I needed to do the same thing but with a combobox. The workaround I found is to clear and reset the DisplayMember property.
This worked:
myComboBox.DisplayMember = null;
myComboBox.DisplayMember = "DisplayName";
It's important to note that this is perhaps not the best solution as it will cause multiple SelectedValueChanged events but the end result is successful.
Doing it this way probably requires re-binding the listbox, loosing selectedIndex etc.
One workaround is to forget about the DisplayMember property and handle the Format event of the ListBox instead. Something like (from memory) :
// untested
e.Value = (e.Item as MyClass).DisplayValue;
I know this was ages ago but I had similar problem and could not find satisfying solution and finally solved with this single line at the end after updating the values:
bindingsource.EndEdit();
Items on listbox reflects any changes entered into textboxes after Update button clicked. So after lines like this:
textbox1.DataBindings["Text"].WriteValue();
textbox2.DataBindings["Text"].WriteValue();
just insert this line:
bindingsourcevariable.EndEdit();
Hope this helps others who also encounter similar problem but haven't found the right solution
Here is solution code that does everything in XAML as opposed to back end C#. This is how I do my projects utilizing MVVM (minimizing the back end code, and if possible having no back end code)
<ListBox x:Name="lstServers" HorizontalAlignment="Left" Height="285" Margin="20,37,0,0" VerticalAlignment="Top" Width="215"
ItemsSource="{Binding Settings.Servers}"
SelectedItem="{Binding Settings.ManageSelectedServer, Mode=TwoWay}"
DisplayMemberPath="UserFriendlyName"/>
This is a listbox on the Window. The keys to point out here, which can be very tricky, are the usual ItemsSource property being set to a Settings object on my view model, which has a Servers Observable collection.
Servers is a class that has a property called UserFriendlyName.
public sealed class AutoSyncServer : ObservableModel
{
public AutoSyncServer()
{
Port = "80";
UserFriendlyName = "AutoSync Server";
Server = "localhost";
}
private string _userFriendlyName;
public string UserFriendlyName
{
get { return _userFriendlyName;}
set
{
_userFriendlyName = value;
OnPropertyChanged("UserFriendlyName");
}
}
This is a partial code snippet for you of the class itself.
The SelectedItem of the ListBox is bound to an instance of the Selected object that I store in the model view called ManageSelectedServer.
The tricky part here is the DisplayMemberPath is set to "UserFriendlyName" as opposed to "{Binding UserFriendlyName}". This is key
If you use {Binding UserFriendlyName} it will display the UserFriendlyNames in the collection but will not reflect any changes to that property.
The XAML for the TextBox where the user can update the user friendly name (which should change the text in the listbox also) is:
<TextBox x:Name="txtDisplayName" HorizontalAlignment="Left" Height="23" Margin="395,40,0,0" TextWrapping="Wrap"
Text="{Binding ElementName=lstServers,Path=SelectedItem.UserFriendlyName, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Top" Width="240"/>
This sets the Text property of the TextBox and binds it to the ListBox element lstServers SelectedItem property UserFriendlyName. I've also included an UpdateSourceTrigger=PropertyChanged so that any changes made to the text source notify that they have been changed.
XAML is tricky!

Categories