How to make logs - c#

To explain a little more, I have a Main Form which contains a large list of jobs.
Every item in the list is a instance of my class called Jobs.
When an item is clicked, another Form is opening, in which user can edit information of selected job. I pass a job object from Main Form to details Form and edit it through TextBoxes, ComboBoxes and so on.
Now I need to detect which properties of jobs have changed and write it in log file. I know how to write to log file, but I dont know how to detect which properties have changed.
I could go and write 30 if statements in which I would compare starting point with ending point but I have 30 properties and it would be a complete mess.
Any ideas?

Take a look at INotifyPropertyChanged:https://learn.microsoft.com/en-us/dotnet/framework/winforms/how-to-implement-the-inotifypropertychanged-interface
Example
using log4net;
using System.ComponentModel;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(Form1).FullName);
public PersonViewPresenter Presenter { get; private set; }
public Form1()
{
InitializeComponent();
Presenter = new PersonViewPresenter();
Presenter.PropertyChanged += Presenter_PropertyChanged;
AddBindings();
}
private void Presenter_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Logger.Info($"Property changed {e.PropertyName}");
}
private void AddBindings()
{
_firstnameTextbox.DataBindings.Add(new Binding(nameof(_firstnameTextbox.Text), Presenter, nameof(Presenter.FirstName), false, DataSourceUpdateMode.OnValidation));
_lastnameTextBox.DataBindings.Add(new Binding(nameof(_lastnameTextBox.Text), Presenter, nameof(Presenter.LastName), false, DataSourceUpdateMode.OnValidation));
}
}
}
ViewPresenter implementation
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WindowsFormsApp1
{
public class PersonViewPresenter : ViewPresenterBase
{
private string _lastName;
private string _firstName;
public string FirstName
{
get => _firstName; set
{
if (_firstName != value)
{
_firstName = value;
NotifyPropertyChanged();
}
}
}
public string LastName
{
get => _lastName; set
{
if (_lastName != value)
{
_lastName = value;
NotifyPropertyChanged();
}
}
}
}
public abstract class ViewPresenterBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Related

Simplifying ViewModel properties in an MVVM design

I am new to MVVM, and I believe I have successfully built an MVVM app to appreciate it. I soon realised that I could not have properties like below to fire notifications:
public string Status { get; set; }
public bool IsIdle { get; set; }
public ObservableCollection<SpecifiedRecord> FilesCollection { get; set; }
I had to rewrite them as below:
private string _status;
public string Status
{
get { return _status; }
set
{
_status = value;
OnPropertyChanged(nameof(Status));
}
}
private bool _isIdle;
public bool IsIdle
{
get { return _isIdle; }
set
{
_isIdle = value;
OnPropertyChanged(nameof(IsIdle));
}
}
private ObservableCollection<SpecifiedRecord> filesColl = new ObservableCollection<SpecifiedRecord>();
public ObservableCollection<SpecifiedRecord> FilesCollection
{
get { return filesColl; }
set
{
if (value != this.filesColl)
filesColl = value;
OnPropertyChanged(nameof(FilesCollection));
}
}
MVVM has been there for nearly 9 years, and I thought in this day and age, Microsoft would allow OnPropertyChanged events to fire automatically i.e. built-in to Net without us having to write it everytime because if I find it very inefficient to do so.
Alternatively, is there a more simplified way to achieve the same by way of an inherited class?
Sources:
https://github.com/mainroads/SpecifiedRecordsExporter/blob/mvvm/SpecifiedRecordsExporter/MVVM/ViewModels/MainPageViewModel.cs
https://github.com/mainroads/SpecifiedRecordsExporter/blob/mvvm/SpecifiedRecordsExporter/MVVM/ViewModels/ViewModelBase.cs
Thanks,
Michael
You can simplify the PropertyChangedEventHandler alot using the CallerMemberName attribute and using an Inherited Class
public class Core : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void PropChanged([CallerMemberName] string callerName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(callerName));
}
}
Then you use it like so after adding : Core to your class
public class Program : Core
{
private bool _isIdle;
public bool IsIdle
{
get
{
return _isIdle;
}
set
{
//if (_isIdle != value)
//{
_isIdle = value;
PropChanged();
//} reduce number of events (comments)
}
}
}
You can also specify the Caller Name manually to trigger an update for a different property.
This is the most modern way of doing this that I know of, The extra bonus here is you can also use the Core class for anything Static
There's no need anymore for all that boilerplate code.
Using the Source Generators from the MVVM Community Toolkit you can inherit from ObservableObject and then write your properties like this:
public partial class MyViewModel : ObservableObject
{
[ObservableProperty]
string name;
}
This will be used to generate a class that looks similar to this under the hood:
partial class MyViewModel
{
public string Name
{
get => name;
set
{
if(name.Equals(value)) return;
OnPropertyChanging();
name = value;
OnPropertyChanged();
}
}
}
You can also raise notifications for other properties and have commands auto-generated, too:
public partial class MyViewModel : ObservableObject
{
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName)]
string firstName;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName)]
string lastName;
public string FullName => $"{FirstName} {LastName}";
[RelayCommand]
private void SayHello()
{
Console.WriteLine($"Hello, {FullName}!");
}
}
Note that the backing fields for auto-generated properties must be lowercase, because the generator will create the properties beginning with an uppercase letter.
Commands will have the same name as the method with the "Command" suffix, so SayHello() becomes SayHelloCommand. In case of an async method, e.g. async Task SayHelloAsync(), the Command will still be called SayHelloCommmand, without the "Async" suffix.
I've also written a blog series going into more detail about this.

MVVM how to get notify event for a nested class object

Hi I know that there a posts about this topic, but I could not solve my problems with them.
I want to understand and learn a simple way to get a ViewModelBase that I can subcribe to in my View so that a UI Refresh is forced.
I have written an windows console example. The structure is Class Customer(string Name, MyAddress Address) where MyAddress is a Class(string StreetName). In Main I have a list of customers. Now I want to get a message every time there is a change in the list or in the property of the customer including a change of the streetname.
I cant get that to work. If I change the name of the customer it works but not for the 'nest' address. If I change StreetName I dont get a notify Event. I don't know how to subcribe to the ViewModelBase for all the customers in the list.
The Console Progam can be copy/paste in VisulaStudio and runs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace CS_MVVM_NotifyFromNestedClass
{
class Program
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetValue<T>(ref T backingFiled, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(backingFiled, value)) return;
backingFiled = value;
OnPropertyChanged(propertyName);
}
}
public class Customer : ViewModelBase
{
private string _name;
public string Name
{
get => _name;
set { SetValue(ref _name, value); }
}
public MyAddress Address { get; set; }
public Customer(string name, MyAddress address)
{
Name = name;
Address = address;
}
}
public class MyAddress : ViewModelBase
{
private string _street;
public string Street
{
get => _street;
set { SetValue(ref _street, value); }
}
public MyAddress(string street)
{
Street = street;
}
}
public static BindingList<Customer> MyCustomers = new BindingList<Customer>
{
new Customer("John", new MyAddress("JoStreet")),
new Customer("Susi", new MyAddress("SeaStreet")),
};
static void Main(string[] args)
{
//BindingList Event
MyCustomers.ListChanged += OnBindingListChanged;
// 1) Change Name <-- THIS FIRES THE 'OnBindingListChanged' EVENT
MyCustomers[0].Name = "Rick";
// 2) Change Street <-- THIS DOESN'T FIRE A CHANGE-EVENT
MyCustomers[0].Address.Street = "Rockyroad";
//I dont know how to hook up the 'property change event' from ViewModelBase for all obj. of MyCustomer-List
//MyCustomers[0].Address.PropertyChanged += OnSingleObjPropChanged; // <--doesn't work
Console.ReadLine();
}
private static void OnBindingListChanged(object sender, ListChangedEventArgs e)
{
Console.WriteLine("1) BindingList was changed");
foreach (var c in MyCustomers)
{
Console.WriteLine($"{c.Name} {c.Address.Street}");
}
}
private static void OnSingleObjPropChanged(object sender, PropertyChangedEventArgs e)
{
//Never reached --> how to 'hook'
Console.WriteLine("2) Property of List Item was changed");
foreach (var c in MyCustomers)
{
Console.WriteLine($"{c.Name} {c.Address.Street}");
}
}
}
}
First Edit: inner BindingList in the CustomerClass plus the ViewModelBase #Karoshee
I did leave the MyAdresse thing out to simplify. I added a BindingList 'MyTelNrs' to my CustomerClass and subcribt to the ListChanged Event. I didn't change the ViewModelBase from the execpted answere. I do get a notification in my UI, but I don't know if I'am doing it in a save/right way. Just to let the following readers know ... (maybe someone that is better then me answeres, if the below way is 'okay')
public class Customer: ViewModelBase
{
private string _name;
public string Name
{
get => _name;
set => SetValue(ref _name, value);
}
public BindingList<string> MyTelNrs = new();
private void OnLstChanged(object sender, ListChangedEventArgs e)
{
OnPropertyChanged(nameof(MyTelNrs));
}
public Customer(string name, BindingList<string> myTelNrs)
{
Name = name;
MyTelNrs = myTelNrs;
MyTelNrs.ListChanged += OnLstChanged;
}
}
First of all need to make Address property a notify property:
public MyAddress Address
{
get => _address;
set
{
SetValue(ref _address, value);
}
}
Than you need to add some additional logic into ViewModelBase, something like this:
public class ViewModelBase : INotifyPropertyChanged, IDisposable
{
/// <summary>
/// All child property values and names, that subscribed to PropertyChanged
/// </summary>
protected Dictionary<ViewModelBase, string> nestedProperties
= new Dictionary<ViewModelBase, string>();
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetValue<T>(ref T backingFiled, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(backingFiled, value)) return;
if (backingFiled is ViewModelBase viewModel)
{ // if old value is ViewModel, than we assume that it was subscribed,
// so - unsubscribe it
viewModel.PropertyChanged -= ChildViewModelChanged;
nestedProperties.Remove(viewModel);
}
if (value is ViewModelBase valueViewModel)
{
// if new value is ViewModel, than we must subscribe it on PropertyChanged
// and add it into subscribe dictionary
valueViewModel.PropertyChanged += ChildViewModelChanged;
nestedProperties.Add(valueViewModel, propertyName);
}
backingFiled = value;
OnPropertyChanged(propertyName);
}
private void ChildViewModelChanged(object? sender, PropertyChangedEventArgs e)
{
// this is child property name,
// need to get parent property name from dictionary
string propertyName = e.PropertyName;
if (sender is ViewModelBase viewModel)
{
propertyName = nestedProperties[viewModel];
}
// Rise parent PropertyChanged with parent property name
OnPropertyChanged(propertyName);
}
public void Dispose()
{ // need to make sure that we unsubscibed
foreach (ViewModelBase viewModel in nestedProperties.Keys)
{
viewModel.PropertyChanged -= ChildViewModelChanged;
viewModel.Dispose();
}
}
}
As I know this does not contradict the MVVM, the only issue with subscribing/unsubscribing child property changed.
Updated:
I added few changes and comments in code below.
The key thing here, that you need to subscribe to PropertyChanged of child properties that inherited from ViewModelBase.
But subscribing is a half way throught: you need to make sure that you unsubscribe it, when objects does not need anymore, so it's has to be stored in nestedProperties.
Also we need to replace child property name from ChildViewModelChanged with parent property name to rise PropertyChange event on parent object. For that goal I saved property name with property value than subscribed on ChildViewModelChanged, this is why I use Dictionary type in nestedProperties
Also important thing to unsubscribe all ProperyChanged, when object no longer needed. I added IDisposable interface and Dispose method to do that thing. Dispose method also needs to be rised (with using or manualy), in your case perhaps will be better to make own BindingList with IDisposable, that rise Dispose on all items.

Bind text field to a value that is fetched from a REST Api using Xamarin

I've started a Xamarin project using the template that is available in Visual Studio.
I wrote some services that fetches data from REST api. I have printed these values to the console and I am able to see that the services work like they should.
However I have troubles displaying the name of a user that I fetched from the Api.
I'm trying to do this in a ViewModel class.
using MyApp.Models;
using System;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;
using MyApp.Services;
using System.Threading.Tasks;
namespace MyApp.ViewModels
{
public class AboutViewModel : BaseViewModel
{
static readonly UserService CurrentUser = new UserService();
public AboutViewModel()
{
//GetData().Wait();
Title = "My App";
OpenWebCommand = new Command(async () => await Browser.OpenAsync("https://aka.ms/xamain-quickstart"));
IsConnected = false;
GetData();
}
protected async void GetData()
{
user = await CurrentUser.GetUser();
Name = user.fullName;
}
public ICommand OpenWebCommand { get; }
public bool IsConnected { get; set; }
public string Name { get; set; }
public User user { get; set; }
}
}
This is the line from the .xaml file where it would be displayed:
<Label Text="{Binding Name}" FontSize="Title"/>
I know this is bad practice but I tried to hack it into working. It still doesn't work, and it displays nothing. It's the only thing I've managed so far that doesn't crash or make the app freeze. How bind to the variable "Name", when "Name" will eventually be set from an async void or task?
Your BaseViewModel should probably implement the INotifyPropertyChanged interface or inherit from a class that already implements it, if you are using a MVVM framwork of sorts.
This could look something like:
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetProperty<T>(ref T backingField, T newValue, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(backingField, newValue))
{
return false;
}
backingField = newValue;
RaisePropertyChanged(propertyName);
return true;
}
}
Then for your properties in your ViewModel you could use SetProperty to ensure PropertyChanged is fired when their values change. This is needed for the UI they are bound to, to figure out that something changed.
private string _name;
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
If you don't want to use SetProperty simply use RaisePropertyChanged:
private string _name;
public string Name
{
get => _name;
set
{
_name = value;
RaisePropertyChanged();
}
}

Changing protection level of newly created object?

Alright, so I have luck of running into a lot of basic problems. I can't figure a way around this particular issue.
This piece of code needs to access "_Player.Name" property of object created in "MainWindow" class.
Edit: Putting up the whole code this time. Here's the Code_Behind where the string is.
public class Code_Behind
{
private static string _Name = "Default";
public class Player
{
public void setName(string name) //Ignore this part, was trying to find a work around here
{
_Name = name;
}
public string Name
{
get { return _Name; }
set
{
_Name = value;
}
}
}
//contentControl is used to store Content properties
//UI elements are bound to Content properties to efficiently change their Content
public class contentControl : INotifyPropertyChanged
{
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public void setEvent(string Event)
{
textBoxContent = Event;
}
public void addEvent(string Event)
{
textBoxContent +="\n" + Event;
}
public class Events
{
public string EV001 = String.Format("\"Greetings {0}. What can I do for you today?\"", window.PlayerName);
}
}
And here is the MainWindow one:
public partial class MainWindow : Window
{
Code_Behind.contentControl cC = new Code_Behind.contentControl();
Code_Behind.contentControl.Events Events = new Code_Behind.contentControl.Events();
Code_Behind.Player _Player = new Code_Behind.Player();
public string GetPlayerName()
{
return _Player.Name;
}
public static string _name = "null";
public MainWindow()
{
this.DataContext = cC;
InitializeComponent();
}
public string GetPlayerName()
{
return _Player.Name
}
Create a method in your MainWindow class. After that you call this method.
public string EV001 = String.Format("\"Greetings {0}. What can I do for you today?\"",
window.GetPlayerName());
You can do it with property too if you want.
public string PlayerName
{
get { return _Player.Name; };
}
The bigger problem you have here is not about accessibility, but not understanding the difference between a class and an object.
MainWindow is a class. It does not represent any specific window. Think of a class like a recipe to create objects. If you had a chocolate chip cookie recipe, you don't eat the recipe, you eat a specific cookie or cookies baked following that recipe.
Your other class first needs to know which specific window you are trying to get the player name from. It needs a reference to a particular MainWindow object.
It looks like you're trying write something like a viewmodel: You've got a player, he has a name, and there's a collection of strings that you think of as "events". I don't understand what the "events" are meant to be, but I implemented my best guess at what I think you seem to be trying to do.
As for this:
public class Events
{
public string EV001 = String.Format("\"Greetings {0}. What can I do for you today?\"", window.PlayerName);
}
I guess you created an instance of MainWindow somewhere, and called it window, but it's defined someplace where it's "out of scope" for that line of code. By analogy, you can't see anything that's behind the next hill, only stuff that's in the valley you're standing in. That's roughly (very roughly, sorry) kind of what scope is about.
But let's move on to my guess at what you're trying to do. This builds, runs, and works. Any questions at all, fire away.
ViewModels.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Player
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public class MainViewModel : ViewModelBase
{
#region Player Property
private PlayerViewModel _player = default(PlayerViewModel);
public PlayerViewModel Player
{
get { return _player; }
set
{
if (value != _player)
{
_player = value;
OnPropertyChanged(nameof(Player));
// Change the player for all the existing events.
foreach (var e in Events)
{
e.Player = Player;
}
}
}
}
#endregion Player Property
private ObservableCollection<Event> _events = new ObservableCollection<Event>();
public ObservableCollection<Event> Events
{
get { return _events; }
private set
{
if (value != _events)
{
_events = value;
OnPropertyChanged(nameof(Events));
}
}
}
#region Event Methods
// This is a BIG guess as to what you're trying to do.
public void AddGreeting()
{
// Player is "in scope" because Player is a property of this class.
if (Player == null)
{
throw new Exception("Player is null. You can't greet a player who's not there.");
}
Events.Add(new Event("\"Greetings {0}. What can I do for you today?\"", Player));
}
#endregion Event Methods
}
public class Employee : ViewModelBase
{
#region DisplayLtdOccupationId Property
private bool _displayLtdOccupationId = default(bool);
public bool DisplayLtdOccupationId
{
get { return _displayLtdOccupationId; }
set
{
if (value != _displayLtdOccupationId)
{
_displayLtdOccupationId = value;
OnPropertyChanged(nameof(DisplayLtdOccupationId));
}
}
}
#endregion DisplayLtdOccupationId Property
}
public class Event : ViewModelBase
{
public Event(String format, PlayerViewModel player)
{
_format = format;
Player = player;
}
private String _format = "";
public String Message
{
get { return String.Format(_format, Player.Name); }
}
#region Player Property
private PlayerViewModel _player = default(PlayerViewModel);
public PlayerViewModel Player
{
get { return _player; }
set
{
if (value != _player)
{
_player = value;
OnPropertyChanged(nameof(Player));
// When player changes, his name changes, so that
// means the value of Message will change.
OnPropertyChanged(nameof(Message));
if (_player != null)
{
_player.PropertyChanged += _player_PropertyChanged;
}
}
}
}
private void _player_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(PlayerViewModel.Name):
OnPropertyChanged(nameof(Message));
break;
}
}
#endregion Player Property
}
public class PlayerViewModel : ViewModelBase
{
private String _name = default(String);
public String Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
OnPropertyChanged(nameof(Name));
}
}
}
}
}
MainWindow.xaml.cs
using System.Windows;
namespace Player
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel = new MainViewModel();
ViewModel.Player = new PlayerViewModel() { Name = "Ivan the Terrible" };
}
// Just here as a convenience, and to make sure we don't give the DataContext
// the wrong kind of viewmodel.
public MainViewModel ViewModel
{
set { DataContext = value; }
get { return DataContext as MainViewModel; }
}
private void Greeting_Click(object sender, RoutedEventArgs e)
{
ViewModel.AddGreeting();
}
}
}
MainWindow.xaml
<Window
x:Class="Player.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"
xmlns:local="clr-namespace:Player"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation="Vertical">
<WrapPanel>
<Button x:Name="Greeting" Content="Greeting" Click="Greeting_Click" />
<Label>Name: </Label>
<TextBox Text="{Binding Player.Name}" Width="120" />
</WrapPanel>
<ListBox
ItemsSource="{Binding Events}"
DisplayMemberPath="Message"
>
</ListBox>
</StackPanel>
</Grid>
</Window>
You can change the set of Name to be private, but still allow the outside world to read the property with the get.
public string Name { get; private set; } = "Default";
This should give you the functionallity desired without the need to create a new GetName() method.

Has the DataSource been changed via a BindingSource?

I'm using a BindingSource to connect a single large data-structure to numerous controls (no SQL, just one data-structure, lots of controls). Old-style Windows Forms application, Visual Studio 2012 Express. I have managed to wrap numerous GUI components with properties to work around the lack of direct support for control binding of things like radio button groups, multi-select listboxes, the title bar, etc. All this works great, updates flow nicely in both directions between the GUI and the data-structure.
I need to track if any changes to the data-structure have been made via any control on the GUI, but I can't see how to do this (I did look at previous related questions here)... This is needed to provide a simple indication of "changes made but not saved", with an asterisk in the title bar and a warning if the user tries to exit the application without saving changes.
Thanks in advance for any help !
You'll have to implement the INotifyPropertyChanged interface from within your object classes, then catch whenever a change occurs through proper event handlers for your type class within your DataSource BindingSource property.
Here's an example:
using System;
using System.ComponentModel;
namespace ConsoleApplication1
{
internal class Program
{
class Notifications
{
static void Main(string[] args)
{
var daveNadler = new Person {Name = "Dave"};
daveNadler.PropertyChanged += PersonChanged;
}
static void PersonChanged(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine("Something changed!");
Console.WriteLine(e.PropertyName);
}
}
}
public class Person : INotifyPropertyChanged
{
private string _name = string.Empty;
private string _lastName = string.Empty;
private string _address = string.Empty;
public string Name
{
get { return this._name; }
set
{
this._name = value;
NotifyPropertyChanged("Name");
}
}
public string LastName
{
get { return this._lastName; }
set
{
this._lastName = value;
NotifyPropertyChanged("LastName");
}
}
public string Address
{
get { return this._address; }
set
{
this._address = value;
NotifyPropertyChanged("Address");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
}

Categories

Resources