I want to bind my label to my model which works fine but the actual value of the property does not get updated, I also implemented INotifyPropertyChanged
Am I doing something wrong here?
My Model
public string ErgebnisBasisPaketPreisString {
get
{
return _ergebnisBasisPaketPreis = (BasisPaketPreis[(int) Basispaket] * (BasisPaketInterval + 1)).ToString("C0");
}
set
{
_ergebnisBasisPaketPreis = value;
OnPropertyChanged(nameof(ErgebnisBasisPaketPreisString));
}
}
My Label:
<Label x:Name="LabelPreisBasispaketIntervall"
Text="{Binding ErgebnisBasisPaketPreisString}"
Grid.Column="3"
VerticalOptions="Center"/>
And I am setting the binding context to my Content page.
ContentPage:
public partial class GeräteKonfiguration : ContentPage {
public GeräteKonfiguration(User currentUser) {
InitializeComponent();
_currentUser = currentUser;
Initialize();
}
private User _currentUser;
private Gerät _currentGerät;
private void Initialize() {
_currentGerät = _currentUser.ServiceModuleAngebotObj.CurrentGerät;
LabelPreisBasispaketIntervall.SetBinding(Label.TextProperty, _currentGerät.ErgebnisBasisPaketPreisString);
LabelPreisBasispaketIntervall.BindingContext = _currentGerät;
BindingContext = _currentGerät;
ToolBarView.BackButton.Clicked += BackButtonOnClicked;
ToolBarView.BackButton.Text = "blabla";
ToolBarView.TitleText = _currentGerät.Anwendung + " - " + _currentGerät.Antriebsart +
" - " + _currentGerät.Baureihe + " - " + _currentGerät.Typ;
LabelPreisBasispaketIntervall.Text = _currentGerät.ErgebnisBasisPaketPreisString;
}
}
This line in your code behind is overwriting your binding by binding the label text to whatever the value of the property is.
LabelPreisBasispaketIntervall.SetBinding(Label.TextProperty, _currentGerät.ErgebnisBasisPaketPreisString)
This isn't likely to be a valid binding path (which would be ErgebnisBasisPaketPreisString), so the binding won't work.
You then get the correct initial value by setting it here:
LabelPreisBasispaketIntervall.Text = _currentGerät.ErgebnisBasisPaketPreisString;
Remove both of these lines, and the binding should work - your XAML looks correct.
Secondly, your property getter doesn't use the value you set it to - you re-compute it each time. Your property should probably just be:
public string ErgebnisBasisPaketPreisString
{
get { return _ergebnisBasisPaketPreisString; }
set
{
_ergebnisBasisPaketPreisString = value;
OnPropertyChanged(nameof(ErgebnisBasisPaketPreisString));
}
}
And you can set the initial computed value in the constructor. Or stick to the computed property and raise the property changed in the dependent properties:
public string ErgebnisBasisPaketPreisString
{
get { return BasisPaketPreis[(int) Basispaket] * (BasisPaketInterval + 1)).ToString("C0"); }
}
public string Basispaket
{
get { return _basispaket; }
set
{
_basispaket = value;
OnPropertyChanged(nameof(Basispaket));
OnPropertyChanged(nameof(ErgebnisBasisPaketPreisString));
}
}
// and similar for the other properties that are used in the computation
Related
I'm making a WPF Application and I want the Text within my Textbox to change as I change the variable value, however, although I'm setting the variable correctly I can't get it to update the Textbox.
I have this class:
public class UserSettings : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string username;
public string nameuser
{
get { return username;} set { username= value; OnPropertyChanged(nameuser); }
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Which gets called in this class:
public partial class User: Window
{
private UserSettings objsettings = null;
public User()
{
objsettings = new UserSettings();
DataContext = objsettings;
InitializeComponent();
Console.WriteLine("objsettings.username1: " + objsettings.nameuser);
}
public void SetUserSettings(string username)
{
Console.WriteLine("Username: " + username);
objsettings.nameuser= username;
Console.WriteLine("objsettings.username2: " + objsettings.nameuser);
}
and the XAML is:
<TextBox Text="{Binding nameuser, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Height="23" Margin="210,193,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="30"/>
The console print in the SetUserSettings prints the value however the console print at the top prints the value as nothing. I'm aware that the top value is printing nothing as it gets set AFTER the console print is called (hence it wouldn't contain a value yet), but how do I update it so the window prints the new value, how do I get it to continously loop through User() without opening new windows but just update the values?
You send incorrect Notify:
get { return username;} set { username= value; OnPropertyChanged(nameof(nameuser)); }
You should send not nameuser, but nameof(nameuser).
As for initial username pass it to the User class:
public User(string username)
{
objsettings = new UserSettings();
objsettings.nameuser = username;
DataContext = objsettings;
InitializeComponent();
Console.WriteLine("objsettings.username1: " + objsettings.nameuser);
}
You send an incorrect Notification. You should send nameof(property name) instead the property value.
In addition, to increase the performance, we don't send notifications if there is no change in property value:
public string nameuser
{
get {
return username;
}
set {
if(username == value)
{
return;
}
username= value;
OnPropertyChanged(nameof(nameuser));
}
}
OnPropertyChanged method expects the property name as string. In your case the code compiles since nameuser is also of type string. But essentially you are just telling the UI to listen for changes in property whose name is same as value of nameuser.
Changing it to the correct property name as OnPropertyChanged("nameuser"), will get the results you want.
In C# version 6 you can also use the nameof feature as it ensures that there are no magic strings in the code OnPropertyChange(nameof(IsBarNull));
I am unable to programmatically set the selection in a ComboBox.
I try setting various properties (SelectedItem, SelectedText, SelectedIndex) but the ComboBox does not display the Name. The first row of the ComboBox, which is blank, is selected. The return value of the setting of the Property is correct.
What am I doing wrong?
...
this.bsConstructionContractors.DataSource = typeof(Contractor);
...
public partial class EditContractorDialog : Form
{
public EditContractorDialog(Contractor contractor)
{
InitializeComponent();
this.cmbEditContractorName.DataBindings.Add(new System.Windows.Forms.Binding("SelectedValue", projectView.bsProject, "ContractorId", true));
// new BindingSource is important here, so as to use a separate CurrencyManager
// because bsConstructionContractors is shared with another ComboBox on another form
this.cmbEditContractorName.DataSource = new BindingSource(projectView.bsConstructionContractors, null);
this.cmbEditContractorName.ValueMember = "ContractorId";
this.cmbEditContractorName.DisplayMember = "Name";
cmbEditContractorName.Enabled = true;
cmbEditContractorName.Focus();
// None of the following cause the ComboBox to display Contractor.Name
// The first entry in the ComboBox, which is a blank, is displayed
object myObject = cmbEditContractorName.SelectedItem = contractor;
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject: " + myObject.GetType()); // type is Contractor
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject: " + myObject); // myObject is the contractor
object myObject2 = cmbEditContractorName.SelectedText = contractor.Name;
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject2: " + myObject2.GetType()); // type is String
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject2: " + myObject2); // myObject2 is the contractor.Name
object myObject3 = cmbEditContractorName.SelectedIndex = 3; // arbitrary index, just to see if it would be selected
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject3: " + myObject3.GetType()); // type is Int32
System.Diagnostics.Trace.WriteLine("EditContractorDialog(): myObject3: " + myObject3); // myObject3 = 3
}
}
public partial class Contractor : System.IComparable
{
protected int id;
protected string name;
protected string licenseNumber;
protected Project project;
public virtual int ContractorId
{
get { return this.id; }
set { this.id = value; }
}
public virtual string Name
{
get { return this.name; }
set { this.name = value; }
}
public virtual string LicenseNumber
{
get { return this.licenseNumber; }
set
{ this.licenseNumber = value; }
}
public virtual int CompareTo(object obj)
{
if (!(obj is Contractor))
{
throw new System.InvalidCastException("This object is not of type Contractor");
}
return this.Name.CompareTo(((Contractor)obj).Name);
}
}
Use SelectedIndex finding the index by contractor name:
cmbEditContractorName.SelectedIndex = cmbEditContractorName.FindString(contractor.Name);
That is because you need to get an object reference to assign from the DataSource of the combobox itself.
Also for comboboxes I suggest you to use an ObservableCollection<T>.
cmbEditContractorName.DataSource = new ObservableCollection<Type>(your List<Type>);
cmbEditContractorName.SelectedItem = ((ObservableCollection<Type>)cmbEditContractorName.DataSource).FirstOrDefault(c=> c.yourProperty = "something"); // this will select the first item meeting your condition
Your code isn't working because you are assigning SelectedItem property with a reference of an object not existing in the combobox DataSource.
I have a WPF application that includes ~50 controls that are bound to properties on my business object which implements INotifyPropertyChanged. Here's a quick snippet of my business object:
public class MyBusinessObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
// properties begin here
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
{
return;
}
_name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
// constructor, etc. not shown
}
I also have several validation rules that are used to validate the user input in these controls. I'm using command binding to prevent my user from saving the data if there are any validation errors. My application also includes a "Reset default values" button which, obviously, will reset the default value for all of the properties on my business object. This all works exactly as I'd like it to with one exception. If my user enters invalid data into one or more controls and then clicks the "Reset default values" button, the controls that contain invalid data don't always update as I'd expect. This happens because of the following code in my property setters:
if (_name == value)
{
return;
}
This code exists to prevent unnecessary property changed notifications from occurring when the value entered by my user in the bound UI control is the same value that the property is already set to. As an example, I have an IntegerUpDown control in my UI (this control is part of the Extended WPF Toolkit from Xceed). The default value of the property that my control is bound to is 10. My user deletes the value from the control and my validation rule is triggered which results in a validation error and the UI is updated appropriately with an error adorner, etc. The value of the property that this control is mapped to hasn't been changed so it's still set to 10. Now my user clicks the "Reset default values" button which will result in the default value (10) for the property being reset. However, the value for the property is already set to 10 so the short circuit logic in my setter will return instead of setting the property value.
So now, after my user clicks "Reset default values", I am also forcing an update on my binding target like this:
this.myIntegerUpDown.GetBindingExpression(Xceed.Wpf.Toolkit.IntegerUpDown.ValueProperty).UpdateTarget();
This solves my problem but only for this particular control. Is there any easy way to do this for all of my bound controls without having to specify each one? Thanks.
OnPropertyChanged(new PropertyChangedEventArgs(string.Empty));
This is intended to imply that ALL properties on that object have changed.
Could you do one of the following?
1) Reset the DataContext - Either recreate it, or re-set the property
var context = this.DataContext;
this.DataContext = null;
this.DataContext = context;
2) Loop through all properties programmatically via reflection and manually call OnPropertyChanged with the relevant property names.
var properties = typeof(ViewModel).GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
this.OnPropertyChanged(new PropertyChangedEventArgs(property.Name));
}
You've mentioned validation and reset values, and of course the obvious one is to persist it.
Why don't you implement IEditableObject Interface on your entity that has three signature methods. BeginEdit(), CancelEdit() and EndEdit()
That way you can easily roll back your entity to the whatever you want, or validate it and lastly persist it. A good example is found here
Sample code
public class Customer : IEditableObject
{
struct CustomerData
{
internal string id ;
internal string firstName ;
internal string lastName ;
}
private CustomersList parent;
private CustomerData custData;
private CustomerData backupData;
private bool inTxn = false;
// Implements IEditableObject
void IEditableObject.BeginEdit()
{
Console.WriteLine("Start BeginEdit");
if (!inTxn)
{
this.backupData = custData;
inTxn = true;
Console.WriteLine("BeginEdit - " + this.backupData.lastName);
}
Console.WriteLine("End BeginEdit");
}
void IEditableObject.CancelEdit()
{
Console.WriteLine("Start CancelEdit");
if (inTxn)
{
this.custData = backupData;
inTxn = false;
Console.WriteLine("CancelEdit - " + this.custData.lastName);
}
Console.WriteLine("End CancelEdit");
}
void IEditableObject.EndEdit()
{
Console.WriteLine("Start EndEdit" + this.custData.id + this.custData.lastName);
if (inTxn)
{
backupData = new CustomerData();
inTxn = false;
Console.WriteLine("Done EndEdit - " + this.custData.id + this.custData.lastName);
}
Console.WriteLine("End EndEdit");
}
public Customer(string ID) : base()
{
this.custData = new CustomerData();
this.custData.id = ID;
this.custData.firstName = "";
this.custData.lastName = "";
}
public string ID
{
get
{
return this.custData.id;
}
}
public string FirstName
{
get
{
return this.custData.firstName;
}
set
{
this.custData.firstName = value;
this.OnCustomerChanged();
}
}
public string LastName
{
get
{
return this.custData.lastName;
}
set
{
this.custData.lastName = value;
this.OnCustomerChanged();
}
}
internal CustomersList Parent
{
get
{
return parent;
}
set
{
parent = value ;
}
}
private void OnCustomerChanged()
{
if (!inTxn && Parent != null)
{
Parent.CustomerChanged(this);
}
}
public override string ToString()
{
StringWriter sb = new StringWriter();
sb.Write(this.FirstName);
sb.Write(" ");
sb.Write(this.LastName);
return sb.ToString();
}
}
Wouldn't it be easier to just always call OnPropertyChanged regardless of whether its the same? How much of a performance boost does that give you?
i make user control from 3 text boxes but i don not how to declare read only property to it i tried many things but it do not work here is my code to make the control
i want to make it read only when needed like if i add checkbox i want if checkbox.check=true make my control readonly
public partial class dateIN : UserControl
{
Dates datess = new Dates();
public dateIN()
{
InitializeComponent();
}
private void dateIN_Leave(object sender, EventArgs e)
{
if (txtDay.Text != "" || txtMonth.Text != "" || txtYear.Text != "")
{
if (!datess.IsHijri(txtDay.Text.Trim() + "/" + txtMonth.Text.Trim() + "/" + txtYear.Text.Trim()))
{
txtDay.Focus();
}
}
}
public string Day
{
set { txtDay.Text = value; }
get { return txtDay.Text; }
}
public string Month
{
set { txtMonth.Text = value; }
get { return txtMonth.Text; }
}
public string Year
{
set { txtYear.Text = value; }
get { return txtYear.Text; }
}
need to know how to make read only property available here plz
just remove the set { } part of the property
Example:
public string Day
{
get { return txtDay.Text; }
}
I dont know the correlation of where your "txtDay", "txtMonth", "txtYear" come from, but you could do something like
public partial class dateIN : UserControl
{
...
...
private bool AllowEditing()
{ return SomeCondition when SHOULD be allowed...; }
public string Day
{
// only allow the set to apply the change if the "AllowEditing" condition
// is true, otherwise, ignore the attempt to assign.
set { if( AllowEditing() )
txtDay.Text = value; }
get { return txtDay.Text; }
}
// same concept for month and year too
}
so may you add some flag to your set when it is true then you set a value.
also you can work with textbox property called ReadOnly.
I'm trying to alter how a combobox is displayed using the following code:
private void UpdateMapRoadPointList(List<GeographicAddress> plstMapRoadPointList)
{
cboFind.DataSource = plstMapRoadPointList;
cboFind.DisplayMember = "ShortCode";
cboFind.ValueMember = "";
}
GeographicAddress is a class which has a ShortCode property which returns a string:
internal string ShortCode
{
get { return Distance + Carriageway; }
}
However, when using the application, the disaplyed value is still coming from GeographicAddress.ToString(). On debugging, it seems that cboFind.DisplayMember = "ShortCode" is having no effect! DisplayMember is "" before and after executing that line!
What am I missing?
public string ShortCode
{
get { return Distance + Carriageway; }
}
private void UpdateMapRoadPointList(List<GeographicAddress> plstMapRoadPointList)
{
cboFind.DataSource = plstMapRoadPointList;
cboFind.DisplayMember = "ShortCode";
}
this should work
Set ShortCode property to Public or it will fail and use GeographicAddress.ToString()