observable collection not getting updated on UI change
-
Hi Experts, I am trying to bind an observable collection to a user control but it is not getting updated on user change but it is getting updated when the user control is changed through code. Following is an example i tried. It might be a bit long but it is working so you can copy and paste the code as it is. Please see my question at the end of the post. --Customer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;namespace TestMVVM
{
class Customer : INotifyPropertyChanged
{
private string firstName;
private string lastName;public string FirstName { get { return firstName; } set { if (firstName != value) { firstName = value; RaisePropertyChanged("FirstName"); } } } public string LastName { get { return lastName; } set { if (lastName != value) { lastName = value; RaisePropertyChanged("LastName"); } } } #region PropertChanged Block public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string property) { if (PropertyChanged != null) { PropertyChanged(this,
new PropertyChangedEventArgs(property));
}
}
#endregion
}
}--UCTextBox.xaml
<UserControl x:Class="TestMVVM.UCTextBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="40" Width="200"> <Grid> <TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="txtTextControl" VerticalAlignment="Top" Width="120" /> </Grid>
</UserControl>
--UCTextBox.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Collectio -
Hi Experts, I am trying to bind an observable collection to a user control but it is not getting updated on user change but it is getting updated when the user control is changed through code. Following is an example i tried. It might be a bit long but it is working so you can copy and paste the code as it is. Please see my question at the end of the post. --Customer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;namespace TestMVVM
{
class Customer : INotifyPropertyChanged
{
private string firstName;
private string lastName;public string FirstName { get { return firstName; } set { if (firstName != value) { firstName = value; RaisePropertyChanged("FirstName"); } } } public string LastName { get { return lastName; } set { if (lastName != value) { lastName = value; RaisePropertyChanged("LastName"); } } } #region PropertChanged Block public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string property) { if (PropertyChanged != null) { PropertyChanged(this,
new PropertyChangedEventArgs(property));
}
}
#endregion
}
}--UCTextBox.xaml
<UserControl x:Class="TestMVVM.UCTextBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="40" Width="200"> <Grid> <TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="txtTextControl" VerticalAlignment="Top" Width="120" /> </Grid>
</UserControl>
--UCTextBox.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.CollectioYou're thinking like a WinForms programmer... WPF has a better way to handle this... Let's focus on UCTextBox to start. You can wipe out about two thirds of that with one data-bind. * The DependencyProperty will handle all of the change notification, so you can ditch the INotifyPropertyChanged completely, along with the methods that support it. * When using a DependencyProperty, your setter ("Text") shouldn't have ANYTHING except the SetValue() call. You have to assume that the setter might not be triggered at all, and that something might call SetValue directly. * The root of your current problem (Don't stop here - There's a better way to do this) is that you're not catching the text box's change event at all. Try this... That textbox inside your UserControl? Don't give it a name at all. It doesn't need one. Back in the WinForms days, you had to name everything, but in WPF, you don't want to name something unless absolutely necessary. The idea is to never directly refer to GUI controls from the code-behind, unless you don't have a choice. (Note: This will force you to remove some of the code, such as the textChangedCallback handler - That's a good thing. You don't need that) So lose the name property, and instead, go to what you're currently calling txtTextControl, and add this inside its XAML tag:
Text="{Binding Text,RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"So what does all of that mean? Let's go through it... "Text={Binding Text..." = Bind the TextBox's text property to the Text property of another control "RelativeSource=" = Instead of naming our source, we're just going to explain how to locate it "{RelativeSource FindAncestor" = The control we want is an ancestor of this one "AncestorType={x:Type UserControl}" = We're looking for a UserControl So far, that means we're going to look up the tree until we find a UserControl, then look for a Text property on it, and bind to that. "Mode=TwoWay" = Bind in both directions, so when either side changes, the other side is updated "UpdateSourceTrigger=PropertyChanged" = Update the bound property every time the user hits a key, instead of when it loses focus. From this point, it's basically magic. That should get you started... Just try to think in terms of WPF, because it changes the game entirely... 1) Don't refer to GUI controls from the code if you can avoid it. Instead, bind the controls to model properties
-
You're thinking like a WinForms programmer... WPF has a better way to handle this... Let's focus on UCTextBox to start. You can wipe out about two thirds of that with one data-bind. * The DependencyProperty will handle all of the change notification, so you can ditch the INotifyPropertyChanged completely, along with the methods that support it. * When using a DependencyProperty, your setter ("Text") shouldn't have ANYTHING except the SetValue() call. You have to assume that the setter might not be triggered at all, and that something might call SetValue directly. * The root of your current problem (Don't stop here - There's a better way to do this) is that you're not catching the text box's change event at all. Try this... That textbox inside your UserControl? Don't give it a name at all. It doesn't need one. Back in the WinForms days, you had to name everything, but in WPF, you don't want to name something unless absolutely necessary. The idea is to never directly refer to GUI controls from the code-behind, unless you don't have a choice. (Note: This will force you to remove some of the code, such as the textChangedCallback handler - That's a good thing. You don't need that) So lose the name property, and instead, go to what you're currently calling txtTextControl, and add this inside its XAML tag:
Text="{Binding Text,RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"So what does all of that mean? Let's go through it... "Text={Binding Text..." = Bind the TextBox's text property to the Text property of another control "RelativeSource=" = Instead of naming our source, we're just going to explain how to locate it "{RelativeSource FindAncestor" = The control we want is an ancestor of this one "AncestorType={x:Type UserControl}" = We're looking for a UserControl So far, that means we're going to look up the tree until we find a UserControl, then look for a Text property on it, and bind to that. "Mode=TwoWay" = Bind in both directions, so when either side changes, the other side is updated "UpdateSourceTrigger=PropertyChanged" = Update the bound property every time the user hits a key, instead of when it loses focus. From this point, it's basically magic. That should get you started... Just try to think in terms of WPF, because it changes the game entirely... 1) Don't refer to GUI controls from the code if you can avoid it. Instead, bind the controls to model properties
Thank you very much for the insight on WPF. I am a little new to WPF and have the only hands on since i am on this project. I think this did the trick for me. Will remember this and also will remove the unwanted code which you have said. Also sorry to have posted in WCF section. I did not check the forum name before posting this. What do you want me to do on this? Should i copy paste this query to WPF forum now? Please advice.
-
Thank you very much for the insight on WPF. I am a little new to WPF and have the only hands on since i am on this project. I think this did the trick for me. Will remember this and also will remove the unwanted code which you have said. Also sorry to have posted in WCF section. I did not check the forum name before posting this. What do you want me to do on this? Should i copy paste this query to WPF forum now? Please advice.
Nah, it's no big deal. If a mod drops by, they can move it over, but no need to post it twice. And don't be daunted by WPF... I was in your shoes a couple years ago, and I was doing the same thing until I got the hang of it. Once you do get into WPF, though, you'll see that you can write amazing interfaces much more easily than with WinForms... I was skeptical at first, but it really is a huge improvement. Just get into data-binding for as much of the GUI processing as possible... Then look into styles... You really don't even need that UserControl, as you could accomplish the same thing with a text box template... But that's a little more advanced, so take it one step at a time.
Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels) -
Nah, it's no big deal. If a mod drops by, they can move it over, but no need to post it twice. And don't be daunted by WPF... I was in your shoes a couple years ago, and I was doing the same thing until I got the hang of it. Once you do get into WPF, though, you'll see that you can write amazing interfaces much more easily than with WinForms... I was skeptical at first, but it really is a huge improvement. Just get into data-binding for as much of the GUI processing as possible... Then look into styles... You really don't even need that UserControl, as you could accomplish the same thing with a text box template... But that's a little more advanced, so take it one step at a time.
Proud to have finally moved to the A-Ark. Which one are you in?
Author of the Guardians Saga (Sci-Fi/Fantasy novels)Thanks Ian..!!! :)