update source trigger of one control should effect the other control - c#

I am using a third party control for datagrid. I have implemented property changed event in model class and it is working when i use
Text="{Binding itemQty, UpdateSourceTrigger=propertychanged}"
it is even updating in my data source, but i have another textbox here data is not retrieving from the item source though item source is updated with new values.
I want to display the data with property changed event of first textbox and the rows are dynamic, so i can't directly call them.
If i refresh the data source it is displaying but i can't use that process as it is time taking process when items are many.

I want to display the data with property changed event of first textbox and the rows are dynamic
The problem is you have not set Mode=TwoWay for your Text property. And UpdateSourceTrigger defines constants that indicate when a binding source is updated by its binding target in two-way binding.
<TextBox Text="{Binding Info,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding Info}"/>
Code behind
private string info { get; set; }
public string Info
{
get { return info; }
set
{
info = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string properName = null)
{
if(PropertyChanged != null)
this.PropertyChanged(this,new PropertyChangedEventArgs(properName));
}

Related

Binding a combo box to an ObservableCollection

I have a wpf c# application.
I am using a combo box and I have set its itemsource property to an observable collection.
The problem I have is that when I modify this collection the changes are not reflected in my drop down.
so i am wondering what I have done wrong?
This is my class object:
public class JobTicker
{
public string CustomerRef { get; set; }
public string JobRef { get; set; }
public int JobId { get; set; }
public string CustomerJobDetails { get; set; }
public string CustomerName { get; set; }
}
I bind to my collection:
ActiveState.JobsActive = new ObservableCollection<JobTicker>('data from a list');
my declaration of the collection variable:
public static ObservableCollection<JobTicker> JobsActive = new ObservableCollection<JobTicker>();
My combo Box (which is on a userControl of mine that is loaded when my app starts)
<xctk:WatermarkComboBox x:Name="cboActiveJobs" Grid.Row="1" Grid.Column="2"
Width="250" Watermark="Select Customer"
DisplayMemberPath="CustomerJobDetails"
HorizontalContentAlignment="Center"
SelectionChanged="cbo_SelectionChanged"
DropDownOpened="cbo_DropDownOpened"
DropDownClosed="cbo_DropDownClosed"
Style="{StaticResource ComboBoxFlatStyle}"
/>
and my code behind:
cboActiveJobs.ItemsSource = ActiveState.JobsActive;
Now if I modify 'ActiveState.JobsActive' I would expect changes to be reflected in my dropdown but they are not.
The code you have isn't actually binding it. It's just assigning a collection to a property.
The combo box's ItemsSource property can't listen for notifications from the ObservableCollection. Instead, you need an instance of the Binding class to listen for those notifications and make the UI updates happen. Binding is where all the magic is. You could create one programmatically in code behind and attach it (see links below), but the easiest and by far most common way is to bind in XAML:
<xctk:WatermarkComboBox
ItemsSource="{Binding JobsActive}"
SelectedItem="{Binding SelectedCustomer}"
x:Name="cboActiveJobs"
Grid.Row="1"
Grid.Column="2"
Width="250"
Watermark="Select Customer"
DisplayMemberPath="CustomerJobDetails"
HorizontalContentAlignment="Center"
SelectionChanged="cbo_SelectionChanged"
DropDownOpened="cbo_DropDownOpened"
DropDownClosed="cbo_DropDownClosed"
Style="{StaticResource ComboBoxFlatStyle}"
/>
Now, JobsActive should be a public property of the view model that the DataContext for that control. If it isn't, that won't work.
Since you've got a SelectionChanged event, I also added a SelectedCustomer binding, which would be a property on your view model as well. The Binding will update this both ways: Change it in your viewmodel, and the combobox selection will change. When the user picks a combobox item, the viewmodel's property value will change.
private JobTicker _selectedCustomer;
public JobTicker SelectedCustomer {
get { return _selectedCustomer; }
set {
_selectedCustomer = value;
// If you're not in C#6, use this instead:
//OnPropertyChanged("SelectedCustomer");
OnPropertyChanged(nameof(SelectedCustomer));
}
}
// Implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propName));
}
}
If you do want to get this binding working right away without writing a viewmodel, I don't recommend that approach, but it's absolutely doable. There are several answers on StackOverflow that should help with getting that working: WPF Binding Programatically, How to programmatically set data binding using C# xaml.

Binding not updating in ComboBox Text field when underlying ComboBox item description changes

I am having a binding update problem with my ComboBox. My ComboBox's ItemSource is bound to a list of LaneConfigurations. The ComboBox's SelectedItem is bound to the SelectedLaneConfiguration property in my code-behind. I configured the ComboBox's ItemTemplate to display the 'DisplayID' property for each LaneConfiguration.
This works most of the time. However, changing a lane configuration can result in the DisplayID changing. If you have a particular lane selected and it's DisplayID is being displayed as the 'Text' of the ComboBox and then you change the LaneConfiguration object, the 'Text' portion of the ComboBox is not updated with the new 'DisplayID' that should be showing. When I click the dropdown arrow on the ComboBox, the item appearing as the selected item in the list is showing the correct DisplayID, but that doesn't match the 'DisplayID' that is being shown at the top of the ComboBox in it's 'Text' field.
In my code behind, I am firing a PropertyChanged event on the 'SelectedLaneConfiguration' property. How do I get the ComboBox to realize that the 'DisplayID' property needs updating? I have tried to fire a PropertyChanged event for the 'DisplayID' property, but it is part of the LaneConfiguration class, so it doesn't appear to be updating.
I have included the XAML below along with a screenshot that shows the ComboBox Text display out of sync with the content of the ComboBox dropdown.
Partial XAML:
<ComboBox x:Name="_comboBoxLanes" Height="26"
ItemsSource="{Binding SensorConfiguration.LaneConfigurations}"
SelectedItem="{Binding Path=SelectedLaneConfiguration}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayID, Mode=OneWay}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Some of the code-behind:
public partial class LaneManagement : INotifyPropertyChanged, IDisposable
{
..
..
public event PropertyChangedEventHandler PropertyChanged;
private void FirePropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
private void SensorConfiguration_Changed()
{
LaneTools.ResetLanePolygons();
GenerateLaneTypeDropdowns();
FirePropertyChanged("SensorConfiguration");
FirePropertyChanged("SelectedLaneConfiguration");
FirePropertyChanged("DisplayID");
}
}
public class LaneConfiguration : PolygonConfiguration
{
public override string DisplayID
{
get
{
return IsLaneGroup?string.Format("Lanes {0} - {1}", ID, ID + LaneCount - 1): string.Format("Lane {0}", ID);
}
}
}
I created a shorter example of this and reposted and got an answer.
I thought I only needed INotifyPropertyChanged on the code-behind. I actually needed it in my data object LaneConfiguration class as well. I should have paid closer attention to Ali Adl's comment. It would have saved me a day of frustration..
Thanks Ali Adl and Tim for your helpful answers !!
The right way is to make properties that you bindin-g - DependencyProperty - than you'll not have any problems with auto update.
If you use INotifyPropertyCahgnge than it must work, if it don't - check if PropertyChanged event == null.

WPF Simple Binding

I'm trying to convert my console app to a nice WPF GUI. Am getting a little stuck on this code and was wondering if someone can help?
In my xaml I have this:
<CheckBox IsChecked="{Binding CL.LoggedIn}"></CheckBox>
to try and bind the value of the checkbox to the value of CL.LoggedIn. CL is my ConnectionLibrary.cs class in a referenced class library.
In the code behind for the xaml page i declare CL as follows :
public ConnectionLibrary CL = new ConnectionLibrary();
In the connection library class I have added :INotifyPropertyChanged to the class declaration and added the following code:
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
I have changed the LoggedIn property to now look like this:
private bool loggedIn;
public bool LoggedIn {
get { return loggedIn; }
set { loggedIn = value; OnPropertyChanged("LoggedIn"); }
}
However, it doesnt seem to work in my xaml? I dont get any binding errors in the output window, but it doesnt reflect the value of LoggedIn correctly.
Any ideas?
Thanks!
Have you set the datacontext of your view?
In the code-behind of your XAML file, you need to do:
this.DataContext = CL;
then the binding is:
<CheckBox IsChecked="{Binding LoggedIn}"></CheckBox>
The binding will find the the named path (i.e. LoggedIn) on the object that is in the DataContext.
EDIT: The default binding is one-way, this means it only gets updated from your ViewModel.
For controls that can be inputed data (i.e: TextBox, CheckBox...) you can set the Binding as "TwoWay". The Binding expression becomes:
<CheckBox IsChecked="{Binding LoggedIn, Mode="TwoWay"}"></CheckBox>
Now whenever the Checked state changes in the UI, it is reflected in your ViewModel.
When you use Binding like this, it binds to the current DataContext, not to the page itself.
The easiest way to fix this would be to set DataContext = this at the end of the constructor of the page.
The proper way to fix it would be to use MVVM. That would mean having ConnectionLibrary in a property of another class and set the DataContext to this other class.
<CheckBox IsChecked="{Binding LoggedIn}"></CheckBox>

WPF - Auto refresh combobox content

I got a sample mvvm app. The UI has a textbox, a button and a combobox. when I enter something in the textbox and hit the button, the text I enter gets added to an observablecollection. The Combobox is bound to that collection. How do I get the combobox to display the newly added string automaticly?
As I understand correctly, you want to add an item and select it.
Here is the example how it can be done using ViewModel and bindings.
Xaml:
<StackPanel>
<TextBox Text="{Binding ItemToAdd}"/>
<ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" />
<Button Content="Add" Click="Button_Click"/>
</StackPanel>
ViewModel:
public class MainViewModel:INotifyPropertyChanged
{
public ObservableCollection<string> Items { get; set; }
public string ItemToAdd { get; set; }
private string selectedItem;
public string SelectedItem
{
get { return selectedItem; }
set
{
selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
public void AddNewItem()
{
this.Items.Add(this.ItemToAdd);
this.SelectedItem = this.ItemToAdd;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The MainViewModel has 3 properties (one for the TextBox and two other for the ComboBox) and the method AddNewItem without parameters.
The method can be triggered from a command, but there is no standard class for commands, so I will call it from the code-behind:
((MainViewModel)this.DataContext).AddNewItem();
So you must explicitly set an added item as selected after you add it to a collection.
Because the method OnItemsChanged of the ComboBox class is protected and can't be used.
If the ComboBox is bound to an ObservableCollection, the ComboBox will be updated as soon as the collection is changed.
That's the advantage of using an ObservableCollection - you don't need to do any extra coding to update the UI.
If this is not the behavior you're seeing, perhaps you can post some code/xaml.

Bind a control to a single value in a collection/array in WPF

In WPF I have a collection of bool? values and I want to bind each of these to a separate checkbox programmatically. I want the bindings to be TwoWay so that changing the value of the individual item in the collection in code updates the check box and vice versa.
I have spent ages trying to figure out how to do this and I am completely stuck. With the following code the checkbox only gets the right value when the window is loaded and that's it. Changing the check box doesn't even update the value in the collection. (UPDATE: this appears to be a bug in .NET4 as the collection does get updated in an identical .NET3.5 project. UPDATE: Microsoft have confirmed the bug and that it will be fixed in the .NET4 release.)
Many thanks in advance for your help!
C#:
namespace MyNamespace
{
public partial class MyWindow : Window, INotifyPropertyChanged
{
public MyWindow()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public List<bool?> myCollection = new List<bool?>
{ true, false, true, false, true, false };
public List<bool?> MyCollection
{
get { return myCollection; }
set { myCollection = value; }
}
}
}
XAML:
<CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}">
There are a few things that need changing here to get this to work. Firstly you'll need to wrap your boolean value in an object that implements the INotifyPropertyChanged interface in order to get the change notification that you are looking for. Currently you are binding to boolean values in your collection which do not implement the interface. To do this you could create a wrapper class like so :
public class Wrapper: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool val = false;
public bool Val
{
get { return val; }
set
{
val = value;
this.OnPropertyChanged("Val");
}
}
public Wrapper(bool val)
{
this.val = val;
}
}
You'll then want to create these objects in your form instead of a list of booleans. You may also want to use an observable collection instead of a list so that notification of items being added and removed are sent. This is shown below:
public Window1()
{
InitializeComponent();
this.DataContext = this;
}
private ObservableCollection<Wrapper> myCollection = new ObservableCollection<Wrapper>()
{new Wrapper(true), new Wrapper(false), new Wrapper(true)};
public ObservableCollection<Wrapper> MyCollection
{
get { return myCollection; }
}
The next thing to do is to display a list of check boxes in your ui. To do this WPF provides itemscontrols. ListBox is an itemscontrol so we can use this as a starting point. Set the itemssource of a listbox to be MyCollection. We then need to define how each Wrapper object is going to be displayed in the list box and this can be done with a datatemplate which is created in the windows resources. This is shown below :
<Window.Resources>
<DataTemplate x:Key="myCollectionItems">
<CheckBox IsChecked="{Binding Path=Val, Mode=TwoWay}"></CheckBox>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Path=MyCollection}" ItemTemplate="{StaticResource myCollectionItems}"></ListBox>
</Grid>
This should get you up and running with a simple demo of checkboxes that have values bound to a list of booleans.
What makes you think it's not working? It's working for me :)
Here's my test XAML:
<UniformGrid>
<CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}"/>
<ListBox ItemsSource="{Binding MyCollection}"/>
<Button Content="Test" Click="Button_Click"/>
</UniformGrid>
Here's my code behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
}
(the rest is the same as yours)
I placed a breakpoint on Button_Click and checked MyCollection[0] it was updated according to the IsChecked value of the CheckBox.
Try changing your collection type from List<bool?> to ObservableCollection<bool?> perhaps that is the reason you think it's not working for you (the fact that changes to the collection are not reflected anywhere else in your view).
Change your List<bool?> to an ObservableCollection<bool?>. A List does not raise the change notifications that WPF needs to update the UI. An ObservableCollection does. This handles the case where the list entry is changed and the CheckBox needs to update accordingly.
In the other direction, it works for me even with a List<bool?> -- i.e. toggling the checkbox modifies the value in the collection. Your binding syntax is certainly correct.

Categories

Resources