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.
Related
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.
My problem is, that the UI isn't updating if they call the setter of the property which they binded to.
Here's a sample to make it clear:
Let's say I have a textbox binded to a property like this.
<TextBox PlaceholderText="Task Name..." FontSize="24"
Text="{Binding TaskName, Mode=TwoWay}" />
And this is my property:
public string TaskName
{
get
{
return _taskName;
}
set
{
_taskName = "something";
RaisePropertyChanged();
}
}
If I write something into the textbox then "something" should appear inside of it, after it loses focus, but there isn't any change. However, if I change the value of the property with code, like this:
TaskName = "something";
Then the change will appear on the UI as well.
Some further information.
This is how I implemented the INotifyPropertyChange interface:
public class ViewModelBase : INotifyPropertyChanged
{
public static Navigator NavigationService;
public static void SetNavigationService(Navigator service)
{
NavigationService = service;
}
protected void GoBack()
{
NavigationService.GoBack();
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
I really don't know why is it behave like this. I search for it for hours, but can't find anything.
in the setter of the property you need to call
RaisePropertyChanged(x => x.TaskName)
I am working on an APP that can take number from user and send message to that number.
The number is saved in global variable, the number is changeable by the user. I want the phone number to appear in the textbox every time the user opens the app, so he/she can view the number and update it if they require.
What I've tried:
phonenumber.Text = (App.Current as App).phoneglobal;
I added it after InitializeComponent();, but that didn't work.
Since you are using WPF, I recommend using the MVVM pattern. In your case, you would have:
public partial class MainWindow : Window
{
private MainWindowViewModel viewModel = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = viewModel;
}
}
public class MainWindowViewModel : System.ComponentModel.INotifyPropertyChanged
{
private App currentApp = (Application.Current as App);
public MainWindowViewModel()
{
}
public string PhoneNumber
{
get
{
return currentApp.phoneglobal;
}
set
{
currentApp.phoneglobal = value;
OnPropertyChanged(new PropertyChangedEventArgs("PhoneNumber"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
}
Then, in your xaml, simply bind to the ViewModel's PhoneNumber property.
<Window x:Class="YourNamespace.MainWindow">
<TextBox x:Name="phonenumber" Text="{Binding PhoneNumber}" />
</Window>
Then you should never need to set phonenumber.Text from the code-behind. If you need to set the phone number programmatically, set viewModel.PhoneNumber and the text box will automatically update.
Note that if you set currentApp.phoneglobal directly (without using viewModel.PhoneNumber), then the text box will NOT automatically update.
If this doesn't help, post your xaml code as well as any references in code to the phonenumber text box.
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 have check box in my XAML+C# Windows Store application. Also I have bool property: WindowsStoreTestApp.SessionData.RememberUser which is public and static.
I want check box's property IsChecked to be consistent (or binded, or mapped) to this bool property.
I tried this:
XAML
<CheckBox x:Name="chbRemember1" IsChecked="{Binding Mode=TwoWay}"/>
C#
chbRemember1.DataContext = SessionData.RememberUser;
Code for property:
namespace WindowsStoreTestApp
{
public class SessionData
{
public static bool RememberUser { get; set; }
}
}
But it doesn't seem to work. Can you help me?
<CheckBox x:Name="chbRemember1" IsChecked="{Binding Path=RememberUser, Mode=TwoWay}"/>
public class SessionData : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
bool _rememberUser;
public bool RememberUser
{
get
{
return _rememberUser;
}
set
{
_rememberUser = value;
NotifyPropertyChanged("RememberUser");
}
}
}
You need to implement some form of change notification in order for your check box to be "aware" of any changes to the property. The best bet is to use one of the many MVVM frameworks out there, if not, implement INotifyPropertyChanged in your ViewModel.
Also, typically in WPF, we do not set the DataContext of individual controls but set the DataContext of the Window or User Control to a ViewModel...
Here is an example of a property with change notification through one of the MVVM frameworks:
private bool createTrigger;
public bool CreateTrigger
{
get { return createTrigger; }
set { createTrigger = value; NotifyPropertyChanged(m => m.CreateTrigger); }
}
As you can see a simple auto-implemented property cannot be used for data binding in WPF...
I'd recommend going through Data Binding Overview over on MSDN...
You cannot bind to static properties as static properties cannot raise the PropertyChanged event. You will, of course, need INotifyPropertyChanged. But that is not relevant with static properties. You simply cannot bind to static properties. (You can in WPF and Silverlight)
Try like this, note that the property is not static but the backing field is:
public class SessionData : INotifyPropertyChanged
{
private static bool _rememberUser;
public event PropertyChangedEventHandler PropertyChanged;
public bool RememberUser
{
get { return _rememberUser; }
set
{
_rememberUser = value;
OnPropertyChanged();
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
this.DataContext = new SessionData();
<CheckBox x:Name="chbRemember1" IsChecked="{Binding RememberUser, Mode=TwoWay}"/>