Data binding in wpf with expression in getter - c#

I have a property in my model which has getter
public boolean Status {
get {
return 1==2;
}
}
and a label
<Label Content="{Binding Path=Status, Mode=OneWay}" />
I would like to monitor the Status. Now when the Status value is changed UI does not get updated with the value.

Assuming, that view model already implements INotifyPropertyChanged, you must raise PropertyChanged event, if you want UI to re-read property value. It doesn't matter if this is get-only property or get/set one.
Since it's get-only, you need to call OnPropertyChanged after you change something, that affects getter expression result:
private int a;
private int b;
public bool Status => a == b;
private void DoSomething()
{
a = ...;
b = ...;
// ...
OnPropertyChanged(nameof(Status));
}

You will have to do two things:
Implement the INotifyPropertyChanged interface in class which contains the Status property.
Call the PropertyChanged handler and call that method in the setter of the Status property which you will implement as a part of INotifyPropertyChanged - if you don't what it is, please google it and you will get the piece of code - it basically notifies the UI that a property has changed.
If the Status property is only get then you will have to call the PropertyChanged method after you know that the status has been updated.

Related

C# Binding a Property but checking another [duplicate]

Is it possible to bind to a value in Properties.Settings.Default in a way that will keep my UI current with the value stored there?
I have a class:
public class FavoritePlayer
{
public string Name
{
get
{
return wpfSample021.Properties.Settings.Default.FavoritePlayer.ToString();
}
set
{
wpfSample021.Properties.Settings.Default.FavoritePlayer = value;
}
}
}
In my XAML, I have a resource:
<local:FavoritePlayer x:Key="fvPlayer"/>
and a binding:
<Label DataContext="{DynamicResource fvPlayer}" Content="{Binding Path=Name}"/>
What I would like is for the data-binding to update any time the property is changed. Is there a way to do this?
Conveniently for you, ApplicationSettingsBase implements INotifyPropertyChanged so you just need to subscribe to PropertyChanged on Properties.Settings.Default and raise your own PropertyChanged in response.
You need your properties to implement INotifyPropertyChanged in order for bindings to recognise when the property value changes.

WPF Bind once and never update?

I have a ListView and a GridView that lists users in an application by names. Whenever the user selects an user to edit, I add a new tab to a TabControl, and bind all editable properties to the WPF controls.
However, when the user is editing in the Edit Tab, the information in the List (specifically, the name field) is also being updated.
Currently I'm making a copy of the object to be edited and leaving the original so it doesn't update the ListView, but isn't there a better/easier way to do this?
I've tried setting the Binding Mode=OneWay, didn't work, and also UpdateSourceTrigger=Explicit in the GridView but also didn't work.
Is there any easier way to do this?
Edit: The way I implemented my INotifyPropertyChanged class is part of the issue, since I have this:
public partial class MyTabControl : UserControl
{
public MyTabControl()
{
InitializeComponent();
//Here, DataContext is a List<Users>
//Users being my Model from the Database
//Some of it's properties are bound to a GridView
//User doesn't implement INPC
}
public void OpenTab(object sender, RoutedEventArgs e)
{
User original = (sender as Button).DataContext as User;
// - This will create a new ViewModel below with the User I'm sending
MyTabControl.AddTab(original);
}
}
And my ViewModel of Users is:
public class UserViewModel : INotifyPropertyChanged
{
public User Original { get; private set; }
public string Name { get { return Original.Name; } set { Original.Name = value; OnPropertyChanged("Name"); } }
public UserViewModel(User original)
{
Original = original ?? new User();
}
// - INPC implementation
}
Since my ViewModel is the one reporting the property changes, I didn't expect my original User to report it as well to the GridView.
The Mode=OneWay causes the information flow to go from the bound data entity to the target UI property only, any change to the UI property will not be bound back.
The reason why the UI content is changing is because the underlying property is read/write (i.e. has a getter and a setter) and is notifying any value change (due to the implementation of the INPC interface).
Presuming that it is a list of User objects you've bound to the GridView, you have two simple options to fix this. Which one is best depends on how much scope for change you have:
change the current Name property on the User object, remove the setter for it. Replace the setter with a method to set the property (i.e. SetUserName(string name)) which then sets the private member variable. Or pass the name as an argument to the constructor of the User entity.
create a new property with only a getter which returns the name and set your binding to that; i.e. public string UserName { get { return Name; }}. As there is only a getter there will be no notification of this property, so if the name does change it won't be propagated via this new property.

WPF: Binding TextBox Text to a sub-element of a Property with WCF?

I have a TextBox which I'm trying to bind to a element of a table property 'regimeAlias' is a column with the tbRegimes table which I have mapped with Entity Framework:
<TextBox Text="{Binding NewRegime.regimeAlias, Mode=TwoWay}"/>
Exposed property in my ViewModel:
private tbRegime _NewRegime;
public tbRegime NewRegime
{
get { return _NewRegime; }
set
{
_NewRegime = value;
OnPropertyChanged("NewRegime");
}
}
Lastly, here's the WCF Service Reference auto-generated code class:
public partial class tbRegime : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
//blah blah blah
[System.Runtime.Serialization.DataMemberAttribute()]
public string regimeAlias {
get {
return this.regimeAliasField;
}
set {
if ((object.ReferenceEquals(this.regimeAliasField, value) != true)) {
this.regimeAliasField = value;
this.RaisePropertyChanged("regimeAlias");
}
}
}
The setter never gets hit. Is this because each element within the NewRegime object needs to raise PropertyChanged and if so is there an easy workaround without adding a further DTO layer to my code?
Edit3: with the post from your regimeAlias code. i have to say your binding should work. but of course if you wanna debug you have to set the breakpoint in your regimeAlias setter
<TextBox Text="{Binding NewRegime.regimeAlias, Mode=TwoWay}"/>
this code means, you bind to a Public Property regimeAlias in your class tbRegime.
your setter for NewRegime will never hit because you dont bind to it.
so check your tbRegime class property setter for regimeAlias.
EDIT: the DataContext of the TextBox is of course an object with the Public Property NewRegime, but like i said if you use dot notation in your binding the last property is the one you bind to :)
EDIT: you dont have much ways to workaround:) if you let the binding like you did, you need a model with a public property regimeAlias and it should implement INotifyPropertyChanged.
if you wanna wrap the regimeAlias Property then you have the problem the you have to raise OnPropertyChanged("MyRegimeAlias") at the right point.
public string MyRegimeAlias
{
get { return _NewRegime.regimeAlias; }
set
{
_NewRegime.regimeAlias = value;
OnPropertyChanged("MyRegimeAlias");
}
}
xaml
<TextBox Text="{Binding MyRegimeAlias, Mode=TwoWay}"/>

I can't binding DataGrid to ObservableCollection

I can't understand what's happening here. I have two public properties in my ViewModel:
public ObservableCollection<vw_ClientesFull> MyClients { get; set; }
private IEnumerable<vw_ClientesFull> _clients;
public IEnumerable<vw_ClientesFull> Clients
{
get
{
return _clients;
}
set
{
_clients= value;
OnPropertyChanged("Clients");
}
}
Then I have a method to refresh both of them:
private void RefreshClientes()
{
this.serviceClient.Clientes_ListarCompleted += (s, e) =>
{
Clients = e.Result;
MyClients = new ObservableCollection<vw_ClientesFull>(Clients);
};
this.serviceClient.Clientes_ListarAsync(_sRazonSocial, VendedorSel, TransporteSel, _nID, bInactivos);
}
Them i bind my dataGrid to show the information. If I do:
ItemsSource="{Binding Path=Clients}"
If works perfect, but if i do:
ItemsSource="{Binding Path=MyClients}"
Nothing is show! Why? Doesn't ObservableCollection fire onPropertyChange Automaticaly?
Thanks for the help!!!
UPDATE
So if i need to fire the OnPropertyChange manualy, why this work without it?
public ObservableCollection<Vendedores> Vendedores { get; set; }
private void CargarVendedores()
{
Vendedores = new ObservableCollection<Vendedores>(this.serviceClient.GetVendedores());
this.VendedorSel = this.Vendedores.FirstOrDefault();
}
If i bind a combobox like this:
ItemsSource="{Binding Path=Vendedores}"
Work without the OnPropertyChange! Why!
This problem is due to a misconception. ObservableCollection does not raise PropertyChanged, (which happens when the entire property is reassigned) when you replace it, but rather CollectionChanged (which is raised when items are added or removed). You still need to raise PropertyChanged if you plan to reassign the whole object.
Yes, ObservableCollection implements INotifyPropretyChanged. However, it isn't going to help you here :)
ObservableCollection is special because it implements INotifyCollectionChanged. In other words, it raises an event when items are added to or removed from the underlying collection. It also implements INotifyPropertyChanged, so anything bound to a property of the collection will get updated.
You are changing the variable itself though (setting to a new instance no less). This requires that the "instance" of the ObservableCollection property raise the event. In other words, you need:
private ObservableCollection<vw_ClientesFull> myClients;
public ObservableCollection<vw_ClientesFull> MyClients
{
get { return myClients; }
set
{
myClients = value;
OnPropertyChanged("MyClients");
}
In your update, the binding hasn't fired yet (you set in the constructor) so it gets the correct list. Subsequent changes to the list wouldn't work, however.
You must raise the PropertyChanged event when you set the value of MyClients, same as you've already done for Clients.

WPF - Checkbox bound to whether or not ObservableCollection contains a value?

I currently have a checkbox that is bound to a property that checks an ObservableCollection for a specific value. If the value exists, then the property returns true.
My property and the property that exposes the ObservableCollection are both readonly.
This approach works fine when I first load my model, but when it add additional items into the ObservableCollection the checkbox that is bound to the property does not update.
Here's the code for my property:
public bool IsMeasure11
{
get //readonly
{
return this.Charges.Any(t => t.IsMeasure11);
}
}
And here's the code for my ObservableCollection:
public ObservableCollection<DACharge> Charges
{
get //readonly
{
if (_charges == null)
{
_charges = new GenericEntityCollection<DACharge>(_DACase.Id).ToList().ToObservableCollection();
}
return _charges;
}
}
And the XAML for the Checkbox:
<CheckBox Content="M11" Name="chkM11" IsChecked="{Binding IsMeasure11, Mode=OneWay}">
Thanks in advance,
Sonny
Your property does not implment INotifyPropertyChanged so there is no way for the binding engine to know to update the bound property.
An ObservableCollection<T> does not update the property which it is being returned within; in this instance the public ObservableCollection<DACharge> Charges property.
You will need to register for the ObservableCollection.CollectionChanged event and when an item is added/removed, etc...fire a PropertyChanged event as displayed in the previous link for the Charges property.
You need to invalidate the binding of IsMeasure11 (i.e. invoke the PropertyChanged event of INotifyPropertyChanged) whenever the Charges collection changes. One way of doing this would be to subscribe to the CollectionChanged event of the Charges collection.
// somewhere, maybe the constructor of your view model
this.Charges.CollectionChanged += ChargesChanged;
private void ChargesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
this.NotifyOfPropertyChanged(() => IsMeasure11);
}
You need to make your "add item" action to fire up the INotifyChanged Interface's PropertyChanged event as described here: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
If not then WPF will never know when the value changes as the binding isnt sourced at the ObservableCollection but to another property that accesses it instead.
Hope it helps.

Categories