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}"
Related
C#, WPF. I am using a Datagrid with binding. My understanding is that with INotifyPropertyChanged implemented, object properties should update in the Datagrid if they are changed.
Currently this is not happening, although I I have implemented INotifyPropertyChanged and I know from testing that the PropertyChanged event is firing. My guess is that binding is not two-way(?) If that is the case I'm not sure how to set it to two-way. The binding is set in XAML, and the ItemsSource is set later in code-behind:
<DataGrid Name="dataGridxyz" ItemsSource="{Binding}">
dataGridxyz.ItemsSource = foo;
Adding two-way binding in XAML using this syntax causes an error:
<DataGrid Name="dataGridxyz" ItemsSource="{Binding, Mode=TwoWay}">
So I was looking for something like this:
dataGridxyz.ItemsSource = foo;
dataGridxyz.Binding.Mode = TwoWay;
It may be that I could set it to two-way binding either in XAML or code-behind... but I can't see how to do either.
EDIT:
The following is minimal functional example to show the problem. It is a much-simplified version of the real thing which is part of a much bigger project.
When the button is clicked, the Name property is changed but it does not update in the PropertyGrid.
<Window x:Class="testBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow">
<Grid>
<StackPanel Orientation="Vertical">
<DataGrid Name="dg" ItemsSource="{Binding}" AutoGenerateColumns="True"/>
<Button Name="btn" Width="100" Height="20" Content="Test" Click="btn_Click"/>
</StackPanel>
</Grid>
namespace testBinding
{
public partial class MainWindow : Window
{
BindingList<foo> bar = new BindingList<foo>() { new foo() };
public MainWindow()
{
InitializeComponent();
dg.ItemsSource = bar;
}
private void btn_Click(object sender, RoutedEventArgs e)
{
bar[0].Name = "Paul";
}
}
class foo : genericClass, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
}
class genericClass : INotifyPropertyChanged
{
private string _name = "John";
public string EyeColor = "Blue";
public bool Child = false;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string Name
{
get { return _name; }
set
{
_name = value;
MessageBox.Show("Name changed!"); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
OnPropertyChanged("Name");
}
}
}
}
I figured out what was happening here through a combination of guesswork and trial and error. Thanks to those who commented.
It was not caused by one-way binding as I had originally surmised.
This problem was caused by the fact that the foo object in the example above inherits from another class (genericClass) and both implement INotifyPropertyChanged. It seems clear that the existence of the PropertyChanged event in the foo class prevents the DataGrid from updating. I had not expected this behavior since I know that the PropertyChanged event in the inherited class does fire and does update the Name property.
If I remove the PropertyChanged event from foo, then the name updates in the PropertyGrid as expected.
class foo : genericClass, INotifyPropertyChanged
{
//public event PropertyChangedEventHandler PropertyChanged;
}
It leaves me with the problem of how to handle property changes at more than one level of inheritance (i.e. both in a class and in one it inherits from, which seems a valid thing to do) ... but that is perhaps a different question.
This question already has answers here:
Issue with DependencyProperty binding
(3 answers)
Closed 4 years ago.
I would like to be able to bind complex model (many properties) to UserControl through DependencyProperty, and if model would be edited in UserControl I would like to see this edited information inside my binded model.
Example application: Model, UserControl (xaml + cs), MainWindow (xaml + cs). I have no ViewModel to simplify idea.
Model:
public class MyModel : INotifyPropertyChanged
{
private string _surname;
private string _name;
public string Name
{
get => _name;
set
{
_name = value;
OnPropertyChanged();
}
}
public string Surname
{
get => _surname;
set
{
_surname = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MyModelEditor.xaml (inside Grid):
<DockPanel>
<TextBox Text="{Binding MyModel.Name}"/>
<TextBox Text="{Binding MyModel.Surname}"/>
</DockPanel>
Also contains this line in UserControl root element:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
MyModelEditor.xaml.cs:
public partial class MyModelEditor : UserControl
{
public MyModel MyModel
{
get => (MyModel)GetValue(MyModelProperty);
set => SetValue(MyModelProperty, value);
}
public static readonly DependencyProperty MyModelProperty =
DependencyProperty.Register("MyModel", typeof(MyModel), typeof(MyModelEditor), new FrameworkPropertyMetadata(null));
public MyModelEditor()
{
InitializeComponent();
}
}
MainWindow.xaml (inside Grid):
<DockPanel>
<Button DockPanel.Dock="Bottom" Content="Press Me!" Click="ButtonBase_OnClick"/>
<controls:MyModelEditor MyModel="{Binding MyModel}"/>
</DockPanel>
MainWindow.xaml.cs:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private MyModel _myModel;
public MyModel MyModel
{
get => _myModel;
set
{
_myModel = value;
OnPropertyChanged();
}
}
public MainWindow()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
MessageBox.Show(MyModel?.Name);
}
}
My test scenario: type text in textbox, press button.
Current behavior: Message after pressing button is empty.
Expected behavior: Message after pressing button is same like in textbox.
I wold not like to bind to all properties separately, because in future I will have much more then two properties.
Why current approach does not work?
How can I achieve my goal?
You are apparently not using the UserControl instance as Binding source in your UserControl's XAML. One way to do this would be to set the Binding's RelativeSource:
<TextBox Text="{Binding MyModel.Name,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
However, you don't need a new dependency property at all for this purpose. Just bind the UserControl's DataContext to a MyModel instance, like
<controls:MyModelEditor DataContext="{Binding MyModel}"/>
The Bindings in the UserControl's XAML would automatically work with the MyModel object, like this:
<DockPanel>
<TextBox Text="{Binding Name}"/>
<TextBox Text="{Binding Surname}"/>
</DockPanel>
For both of your TextBox controls, you should define their Binding with a TwoWay mode (ms docs on binding modes). Which, basically, would assure that the data flow is working in both direction (i.e. from the view model into the view and the other way around):
<DockPanel>
<TextBox Text="{Binding MyModel.Name, Mode=TwoWay}"/>
<TextBox Text="{Binding MyModel.Surname, Mode=TwoWay}"/>
</DockPanel>
As a good practice, you should always explicitly define what is the mode of the the Binding (NOTE: by default it's OneWay TwoWay - how to know which is the default?).
Another tip would be to go ahead and use MvvmHelpers nuget (github project), which could spare you the time of implementing INotifyPropertyChanged. Besides, you shouldn't re-invent the wheel
EDIT: Fixes are in your GitHub repo
Two things to note here
You have not instantiated your ViewModel (i.e. MyModel), so it was always null
You don't need to create DependencyPropery every time you want to pass some information to your UserControl. You could simply bind the DataContext itself
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;
}
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}"/>
I have created blank C#/XAML Windows 8 application. Add simple XAML code:
<Page
x:Class="Blank.MainPage"
IsTabStop="false"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel
Margin="0,150"
HorizontalAlignment="Center">
<TextBlock
x:Name="xTitle"
Text="{Binding Title, Mode=TwoWay}"/>
<Button Content="Click me!" Click="OnClick" />
</StackPanel>
</Grid>
</Page>
And the simple code in C# part:
public sealed partial class MainPage
{
private readonly ViewModel m_viewModel;
public MainPage()
{
InitializeComponent();
m_viewModel = new ViewModel
{
Title = "Test1"
};
DataContext = m_viewModel;
}
private void OnClick(object sender, RoutedEventArgs e)
{
m_viewModel.Title = "Test2";
}
}
Now I want to implement ViewModel. I have two way:
Use Dependency Property
Implement INotifyPropertyChanged
For first approach it is:
public class ViewModel : DependencyObject
{
public string Title
{
get
{
return (string)GetValue(TitleProperty);
}
set
{
SetValue(TitleProperty, value);
}
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string)
, typeof(ViewModel)
, new PropertyMetadata(string.Empty));
}
For second it is:
public class ViewModel : INotifyPropertyChanged
{
private string m_title;
public string Title
{
get
{
return m_title;
}
set
{
m_title = value;
OnPropertyChanged("Title");
}
}
protected void OnPropertyChanged(string name)
{
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
I prefer the first way, because it allows use coerce (Silverlight for web and for WP7 doesn't have coerce functionality.. WinRT too.. but I'm still looking and hope) and looks more natural for me. But unfortunately, it works as OneTime for the first approach.
Could anybody explain to me why MS abandon using Dependency Property for implementing view model?
You should not be using a DependencyProperty in your ViewModel - you should only use them in your controls. You will never want to bind one ViewModel to another, also ViewModels do not need to persist their values nor provide default values, nor provide property metadata.
You should only use INotifyPropertyChanged in your ViewModels.