I want to show the stream data to textbox in real time. But the textbox doesn't updated even the stream data has updated. I don't know what is wrong.
Here is my XAML code.
<TextBox Text="{Binding Path = marketPrice}" HorizontalAlignment="Left"/>
And this is View Model code.
public class OrderTestViewModel : INotifyPropertyChanged
{
public QuotesDataSource DataSource;
public string _marketPrice => DataSource.SymbolPrice;
public string marketPrice
{
get { return _marketPrice; }
set
{
RaisePropertyChanged("marketPrice");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I checked the marketPrice is updated real time.
And the last is hidden code.
public partial class OrderTest : UserControl
{
OrderTestViewModel model = new OrderTestViewModel();
public OrderTest()
{
InitializeComponent();
DataContext = model;
}
}
Please help me.
It seems your marketPrice setter never update the value of _marketPrice (which will always show the same value.
Would you want something like :
public string _marketPrice = DataSource.SymbolPrice;
public string marketPrice
{
get { return _marketPrice; }
set
{
if (_marketPrice != value)
{
_marketPrice = value;
RaisePropertyChanged("marketPrice");
}
}
}
I want to update new value in UI when DataSource.SymbolPrice is updated. DataSource.SymbolPrice is updated periodly
Then you should bind directly to the SymbolPrice property and implement INotifyPropertyChanged and raise the PropertyChanged event in the QuotesDataSource class:
public class OrderTestViewModel
{
public QuotesDataSource DataSource;
public string marketPrice => DataSource.SymbolPrice;
}
Obviously some object must tell the UI when there is a update and this is the responsibility of the source object.
The view model cannot be supposed to know when the price is changed in the QuotesDataSource unless the latter tells it somehow, for example by raising an event.
Related
I try to binding textblock usercontrol with property of my class, but it only works at initial stage, I have implement IPropertyChnaged in my class.
In my class, _Feedbackpos (field of property) would change in background, I don't know how to solve this problem.
my class
public class TestControl : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyname)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
private double _Feedbackpos;
public double Feedbackpos
{
get
{
return _Feedbackpos;
}
set
{
_Feedbackpos = value;
NotifyPropertyChanged("Feedbackpos");
}
}
//it's a callback function, it would excute when detect feedback position of controller change
private void ReadFeedbackpos()
{
_Feedbackpos = Controller.Read();
}
}
application windows
TestControl TestDll = new TestControl();
Binding BindingTxtBlk = new Binding(){Source= TestDll, Path = new Property("Feedbackpos")};
FeedbackPosTxtBlk.Setbinding(Textblock.TextProperty,BindingTxtBlk);
Change the function ReadFeedbackpos() to
private void ReadFeedbackpos()
{
Feedbackpos = Controller.Read();
}
Otherwise NotifyPropertyChanged("Feedbackpos"); will never get called.
I have a array property, in which I want to notify whenever any elements of that array gets changed.
private double[] _OffsetAngles = new double[3];
public double[] OffsetAngles
{
get { return _OffsetAngles; }
set
{
_OffsetAngles = value;
NotifyPropertyChanged();
}
}
if any of the elements of OffsetAngles gets changed, I want to get the notification.
i.e. if I set OffsetAngles[1] = 20; //Trigger should happen.
if I set OffsetAngles[0] = 40; //Trigger should happen again.
Imagine that you are not using double but some class. And then that the filed of that class has changed. Should the array raise property changed? Surely not. So there are multiple solutions that you may consider:
use ObservableCollection and its SetItem method
use ObservableCollection and instead of assigning value remove and insert the value
instead of double use some class that implements INotifyPropertyChanged and when the dobule changes raise this event, it should be right approach if the purpose is data binding
recreate the Array each time (cumbersome and inefficient but still works)
So as others have mentioned, in your case you fire the NotifyPropertyChanged() when the array itself is changed, not any element of the array.
If you want the elements to be able to fire the event you would have to implement a class like:
public class NotifyingData<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private T _Data;
public T Data
{
get { return _Data; }
set { _Data = value; NotifyPropertyChanged(); }
}
}
and then populate your array with that class:
_OffsetAngles[0] = new NotifyingData<double> { Data = 10 };
I don't have access to VS right now, so there might be some errors, but this should be the right concept for you.
This example shows how to create and bind to a collection that derives from the ObservableCollection class, which is a collection class that provides notifications when items get added or removed.
public class NameList : ObservableCollection<PersonName>
{
public NameList() : base()
{
Add(new PersonName("Willa", "Cather"));
Add(new PersonName("Isak", "Dinesen"));
Add(new PersonName("Victor", "Hugo"));
Add(new PersonName("Jules", "Verne"));
}
}
public class PersonName
{
private string firstName;
private string lastName;
public PersonName(string first, string last)
{
this.firstName = first;
this.lastName = last;
}
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
}
The objects in your collection must satisfy the requirements described in the Binding Sources Overview. In particular, if you are using OneWay or TwoWay (for example, you want your UI to update when the source properties change dynamically), you must implement a suitable property changed notification mechanism such as the INotifyPropertyChanged interface.
Ref: https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-create-and-bind-to-an-observablecollection
I had the same issue a while ago. I had to update a DataTable whenever the data changed and that's how I solved it on my program :
public ObservableCollection<KeyStroke> keyList = new ObservableCollection<KeyStroke>();
public class KeyStroke : INotifyPropertyChanged
{
// KeyStroke class storing data about each key and how many types it received
private int id;
private int numPress;
public KeyStroke(int id, int numPress)
{
Id = id;
NumPress = numPress;
}
public int Id
{
get => id;
set
{
id = value;
NotifyPropertyChanged("Id");
}
}
public int NumPress
{
get { return this.numPress; }
set
{
this.numPress = value;
NotifyPropertyChanged("NumPress");
}
}
public event PropertyChangedEventHandler PropertyChanged; //This handle the propertyChanged
private void NotifyPropertyChanged(String propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); //This is the WPF code for the DataGrid but you can replace it by whatever you need
}
}
This should help you. You can also put conditions inside the getter/setters of the properties but I think it's not really pretty
I have a ViewModel that is bound to one page called SettingsView.
In this page i have some properties like so:
public string SettingsHeaderTitle { get { return AppResources.settings_header_title; } }
I have one button that navigates to another page where we can change language and then goes back to SettingsPage.
I had implemented a command like so:
public void UpdateView()
{
RaisePropertyChanged(string.Empty);
}
My problem is that when I call this command from on Loadedd or NavigatedTo events nothing happens. Then I added a button to call this command (for debug purposes) and the Page is updated successfully.
What am I doing wrong?
You need to implement INotifyPropertyChanged on your ViewModels like so
public class SelectionItem<T> : INotifyPropertyChanged
{
private AppliesTo _appliesTo;
public AppliesTo AppliesTo
{
get { return _appliesTo; }
set
{
_appliesTo = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("AppliesTo"));
}
}
}
EDIT: I just noticed you're using MVVM Light, then it becomes even easier, in your ViewModels inherit from ViewModelBase and make your property like this:
private bool _isComparisonRun;
public bool IsComparisonRun
{
get { return _isComparisonRun; }
set
{
if (_isComparisonRun == value) return;
_isComparisonRun = value;
RaisePropertyChanged(() => IsComparisonRun);
}
}
Why does my textbox fail to update when I try to update it from another class?
I've instantiated the MainWindow class in my Email class, but when I try to do
main.trending.Text += emailText;
Am I doing something wrong?
You should bind your data.
Model
public class YourData : INotifyPropertyChanged
{
private string _textBoxData;
public YourData()
{
}
public string TextBoxData
{
get { return _textBoxData; }
set
{
_textBoxData = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("TextBoxData");
}
}
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
XAML Binding
Set data context in Codebehind
this.DataContext = YourData;
Bind Property
<TextBox Text="{Binding Path=Name2}"/>
See #sa_ddam213 comment. Dont do something like MainWindow main = new MainWindow(); inside Email class. Instead, pass the MainWindow object you already have.
Following codes will work:
public class MainWindow
{
public void MethodWhereYouCreateEmailClass()
{
Email email = new Email;
email.Main = this;
}
}
public class Email
{
public MainWindow main;
public void MethodWhereYouSetTrendingText()
{
main.trending.Text += emailText;
}
}
But I dont say that is best practice. I just try to keep it close to your existing code i guess.
I've tried to search, but I can't find the answer. I have a mainwindow containing two usercontrols, A and B. They both have separate ViewModels but get their data from the same modelinstance. When I change a property in usercontrol A, I want it to update the corresponding value in usercontrol B.
It seems that the OnPropertyChanged("MyProperty") only updates properties in the same ViewModel. I know that the data behind ViewModel B is the same as for ViewModel A since I can refresh the data manually with a refresh-button.
Are there any simple ways to refresh the values in other usercontrols?
If you need such behavior also the Model has to implement the INotifyPropertyChanged Interface.
class Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string someText = string.Empty;
public string SomeText
{
get { return this.someText; }
set { this.someText = value; this.PropertyChanged(this, new PropertyChangedEventArgs("SomeText")); }
}
}
class ViewModelA : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Model data;
public Model Data
{
get { return this.data; }
set { this.data = value; this.PropertyChanged(this, new PropertyChangedEventArgs("Data")); }
}
}
class ViewModelB : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Model data;
public Model Data
{
get { return this.data; }
set { this.data = value; this.PropertyChanged(this, new PropertyChangedEventArgs("Data")); }
}
}
You have to pass the same model instance to both viewmodels and then bind the data in your Controls like this.
For TextBoxA that uses ViewModelA as DataContext
<TextBox x:Name="TextBoxA" Text="{Binding Path=Data.SomeText}" />
For TextBoxB that uses ViewModelB as DataContext
<TextBox x:Name="TexTBoxB" Text="{Binding Path=Data.SomeText}" />
Now when you Change the text in one of the text boxes it will automatically change in the other.