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.
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.
I ran into a quite confusing problem when developing a multi-window wpf application.
There are two windows, MainWindow and SecondWindow. The code of both is pretty simple:
MainWindow:
<Button Content="Change Property to 5" Click="ChangeProperty" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" />
SecondWindow:
<Label Content="{Binding InstanceOfMyClass.value, NotifyOnSourceUpdated=True}"></Label>
The code behind the second Window is untouched, the code behind the first window is the following:
public partial class MainWindow : Window
{
SecondWindow w;
ViewModel vm;
public MainWindow()
{
InitializeComponent();
vm = new ViewModel() { InstanceOfMyClass = new MyClass() { value = 3 } };
w = new SecondWindow() { DataContext = vm };
w.Show();
}
private void ChangeProperty(object sender, RoutedEventArgs e)
{
vm.InstanceOfMyClass.value = 7;
}
}
And the view model class which implements INotifyPropertyChanged:
class ViewModel : INotifyPropertyChanged
{
private MyClass _instance;
public MyClass InstanceOfMyClass
{
get
{
return _instance;
}
set
{
_instance = value;
OnPropertyChanged("InstanceOfMyClass");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
class MyClass
{
public int value { get; set; }
}
I expected the text block to change its text to 5 when I click the button.
The number "3" is correctly loaded on startup. The window also refreshes when I create a new instance of MyClass and set it as InstanceOfMyClass in my ViewModel.
But when I hit the button - or, even stranger, when I temporarily store InstanceOfMyClass, set it to null and reassign it with the saved variable - nothing happens.
Any idea why?
Thanks in advance!
Implement INotifyPropertyChanged in MyClass and try again. In ChangeProperty you change the value property, that doesn't notify the view about the change.
Or you can also try rewriting your ChangeProperty to the following:
vm.InstanceOfMyClass = new MyClass() { value = 7 };
Both of these approaches should fix the problem as far as I can see.
I wanted to do something really simple with data binding, but this is just not working. this is what i wanted to do:
1, I want to do it with designer, because i don't want to manage the code, which is the whole purpose of me using this IDE.
2, when user edit in a text box, a string variable in my class changes.
3, when the program edit the string variable, text in that text box changes.
here's the code i wrote for it:
public partial class frmMain : Form, INotifyPropertyChanged
....
private string _btxtChars;
[System.ComponentModel.Bindable(true)]
public string btxtChars {
get
{
return _btxtChars;
}
set
{
_btxtChars = value;
OnPropertyChanged("btxtChars");
}
}
....
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
and I set the corresponding attribute in my designer that have resulted the following code:
this.txtCharToAdd.DataBindings.Add(
new System.Windows.Forms.Binding("Text",
this.frmMainBindingSource,
"btxtChars",
true,
System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged)
);
Now, when I edit the variable btxtchars, nothing happens. What did I do wrong?
You should initialize your BindingSource as follows to initiate binding with your form as data-storage object:
public partial class frmMain : Form, INotifyPropertyChanged {
public frmMain() {
InitializeComponent();
// you can see that the InitializeComponent method contains the following line:
// this.frmMainBindingSource.DataSource = typeof(WindowsFormsApplication1.frmMain);
frmMainBindingSource.DataSource = this; // you should either replace the line above or initiate binding here
}
//...
I am just getting started with MVVM so apologies if I've done something really stupid. I tried writing a very simple test to see if I could remember everything, and for the life of me I can't see why its not working.
In my view I have a textBox where its text property is bound to a value in the ViewModel. Then when pressing a button the value should be altered and the textBox update.
I can see the value does alter (I have added a MessageBox.Show() line in the buttom press command) however the textBox does not update.
I assume that this means I have not properly implemented the INotifyPropertyChanged event properly but am unable to see my mistake.
Could anyone point me in the right direction?
Here is the code:
View
<Window x:Class="Mvvm.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<TextBox Height="40" Width="200" Text="{Binding helloWorld.Message, UpdateSourceTrigger=PropertyChanged}"/>
<Button Command="{Binding UpdateTimeCommand}">Update</Button>
</StackPanel>
</Window>
Behind View
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel.MainWindowViewModel();
}
}
ViewModel
namespace Mvvm.ViewModel
{
internal class MainWindowViewModel
{
private HelloWorld _helloWorld;
/// <summary>
/// Creates a new instance of the ViewModel Class
/// </summary>
public MainWindowViewModel()
{
_helloWorld = new HelloWorld("The time is " + DateTime.Now.ToString("HH:mm:ss"));
UpdateTimeCommand = new Commands.UpdateTimeCommand(this);
}
/// <summary>
/// Gets the HellowWorld instance
/// </summary>
public HelloWorld helloWorld
{
get
{
return _helloWorld;
}
set
{
_helloWorld = value;
}
}
/// <summary>
/// Updates the time shown in the helloWorld
/// </summary>
public void UpdateTime()
{
helloWorld = new HelloWorld("The time is " + DateTime.Now.ToString("HH:mm:ss"));
}
public ICommand UpdateTimeCommand
{
get;
private set;
}
}
Model
namespace Mvvm.Model
{
class HelloWorld : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public HelloWorld(string helloWorldMessage)
{
Message = "Hello World! " + helloWorldMessage;
}
private string _Message;
public string Message
{
get
{
return _Message;
}
set
{
_Message = value;
OnPropertyChanged("Message");
}
}
private void OnPropertyChanged(string p)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(p));
}
}
}
}
Commands
namespace Mvvm.Commands
{
internal class UpdateTimeCommand : ICommand
{
private ViewModel.MainWindowViewModel _viewModel;
public UpdateTimeCommand(ViewModel.MainWindowViewModel viewModel)
{
_viewModel = viewModel;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_viewModel.UpdateTime();
}
}
}
Sorry for such a long post and it being a spot my mistake post but I've looked at it for so long and I don't know what I'm doing wrong
Thanks!
The Problem that you have is that you are changing the wrong Property. Instead of changing the HelloWorld.Message Property, you are changing MainWindowViewModel.HelloWorld property. Your code will work OK if you change this line:
public void UpdateTime()
{
helloWorld = new HelloWorld("The time is " + DateTime.Now.ToString("HH:mm:ss"));
}
For this one
public void UpdateTime()
{
helloWorld.Message = "The time is " + DateTime.Now.ToString("HH:mm:ss");
}
If you want to keep your original code, then you need to implement INotifyPropertyChanged for your ViewModel, and rise the event when you change helloWorld object.
Hope this helps
I think you need to implement PropertyChanged notification on your ViewModel. You are creating a new HelloWorld in the UpdateTime method, but the UI doesn't know it.
Edit
I have a ViewModel base class which I derive all of my ViewModels from. It implements INotifyPropertyChanged, and has references to my relay command classes, and some other common stuff. I recommend always having INotifyPropertyChanged implemented on the ViewModel. The ViewModel is there to expose data to the UI, and it cant do that for data that changes without that interface.
i think your ViewModel needs to implement INotifyPropertyChanged too,
or you can set the DataContext before you call InitializeComponents(), if you do that you should change your code to NOT create a new instance every update like Agustin Meriles said.
i think you mistake Model and VM: Model is MainWindowViewModel and VM is HelloWorld
In your VM (class HelloWorld ) you need use your model
So, your classes will look like:
using System.ComponentModel;
namespace WpfApplication1
{
public sealed class TextVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private TextInfo _info;
public TextVM()
{
_info = new TextInfo();
}
public string MyText
{
get { return _info.MyText; }
set
{
_info.MyText = value;
OnPropertyChanged("MyText");
}
}
private void OnPropertyChanged(string p)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(p));
}
}
}
}
using System;
namespace WpfApplication1
{
public sealed class TextInfo
{
public TextInfo()
{
MyText = String.Empty;
}
public string MyText { get; set; }
}
}
inset inside your ICommands
I am new at C# and databinding, and as an experiment I was trying to bind the form title text to a property:
namespace BindTest
{
public partial class Form1 : Form
{
public string TestProp { get { return textBox1.Text; } set { } }
public Form1()
{
InitializeComponent();
this.DataBindings.Add("Text", this, "TestProp");
}
}
}
Unfortunately, this does not work. I suspect it has something to do with the property not sending events, but I don't understand enough about databinding to know why exactly.
If I bind the title text directly to the textbox, like this:
this.DataBindings.Add("Text", textBox1, "Text")
Then it does work correctly.
Any explanation about why the first code sample does not work would be appreciated.
You must implement INotifyPropertyChanged interface.
Try the following code and see what happens when you remove NotifyPropertyChanged("MyProperty"); from the setter:
private class MyControl : INotifyPropertyChanged
{
private string _myProperty;
public string MyProperty
{
get
{
return _myProperty;
}
set
{
if (_myProperty != value)
{
_myProperty = value;
// try to remove this line
NotifyPropertyChanged("MyProperty");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private MyControl myControl;
public Form1()
{
myControl = new MyControl();
InitializeComponent();
this.DataBindings.Add("Text", myControl, "MyProperty");
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
myControl.MyProperty = textBox1.Text;
}
I think you need to implement the INotifyPropertyChanged Interface. You must implement this interface on business objects that are used in Windows Forms data binding. When implemented, the interface communicates to a bound control the property changes on a business object.
How to: Implement the INotifyPropertyChanged Interface