How to update Sub Window on view-model's properties changed? - c#

I'm learning wpf now, but there a problem when coding . The play data were get from MainWindow,and show player's ID,Name....But i need update player's information. SubWindowViewModel side ,I have update binding properties ,but there is problem, I can't update properties in the view side .I want to update SubWindow when viewModel's properties changed .
public SubWindow(Player player)
{
InitializeComponent();
ISubWindowViewModel subWindowViewModel = new SubWindowViewModel();
#region Get data
subWindowViewModel.ID = player.ID;
subWindowViewModel.Name = player.Name;
subWindowViewModel.Sex = player.Sex;
#endregion
this.DataContext = subWindowViewModel;
}
and view model has implement INotifyPropertyChanged,in xaml.cs:
<TextBox x:Name="Name" Text="{Binding UserName,Mode=TwoWay}"/>
<TextBox x:Name="Sex" Text="{Binding Sex,Mode=TwoWay}" />
<TextBox x:Name="ID" Text="{Binding ID,Mode=TwoWay}"/>
Thank you very much!

I am not pro.. coder too.
What I think is you have to implement something called INotifyPropertyChanged interface in the viewmodel class.
Check out the link. There could be more link out there.
How to: Implement Property Change Notification
INotifyPropertyChanged Interface in WPF with Example
Learn and implement it. Hope it helps. Thank you.
EDIT:
I am assuming your viewModelClass name as PersonViewModel. So your viewmodel class would be sth. like below.
class PersonViewModel:INotifyPropertyChanged
{
private string _username;
public string UserName
{
get { return _username; }
set {
_username= value;
OnPropertyChanged("UserName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string Property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(Property));
}
}
}
Your xaml is correct. So now I am assuming that you have passed the same viewmodelclass object(in the constructor) that u have used in the MainWindow. So in the code behind you have to set the DataContext of the window as u have done above.
public SubWindow(PlayerViewModel player)
{
InitializeComponent();
this.DataContext=player;
}

Related

Data binding to singleton class

I've searched here a number of times and found a bunch of examples, but can't seem to get anything to work.
I've got a solution set up where a ViewModel refers to a MainViewModel class through a locator. The main view model class has:
public NotifyLog Log
{
get { return LogMgr.Instance.Log; }
}
In it. This allows me to specify:
<TextBox IsEnabled="True" Text="{Binding Log.Text, Mode=OneWay}" />
The NotifyLog is defined as:
public class NotifyLog : INotifyPropertyChanged
{
public NotifyLog()
{
_Log = new StringBuilder();
}
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
private StringBuilder _Log;
public void Append(String Value)
{
_Log.Append(Value);
OnPropertyChanged("Text");
}
public string Text
{
get { return _Log.ToString(); }
}
public override string ToString()
{
return this.Text;
}
}
For the initial start of the application, the text box is populated but, the OnPropertyChanged handler is never automatically populated by the binding so no changes are detected. I'm doing something wrong, I just don't know what...
Thanks for your time,
BlD
if you want to update the log when typing in the text box you need to change the binding mode to TwoWay. also the event is triggered when you exit from the text box, not on each char typed.
if you want to update the text box when the log is changed you need to add a setter to the Text property and raise the NotifyPropertyChanged event (in the setter).
also check the output of the program for some binding errors.
To the line:
<TextBox IsEnabled="True" Text="{Binding Log.Text, Mode=OneWay}" />
Try adding the "UpdatedSourceTrigger" like so:
<TextBox IsEnabled="True" Text="{Binding Log.Text, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />

Simple XAML binding in a textblock text

I have a TextBlock control inside a HubSection in a Windows 8.1 Universal app.
<TextBlock x:Name="api_enabled_label"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Text="{Binding APIinfotext}" />
Now when the page is launched, in the contrustor, there is a method that is run.
public string APIinfotext { get; set; }
public sealed partial class MainPage : Page {
VoipMS voip_service = new VoipMS("shoukatali#hotmail.com", "Kitt0cat");
public string APIinfotext { get; set; }
public MainPage() {
this.InitializeComponent();
// disable sections until API is enabled
mainpagehub.Sections[1].IsEnabled = false;
mainpagehub.Sections[2].IsEnabled = false;
//check for API and enable sections
checkAPI();
}
private async void checkAPI() {
//irrelevant code above
switch (result) {
case "success":
APIinfotext = "Your API is connected";
break;
//irrelevant code below
}
}
So why dosnt this work? I set the DataContext of the Textblock to the current class (which is the MainPage partial class) and the property is a public property.
Note: Today is my first time working with .net 4.5 with XAML after a huge break at the .net 2.0 framework with WinForms.
Your binding doesn't know that APIinfotext property has changed. To let the bindings know that the property has changed you can do one of the following. The first one is the easiest.
1) implement INotifyPropertyChanged interface and raise the PropertyChanged changed event once APIinfotext has changed (PropertyChanged("APIinfotext"));
2) Have an event called APIinfotextChanged with the standard event signature and raise that event after the property has changed.
3) Implement your property as a DependencyProperty (not an ideal solution in this case).
You might be missing the part where you have to RaiseProperyChange NotifyPropertyChage to update the bindings. your Model should implement the INotifyPropertyChanged interface
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
then
RaisePropertyChanged("APIinfotext");
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx
Looks like you need a very simple example of what the other two are talking about. Let's assume nothing. You need to set the DataContext correctly, plus raise the event. This is as simple as I can put it, when you click on the button it will change the TextBox because I change the Property which raises the event.
XAML
<Page>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<TextBox Text="{Binding APIinfotext}" Height="100" Width="400" HorizontalAlignment="Left"/>
<Button x:Name="myButton" Content="Change Text" Height="200" Width="400" Click="myButton_Click"/>
</StackPanel>
</Grid>
</Page>
C# (Pay attention, to the SET part of the APIinfotext)
using System.ComponentModel; // INotifyPropertyChanged
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
private string _apiinfotext = "Default Text";
public string APIinfotext
{
get { return _apiinfotext; }
set
{
_apiinfotext = value;
RaisePropertyChanged("APIinfotext");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
}
private void myButton_Click(object sender, RoutedEventArgs e)
{
this.APIinfotext = "Don't confuse movement for progress.";
}
}

Set Datasource of Textbox to Inner Class in xaml

I have a wpf gui page with a textbox that is bound to a property of an innerclass in my window. I have defined the textbox to be bound like so:
XAML:
<TextBox Name="shhh" Text="{Binding Path=derpDerp, Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}" />
CodeBehind:
namespace ...
{
public partial class MainWindow : Window
{
innerclass definition....
public Herp derp;
public MainWindow()
{
...
derp = new Herp();
shhh.DataContext = derp;
...
}
{code that changes derp.derpDerp}
}
}
InnerClass:
public class Herp : INotifyPropertyChanged
{
private secret = "";
public event PropertyChangedEventHandler PropertyChanged;
public Herp(string derp)
{
secret = derp;
}
public string derpDerp
{
get{ return secret; }
set{ secret = value; onPropertyChanged("derpDerp"); }
}
private void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
What I was wondering is if I can declare the source of the textbox in the xaml. I have seen many examples that say to set the textbox to the datacontext of the parent like the window or a container around the textbox. However i don't find that very intuitive if only 1 control needs the data. It would make sense if I have several textboxes and a stackpanel with a datacontext.
In my implementation I create the object in code and set the datacontext to just the textbox. Is there an equivalent xaml solution?
Something like:
<TextBox Source="something" Path=derpDerp..../>
without setting a datacontext to a container or the window. Also, I didn't know how to set the datacontext of the window to my property correctly because it's an inner class with a namespace of the namespace.the window class or something like that.
What would be the proper way of just giving the textbox a datasource or if not possible how do I reference the innerclass and set the source to the window?
Yes, you can create an instance of a class and set it as DataContext on any control in XAML. The general solution would be like this:
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyProject">
<Window.Resources>
<local:Herp DerpDerp="This is Derp!!" x:Key="derp"/>
</Window.Resources>
<Grid>
<TextBox Text="{Binding Source={StaticResource derp}, Path=DerpDerp}"/>
</Grid>
Notice that I defined a new xmlns object called local, which points to the namespace in which the class I'm trying to create resides (in this case, it's Herp).Then, in my Window.Resources, I create an instance of Herp, and set a value for the DerpDerp property. Also notice that I gave the class a key, which is necessary in order for the TextBox to find it and bind to it.
Big note: In order for you to be able to create an instace of a class in XAML, the class needs to have a parameter-less constructor! So I changed Herp a little bit:
namespace MyProject
{
public class Herp : INotifyPropertyChanged
{
private string m_derp;
public Herp()
{
}
public string DerpDerp
{
get { return m_derp; }
set { m_derp = value; OnPropertyChanged("DerpDerp"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Finally, in your TextBox, you use the Source element in your binding to bind to the object:
<TextBox Text="{Binding Source={StaticResource derp}, Path=DerpDerp}"/>

how to set binding for the label in wpf

I need to bind a property to a label. i have written the following code:
xaml for the label is
<Label Canvas.Left="807.3" Canvas.Top="148.9" Height="33.567" x:Name="label2"
Width="98" FontFamily="Tw Cen MT" FontSize="24" FontWeight="Bold"
Foreground="#FFFEE3A4"
Content="{Binding Path=UserInformation.AccountBalance,Mode=OneWay}">
<Label.Background>
<ImageBrush />
</Label.Background>
</Label>
The class whcih have the AccountBalance
public class CustomerInformation : INotifyPropertyChanged
{
public CustomerInformation()
{
_Balance = 0.0;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public double AccountBalance
{
get { return _Balance; }
set
{
_wepaBalance = value;
FirePropertyChanged("AccountBalance");
}
}
protected void FirePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
datacontext is set as below
this.LayoutRoot.DataContext = this;
behind the xaml.cs the following code is written to access the UserInfo which is a global object
public CustomerInformation UserInformation
{
get
{
return Globalobjs._Object.UserInfo;
}
}
xamls.cs is derived from Window only.
The problem is PropertyChangedEventHandler of INotifyPropertyChanged is always null when called .
Can any 1 please help me on this issue?
this.LayoutRoot.DataContext = this;
This is the Window, yet you are setting the Window instance as the DataContext. Set the DataContext to the UserInformation.
this.LayoutRoot.DataContext = Globalobjs._Object.UserInfo;
Does the datacontext that you are binding to implement INotifyPropertyChanged?
If this is not an MVVM patterned project, ensure that the class that contains the property that you are binding to implements that interface, and be sure to call the delegate for the event when you change the property (e.g. OnPropertyChanged("MyProperty"))
If it is an MVVM project and you are not using a framework, it is best to derive all of your ViewModels from a ViewModel base that implements INotifyPropertyChanged.
You are binding to the Windows's DataContext. But the Windows DataContext is not the same as the Windows's code behind, where you have UserInformation property defined. To access a property defined in your Window's code behind, you have to set your Window's Name property, then use the following binding instead:
Content="{Binding ElementName=YourWindowName, Path=UserInformation.AccountBalance,Mode=OneWay}"

How binding of Silverlight UI to .NET Classes works

I am looking at binding a certain silverlight UI to a C# class. In the example code below there are two textboxes in the XAML page. Any changes made to one textbox is reflected in the other the minute it loses focus and vice-versa. While the example I have works as I want it to, I have no clue as to what is goin on under the hood and how it works that way.
Here is the C# code
public class Person : INotifyPropertyChanged
{
public string FirstName
{
get
{return firstname;}
set
{ firstname = value;
FirePropertyChanged("FirstName");
}
}
private string firstname;
void FirePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Grid in the mainpage.xaml
<Grid x:Name="MyLayoutRoot" Background="White" ShowGridLines="True">
<TextBox Text="{Binding FirstName, Mode=TwoWay}" Grid.Column="1"></TextBox>
<TextBox Text="{Binding FirstName, Mode=TwoWay}" Grid.Column="1" Grid.Row="3"></TextBox>
</Grid>
Codebehind for Mainpage.xaml
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
Person p = new Person()
{
FirstName ="Dee"
};
MyLayoutRoot.DataContext = p;
}
}
My understanding so far which is a bit hazy now is this:
The textbox in the xaml(mainpage.xaml) knows what property to bind to based on its "Binding" tag, from the class (Person) it was setup with, in the xaml codebehind file(mainpage.xaml.cs) by using the datacontext property there.
INotifyPropertyChanged is an interface in the person class, that provides some hook that allows the Xaml UI to know when the Firstname property got changed in the UI.
The minute the Firstname property is set, the FirePropertyChanged method gets called which triggers this event PropertyChangedEventHandler as is implemented in this line
PropertyChanged(this, new PropertyChangedEventArgs(property));
Can anyone elaborate on what goes on behind the scenes here at this moment, when one of the textboxes changes and loses focus; and how does the Binding property on the Silverlight client side UI, maintain contact with the C# class which, correct me if I am wrong is still on the server that the silverlight UI was downloaded from.
Thanks for your time.
If the Person class is in the same Silverlight UI project, then it is actually on the client (not the server). Maybe this makes it easier to understand?

Categories