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
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 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 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.
I try to bind my UI to custom DependencyProperty:
<Window.Resources>
<local:Localization x:Key="Localization" xmlns:x="#unknown" xmlns:local="#unknown"/>
</Window.Resources>
<Grid Name="mainStack" DataContext="{StaticResource Localization}">
<Button Padding="10,3" Margin="5" Content="{Binding BtnAdd}" Command="New"/>
</Grid>
Also I have class "Localization":
class Localization : DependencyObject, INotifyPropertyChanged
{
public static DependencyProperty BtnAddProperty;
static Localization()
{
BtnAddProperty = DependencyProperty.Register("BtnAdd", typeof(string), typeof(Localization));
}
public string BtnAdd
{
set
{
SetValue(BtnAddProperty, value);
}
get
{
return (string)GetValue(BtnAddProperty);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
handler.Invoke(this, e);
}
}
public Localization()
{
BtnAdd = MainWindowRes.BtnAdd;
}
public void SwitchLanguage()
{
BtnAdd = MainWindowRes.BtnAdd;
OnPropertyChanged("BtnAdd");
}
}
First time my UI element gets my property value. But when I use my method SwitchLanguage(), property gets new data, and UI still have first value.
Can someone help me please?
P.S.
Sorry, for my English.
Eugene
I tried your example, everything seems to work.
But there are some pitfalls:
There's a framework class called Localization, so make sure you don't mix up!
How do you call SwitchLanguage()? You have to call this on the right instance! (For example in the Code Behind:
var res = (Localization)Resources["Localization"];
res.SwitchLanguage();
Can't really spot any mistake which would make the binding not update, but there are some other things that need to be fixed, the DP field should be readonly and you should not call any property change notifications for DPs as they have an internal mechanism for notifications (inside SetValue).
Are you sure the value of MainWindowRes.BtnAdd is actually different in SwitchLanguage from the value it has in the constructor?