PropertyChanged remains null - c#

I have following textbox binding:
XAML:
<TextBlock x:Name="Auslastungskapazität1" Text="{Binding Kapazität, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="Black" HorizontalAlignment="Center" Margin="0,5,5,5" FontSize="16" ></TextBlock>
MainViewModel Class:
class MainViewModel: ZuliefererStandortListe, IDropTarget, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Kapazität {
get { return _kapazität1Ausgelastet; }
set {
if (this._kapazität1Ausgelastet != value)
_kapazität1Ausgelastet = value;
OnPropertyChanged("Kapazität");
}
}
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
DataContext is the in the MainWindow Constructor as
Kapazität.DataContext = new MainViewModel();
If I change Kapazität the int get changed and the OnPropertyChanged() method gets called. However "PropertyChanged" remains null and therefore the Textbox Binding doesn't get updated.

Either set the DataContext of the TextBox itself:
Auslastungskapazität1.DataContext = new MainViewModel();
...or of any of its parent elements, such as for example the window:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}

Related

Binding not updating from INotifyPropertyChanged class

I am new to WPF. I have binded the source class properties to target controls successfully. But whenever the properties value changes the UI controls not reflecting the updated data. Please help
WPF Code:
<Label Name="Panel_ch1Mode" Content="{Binding Path=Mode, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" FontFamily="Roboto Regular" FontSize="16" Foreground="#FFFFFF"/>
My Class:
public class ClassName: INotifyPropertyChanged
{
//Auto Refresh
private string mode;
public string Mode
{
get
{
return this.mode;
}
set
{
this.mode = value;
NotifyPropertyChanged("Mode");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Try this: Just remove from xaml the UpdateSourceTrigger=PropertyChanged, Mode=TwoWay. )
Improve your implementation of INotifyPropertyChanged linke this:
private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
In code behind please check if the ViewModel is "wired" to the View:
public YourView()
{
InitializeComponent();
DataContext = new ClassName();
}
You have to keep in mind that a binding is always related to DataContext.

Create a ViewModel with sub ViewModel

Is there a proper way to create a C#/WPF ViewModel containing subViewModel ?
Objective is:
I have a MainWindow. That window is use to read/create images. There is a button on that windows who switch between 2 UserControl one with IHM used to read image, the other one used to create.
The MainWindow has a MainWindowViewModel with :
command switch
image length
application parameters
I want that both UserControls can acces to MainWindowViewModel field/properties and have they own commands.
Construction will be something like this:
public partial class ReadUserControl : UserControl
{
public ReadUserControl()
{
InitializeComponent();
DataContext = MainViewModel.ReadViewModel;
}
}
public partial class CreateUserControl : UserControl
{
public CreateUserControl()
{
InitializeComponent();
DataContext = MainViewModel.CreateViewModel;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = MainViewModel;
}
}
For example, if a MainViewModel contain a field ImageWidth setting ImageWidth in CreateUserControl change the value for ReadUserControl.
I hope to have been clear, I don't know how design my MainViewModel to achieve this result
EDIT1:
I've created the MainWindowViewModel as a Singleton but i'm still unable to get MainViewModel.CreateViewModel and MainViewModel.ReadViewModel
public class MainWindowViewModel : ViewModelBase
{
private static MainWindowViewModel _instance = null;
public static MainWindowViewModel Instance
{
get
{
if (_instance == null)
_instance = new MainWindowViewModel();
return _instance;
}
}
private MainWindowViewModel()
: base()
{
}
#region CreateViewModel
/* How to create ? */
#endregion
#region ReadViewModel
/* How to create ? */
#endregion
}
Your example will work. At least if you have made your MainViewModel a Singleton.
A more professional approach might be an Constructor-Injection like this.
public partial class ReadUserControl : UserControl
{
public ReadUserControl(MainViewModel vm)
{
InitializeComponent();
DataContext = vm.ReadViewModel;
}
}
With such DependencyInjections you can achieve a higher level of abstraction, since your UserControls can be generalized. (They will all have the same Constructor)
On the other hand, you give every such UserControl the ability, to manipulate the MainViewModel, not aware of side-effects.
In your special case, it would be more safe, to pass only the needed parameters to the UserControl, instead of giving them a bunch of informations, they will never need.
public partial class ReadUserControl : UserControl
{
public ReadUserControl(Icommand command, int imageLength, AppParams appParams)
{
InitializeComponent();
...
// Do with your Constructorparameters what ever you have to
}
}
Edit:
Here a small, dumb implementation of how it could be done:
Code
public class MainViewModel : INotifyPropertyChanged {
private INotifyPropertyChanged _selectedViewModel;
public MainViewModel() {
var cmd = new RelayCommand(x => {
MessageBox.Show("HelloWorld");
}, x => true);
this.RVM = new ReadViewModel(cmd);
this.WVM = new WriteViewModel(cmd);
this.SelectedViewModel = WVM;
}
private ICommand _switchViewModelCommand;
public ICommand SwitchViewModelCommand => this._switchViewModelCommand ?? (this._switchViewModelCommand = new RelayCommand(x => {
if (this.SelectedViewModel == RVM) {
this.SelectedViewModel = WVM;
return;
}
this.SelectedViewModel = RVM;
}));
public INotifyPropertyChanged SelectedViewModel {
get {
return this._selectedViewModel;
}
set {
if (Equals(value, this._selectedViewModel))
return;
this._selectedViewModel = value;
this.OnPropertyChanged();
}
}
public ReadViewModel RVM {
get; set;
}
public WriteViewModel WVM {
get; set;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ReadViewModel : INotifyPropertyChanged {
public ReadViewModel(ICommand sayHelloCommand) {
this.HelloCommand = sayHelloCommand;
}
public ICommand HelloCommand {
get;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class WriteViewModel : INotifyPropertyChanged {
public WriteViewModel(ICommand sayHelloCommand) {
this.HelloCommand = sayHelloCommand;
}
public ICommand HelloCommand {
get;
}
public ICommand HelloMoonCommand => new RelayCommand(x => { MessageBox.Show("Hello Moon"); });
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid Height="200">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<ContentControl Content="{Binding SelectedViewModel, UpdateSourceTrigger=PropertyChanged}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ReadViewModel}">
<StackPanel>
<Button Content="Say Hello world" Command="{Binding HelloCommand}"></Button>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:WriteViewModel}">
<StackPanel>
<Button Content="Say Hello world" Command="{Binding HelloCommand}"></Button>
<Button Content="Say Hello Moon" Command="{Binding HelloMoonCommand}"></Button>
</StackPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
<Button Content="Switch VM" Command="{Binding SwitchViewModelCommand}" Grid.Row="1"/>
</Grid>
You can pass in the MainViewModel as DataContext for your user control and set the data context of elements as Read/Create model
something like
<Grid> <!--using MainWindowViewModel as data context-->
<Grid DataContext="{Binding Path=CreateViewModel}"> <!--using CreateViewModel as data context-->
.....
</Grid>
<Grid>

C# XAML Databinding has no effect when property is changed

Okay I've been wracking my brain a lot about this one, I'm missing something, I just can't figure out what. Ultimately I'm trying to set databinding so I can update values to be shown on the fly, but for the life of me, it's not working.
The XAML is:
<TextBox x:Name="textBox" HorizontalAlignment="Left"
Height="37" Margin="85,38,0,0" TextWrapping="Wrap"
Text="{Binding Path=TBBind}" VerticalAlignment="Top"
Width="121" />
Note that I have the {Binding Path=TBBind} set.
The code behind is:
using System.ComponentModel;
using System.Windows;
namespace Databinding_Practice_2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
TBBind = "test";
}
private string _tBBind;
public string TBBind
{
get { return _tBBind; }
set
{
if (value != _tBBind)
{
_tBBind = value;
OnPropertyChanged("TBBind");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
MessageBox.Show("OnPropertyChanged triggered");
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
Help me obi-w.... oh wait, help me anyone!
Assuming that you are trying to use the MVVM pattern (which stands for Model-View-ViewModel):
Your MainWindow is the View.
You should create another class to be the View Model, like this:
public class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
TBBind = "test";
}
private string _tBBind;
public string TBBind
{
get { return _tBBind; }
set
{
if (value != _tBBind)
{
_tBBind = value;
OnPropertyChanged("TBBind");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string property)
{
MessageBox.Show("OnPropertyChanged triggered");
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
Your MainWindow code behind will become like this after removing all ViewModel related stuff to the MainWindowViewModel class:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
Now, you should link the View with the ViewModel, there are many ways to do this. Here is one of them:
In the XAML of MainWindow, have the following inside the Window element:
<Window.DataContext>
<wpfApplication5:MainWindowViewModel />
</Window.DataContext>
<Grid>
<TextBox x:Name="textBox" HorizontalAlignment="Left" Height="37" Margin="85,38,0,0" TextWrapping="Wrap" Text="{Binding TBBind}" VerticalAlignment="Top" Width="121" />
</Grid>
Please note that WpfApplication5 is the name of the namespace in my WPF project. This will probably be different in your case.
Try:
public MainWindow()
{
InitializeComponent();
DataContext = this;
TBBind = "test";
}
The difference here sets the critical DataContext property. This is the cornerstone of the MVVM pattern, which you are implementing here. You should consider separating the View Model responsibility into another class, and then setting the View's DataContext to an instance of that class, but the approach you have taken here works for simple cases.

WPF data binding with inner elements

I want to bind my StackPanel component to an object and its properties to elements it the StackPanel
<StackPanel Grid.Column="0" Grid.Row="0" Name="device1" Background="#CC119EDA" DataContext="{Binding}">
<Label FontSize="22" Foreground="White">Desk #1</Label>
<TextBox Text="{Binding Name}" />
</StackPanel>
In code behind
device1.DataContext = new Class { Name = "Name" };
What is wrong with this binding? Thanks
You could try like this. When u set the property to the Object , the UI Thread is not aware of the change , so you need to Implement RaisePropertyChange Mechanism. Using MvvmLight Toolkit is great advantage . Here the window datacontext is set to so could inherit all elements.
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string _name;
public string MyName
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("MyName");
}
}
public MainWindow()
{
InitializeComponent();
MyName = "Eldho";
this.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Xaml
<StackPanel>
<Label>Hi,</Label>
<TextBox Text="{Binding MyName}"/>
</StackPanel>

TextBox text Binding

I have a LineSeries to which I am binding the data from an ObservableCollection of the type ChartData. Now, In my UI, I have a TextBox in which I need to show the Y value of the series. How do I bind the Value property to the TextBox
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObservableCollection<ChartData> lineSeries1Data = new ObservableCollection<ChartData>();
simChart.DataContext = lineSeries1Data;
}
public class ChartData : INotifyPropertyChanged
{
DateTime _Name;
double _Value;
public DateTime Name
{
get
{
return _Name;
}
set
{
_Name = value;
OnPropertyChanged("Name");
}
}
public double Value
{
get
{
return _Value;
}
set
{
_Value = value;
OnPropertyChanged("Value");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
This is my XAML for the TextBox:
<TextBox Name="TxtSignal1Vh1" DataContext="lineSeries1Data" Text="{Binding ChartData.Value}" />
Here is some Working Code,Create a Usercontrol consisting of Chart+textboxes and then binds its Datacontext to respective observable collection.
public MainWindow()
{
InitializeComponent();
observableCollection<DataChart>1st=new observableCollection<DataChart>();
observableCollection<DataChart>2nd=new observableCollection<DataChart>();
win.DataContext = (1st Observable Collection)
lose.DataContext=(2nd Observable Collection)
}
MainWindows xaml
<Grid>
<this:UserControl1 x:Name="win" Margin="10,21,325,144"/>
<this:UserControl1 x:Name="lose" Margin="275,21,10,144"/>
</Grid>
UserControl xaml
<Grid>
<TextBox Text="{Binding Path=Value}" VerticalAlignment="Top" Width="164"/>
<TextBox Text="{Binding Path=Name}" VerticalAlignment="Top" Width="164"/>
</Grid>

Categories