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
}
//...
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'm writing a simple game in c# using wpf. In my xaml.cs I create a Game object that does all the work.
I need to be able to reload the window on a certain propertyChange in the Game object. I already have this in my xaml:
<TextBlock x:Name="PhaseTB" Text="{Binding Phase, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"/>
and Phase is part of the Game object:
public class Game : INotifyPropertyChanged
{
private static Game _instance;
private GamePhase phase;
public static Game Instance
{
get
{
if (_instance == null)
_instance = new Game(10, 10);
return _instance;
}
}
public GamePhase Phase
{
get { return phase; }
set
{
phase = value;
OnPropertyChanged("Phase");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
That all works fine and the textbox is updated according to the Phase value.
My question is: How do I call on a method whenever the Phase value changes? The text changes just fine, but I have no idea how to call a code-behind method.
(sorry for noob-question. I have inherited the code and don't really understand how the whole thing works)
You need to subscribe to the event PropertyChanged:
`<yourDataContext>`.PropertyChanged += propertyChangedHandler;
where <yourDataContext> is your DataContext and propertyChangedHandler is the event handler.
Note - You can access the Data Context like this:
((Game)textBox1.DataContext).PropertyChanged += propertyChangedHandler;
or
((Game)this.DataContext).PropertyChanged += propertyChangedHandler;
if your TextBox inherits the DataContext from the Window/Page's main class.
That event exists precisely for the very purpose you mentioned.
And as for where this code should be put, I would generally put it in the constructor since it's assigning event handlers:
public class MainWindow() {
public MainWindow() {
InitializeComponent();
// Here go the event handlers....
}
}
More info:
Property Changed Event
Data Context
I am trying to bind but it doesn't seem to be working :/
my code:
void Binding(velocity Object, Label Output, string Field)
{
Binding newBinding = new Binding();
newBinding.Source = Object;
newBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
newBinding.Path = new PropertyPath(Field);
Output.SetBinding(Label.ContentProperty, newBinding);
}
Binding(newProjectile.CurrentVelocity, lbl_CurrentVelOutput, "Magnitude"); // how i call it
Thanks a bunch!
edit: i dont get an errror, its just that on the output the label doesnt change.
edit: i have tried looking for how to implement the INotifyChange interface and got something like this
public class velocity : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler Handler = PropertyChanged;
if (Handler != null)
{
Handler(this, new PropertyChangedEventArgs(name));
}
}
public double Velocity
{
get { return Magnitude; }
set
{
Magnitude = value;
OnPropertyChanged("10");
}
}
but i have no idea what i am doing.
Your binding should work just fine, but if you want changes to that Magnitude property to automatically show up in your view, then you'll have to let WPF know about those changes. That's where the INotifyProperty interface comes in, as it allows your code to let WPF known which properties have been changed:
// In C#, the common convention is to give classes CamelCased names:
public class Velocity : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
// Local variables and method arguments are also camelCased,
// but they start with a lower-case character:
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
// Properties with default getters and setters automatically get a 'backing field',
// but we can't use that because we need to call OnPropertyChanged, so we'll have to
// manually write out things. Normally, you'd give the backing field a name similar
// to the property, so it's obvious that they belong together:
private double _magnitude;
public double Magnitude
{
get { return _magnitude; }
set
{
_magnitude = value;
// Here, you need to pass in the *name* of the property that's being changed,
// so WPF knows which views it needs to update (WPF can fetch the new value
// by itself):
OnPropertyChanged("Magnitude");
}
}
}
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.