I'm sure this is a very basic question but I don't even know the technical term / jargon to Google and self-educate on.
I have created a simple model implementing INotifyPropertyChanged.
public class PushNotes : INotifyPropertyChanged
{
public string CompletePushNotes { get; set; }
}
Binding in cs:
evt_pushNotes = new PushNotes()
{
CompletePushNotes = "HelloThere"
};
this.DataContext = evt_pushNotes;
//snip later in code
Helpers.UpdateCompletePushNotes();
In XAML:
<xctk:RichTextBox x:Name="PushEmail" Text="{Binding Path=CompletePushNotes, Mode=OneWay}" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="40,398,40,40">
<xctk:RichTextBox.TextFormatter>
<xctk:PlainTextFormatter />
</xctk:RichTextBox.TextFormatter>
</xctk:RichTextBox>
Helper:
internal static class Helpers
{
internal static void UpdateCompletePushNotes()
{
//duhhhh what do I do now??
//If I create a new PushNotes it will be a different instantiation....???
}
}
Now this is all fine but I have a method in a helper class that needs to change the CompletePushNotes.
Again I know this is a simplistic / newbie question but I don't know what I need to learn.
So do I make my PushNotes class static, or singleton. Is there some global binding "tree" I can walk to find my instantiated and bound PushNotes class that is attached to the UI element?
Not looking for an a handout just need to know what it is I'm looking for.
TIA
Your PushNotes class does not implement the INotifyPropertyChanged interface. Once you have implemented it, you need to modify your CompletePushNotes property to have a backing field and in the setter of the property you can raise the PropertyChanged event to notify the UI of the source property update.
public class PushNotes : INotifyPropertyChanged
{
string completePushNotes;
public string CompletePushNotes
{
get
{
return completePushNotes;
}
set
{
completePushNotes = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Making the PushNotes class static will not help you. You seem to have a variable of some sort to the PushNotes instance (evt_pushNotes), so just do:
evt_pushNotes.CompletePushNotes = something;
If you have a helper class that does something, call the method in the helper class and get the value back or pass the PushNotes instance into the helper class as a parameter.
internal static class Helpers
{
internal static void UpdateCompletePushNotes(PushNotes pushNotes)
{
pushNotes.CompletePushNotes = something;
}
}
Related
There are some similar questions on SO, but they weren't quiet the same, so I'm posting this instead. I'm new to MVVM, so I'm trying to figure out how I can create a class that can hold properties that can be shared among views. So, if I set a property in one view, all the other views would get notified if its changed and would adjust their properties accordingly.
What I have now is rather very crude and is definitely not something I want to use. This is my common class that will hold all the properties:
public static class Common
{
private static string _title;
public static string Title
{
get { return _title; }
set
{
if (_title == value)
{
return;
}
_title = value;
OnPropertyChanged("Title");
}
}
public static void Load()
{
// set properties here
}
public static event PropertyChangedEventHandler PropertyChanged;
private static void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(typeof(SettingsWorker), new PropertyChangedEventArgs(name));
}
}
}
...and I have to subscribe to it from each ViewModel:
Common.PropertyChanged += Common_PropertyChanged;
private void Common_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Title = Common.Title;
}
But this is where the breakdown happens. I can get the property name from the PropertyChangedEventArgs, but I've no idea how to get the value. Therefore, I'm forced to update all the properties, and that can get nasty to maintain. The code is becoming a mess.
I'm basically trying to get properties that ViewModels can share. How can I accomplish this?
It looks like you just have some global data you want to show in multiple places. The most straightforward way to do this is to just make it like and normal ViewModel class and then make it available to each of your other ViewModels and expose it from them to bind to directly (rather than copying the property into each of them). You can do this using IOC, or make it available statically, more similar to how you have it now.
If you go the static direction, the key change you need to make is to use a singleton rather than a static class in order to allow property change notification to work. Bindings work with INPC on instances but not static classes. The Common class would look more like this:
public class Common : INotifyPropertyChanged
{
private static Common _instance = null;
protected Common()
{
}
public static Common GetInstance()
{
if (_instance == null)
_instance = new Common();
return _instance;
}
private string _title;
public string Title
{
get { return _title; }
set
{
if (_title == value)
return;
_title = value;
OnPropertyChanged("Title");
}
}
public void Load()
{
}
public virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventArgs ea = new PropertyChangedEventArgs(propertyName);
if (PropertyChanged != null)
PropertyChanged(this, ea);
}
public event PropertyChangedEventHandler PropertyChanged;
}
There are a lot of different ways you can then use this. Here's one of the more direct ones:
public class SomeViewModel : ViewModelBase
{
public Common CommonData { get; private set; }
public SomeViewModel()
{
CommonData = Common.GetInstance();
}
}
Then in XAML you can bind to the properties from the common class and get change notification, even across the different VM usages.
<TextBox Text="{Binding Path=CommonData.Title}"/>
There's also the option of making the singleton accessible as a property and binding to it directly from XAML using x:Static but that's a little different direction that what you were asking.
So if you have other views that want to get notified when a property changes I would assume you have a separate viewmodel for each of those views. In that case what you would be asking for is "How can viewmodels talk to other viewmodels?" For a good learning experience, I would recommend looking into the observer pattern. If you don't like that style, then I would recommend you look into using a MVVM Framework like "SimpleMVVM, Catel, or many others" (Just need to look some up). Then once you have that framework in you project, I would create a baseviewmodel class that all your viewmodels will inherit. Once that is done you can take advantage of the frameworks messenger system. Basically it would look something like:
public YourViewModel()
{
RegisterToReceiveMessages(MessageTokens.SomeToken, OnChangeCallYourMethodToAddress); //The MessageTokens is something you generally create ur self.
}
#region Notifications
void OnChangeCallYourMethodToAddress(object sender, NotificationEventArgs<SlideShowLocale> e)
{
SomeProperty = e.Data;
}
Then to send a message to "YourViewModel" From another ViewModel:
public AnotherViewModel
{
SendMessage(MessageTokens.SomeToken, new NotificationEventArgs(WhateverYouWantToSend));
}
So basically, by declaring the token you want, it then finds the viewmodel that is registered with that token and listens for any messages to come in.
I have a class Application that I need to override with INotifyPropertyChanged events. I have written the logic to override the original class and ended up creating SuperApplication
I am pulling the data from a library though, and cannot change the loading logic. I just need a way to get the data from the original class into my superClass. I've tried things like superClass = (SuperApplication)standardClass; but it hasn't worked.
How would I go about doing this?
If it helps, this is the code I'm using to override the original class:
public class SuperCreditApplication : CreditApplication
{
public SuperCreditApplicant Applicant { get; set; }
public SuperCreditApplicant CoApplicant { get; set; }
}
public class SuperCreditApplicant : CreditApplicant
{
public SuperProspect Prospect { get; set; }
}
public class SuperProspect : Prospect, INotifyPropertyChanged
{
public State DriverLicenseState
{
get
{
return DriverLicenseState;
}
set
{
DriverLicenseState = value;
OnPropertyChanged("DriverLicenseState");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
It sounds like you should use a copy constructor, passing in "the data from the original class" as a parameter to a newly-constructed superClass (Incidentally, I think the name Super- is probably a mistake, as that will make people think that it's above the original in the hierarchy).
By copy-constructor, I mean something like:
class IWishIWasntCalledSuperApplication : Application
{
IWishIWasntCalledSuperApplication(Application original)
{
this.someData = original.someData;
this.someOtherData = original.someOtherData;
...etc...
}
}
I assume that you can't just implement INotifyPropertyChanged directly on Prospect. If you cannot directly change Prospect (like make all your properties virtual), you can make your SuperProspect class a wrapper for Prospect
public class SuperProspect : INotifyPropertyChanged
{
private readonly Prospect _prospect;
public SuperProspect(Prospect prospect)
{
_prospect = prospect;
}
public State DriverLicenseState
{
get { return _prospect.DriverLicenseState; }
set
{
_prospect.DriverLicenseState = value;
OnPropertyChanged("DriverLicenseState");
}
}
public void SomeMethod()
{
_prospect.SomeMethod();
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You can then use SuperProspect like this
var superProspect = new SuperProspect(myProspect);
If you create an interface for your Prospect members, then you can make both your SuperProspect and your Prospect implement the same interface. If you then program to the interface rather than the concrete Prospect implementation, your code will work with both SuperProspect and/or Prospect.
You didn't say whether the load was during the construction of the object or a later method call. Depending on which, it would look like one of these two code samples.
//This constructor signature should match your base class's
public SuperCreditApplication(object a, object b, object c) : base(a,b,c)
{
//Do whatever you need to do here. The base object's constructor will be called for you
}
public Load()
{
this.BaseObjectLoadMethod();
}
Then you make a new SuperCreditApplication and work with that.
Given your comment and edit I need to give a new answer lol - i misunderstood
you need to use interception to add the event handlers to the properties over which you have no control maybe. Personally I ahve seen this done with IoC containers such as prism. I may be completley wrong here btw but i think MEF may also help
Another way would be to look into code generation using T4 templates to reflect over the existing class to generate your superclass and the properties that map onto 4existing that would contain the code to fire the events.
this looks like it
http://lostechies.com/derekgreer/2009/03/01/implementing-inotifyproperychanged-with/
To explain the MEF thing: I am pretty sure i have seen INotifyPropertyChanged hooked up using MEF in various silverlight examples. I wasn't interested in that aspect when i was reading though so didn't read up on it.
Extracting an interface and using an ioc container to do all the heavy lifting would be the shortest route i imagine.
I don't know if this is possible or not, but here is the code to explain the question in the title:
public class LogicClass : INotifyPropertyChanged
{
private String _myText;
public String MyText
{
get{return _myText;}
set
{
_myText = value;
PropertyChanged(this, new PropertyChangedEventArgs("MyText"));
}
}
...
}
public partial class Window1: Window, INotifyPropertyChanged
{
private LogicClass _logic;
public String LogicText
{
get{return _logic.MyText;}
}
...
}
<ContentControl Name="contentControl1" >
<Binding ElementName="MainWindow" Path="LogicText"/>
</ContentControl>
Is there any way to make this work, without having to expose my LogicClass variable and make use of its implementation of INotifyPropertyChanged. I guess I want to know if this can bubble up, or anything other than having to have a redundant set in my UI code-behind (which is how I am doing this now)
Yes, you need to either handle the PropertyChanged event from _logic and then raise an equivalent PropertyChanged notification on LogicText, or you need to add a standard event on MyText, so you would have a MyTextChanged event, handle this and then raise the PropertyChanged for LogicText.
So if LogicClass if never bound to directly in the Xaml, you wouldn't need to implement INotifyPropertyChanged on LogicClass and you would do (something like) this:
public class LogicClass
{
private String _myText;
public event EventHandler MyTextChanged;
public String MyText
{
get{return _myText;}
set
{
_myText = value;
var handler = MyTextChanged;
if(handler != null){ MyTextChanged(this, EventArgs.Empty); }
}
}
...
}
public partial class Window1: Window, INotifyPropertyChanged
{
private LogicClass _logic;
public Window1()
{
_logic = ... initialised;
_logic.MyTextChanged += (s,e) => RaisePropertyChanged("LogicText");
}
public String LogicText
{
get{return _logic.MyText;}
}
...
}
If what you're asking is if you can essentially say "this property represents another property on another class, so you need to look and see if it changes" in some declarative fashion, then no, that's not possible. You can, however, mimic this behavior yourself. Just attach to the PropertyChanged event on your logic class and when the MyText property changes, raise the window's PropertyChanged event by calling OnPropertyChanged.
Note that this is almost certainly better suited to something that goes in your ViewModel, not something in the codebehind on the window.
In my mvvm ViewModel I have such field
public int Delta { get; private set; }
However when I update it like that:
Delta = newValue;
UI is not refreshed.
I was thinking that databinding will do that for me. For example I can declare collection as ObservableCollection and then databinding will work.
However there are no ObservableInt, how to say View that it need to be refreshed then?
Probably I should raise some event "notify property changed" or something?
You have two choices:
Implement the INotifyPropertyChanged interface on your class.
Inherit from DependencyObject and implement Delta as a DependencyProperty.
The simplest option is #1. You can implement the INotifyPropertyChanged interface on your class quite easily:
public class YourClass : INotifyPropertyChanged
{
private int _delta;
public int Delta
{
get { return _delta; }
set { _delta = value; PropertyChanged?.Invoke(nameof(Delta)); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
You can read more about using and implementing dependency properties on MSDN.
While we're at it with improving the answer, some of the other new additions of c# 6.0 and 7.0 help make it ever more compact:
public class Prop<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get => _value;
set { _value = value; NotifyPropertyChanged(nameof(Value)); }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
This way, you aren't using any "embedded values" (i.e - the property's name) and are keeping the code refactor-safe.
And there's also no need for redundant code blocks due to c# 6.0 and 7.0's new Expression body features
Using #LBushKin's Answer, i modified it to
public class Prop<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get { return _value; }
set { _value = value; NotifyPropertyChanged("Value"); }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(String propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
and to set it up:
class MainWindow ...
// a bool with initial value of true
public static Prop<bool> optionBool { get; set; } = new Prop<bool>{ Value = true };
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// connect UI to be able to use the Prop
DataContext = this;
}
and to use it:
<Grid ...
<CheckBox Content="Da Check" ... IsChecked="{Binding optionBool.Value}"/>
There is also a Collection and 2-Properties version here:
Utils.ObservableProperties.cs (this repo contains several related classes)
Just implement INotifyPropertyChanged Interface in your class and use it to raise a PropertyChanged for your Property and then UI will update. If you are using an MVVM project template then there is a good chance you already have a helper method implemented you only need to use it.
MSDN INotifyPropertyChanged
GalaSoft MVVM Light Toolkit
The ObservableCollection raises events automatically but for your own properties you have to raise the events yourself.
A good example is here: http://www.codeproject.com/Tips/228352/Naming-Properties-in-MVVM?display=Print
I'd suggest using mvvm light: http://mvvmlight.codeplex.com, I used it in silverlight and wpf applications. Very easy to use and provides a messageing system between model, view model and view.
Adding on to https://stackoverflow.com/a/8316100/5725669, there is a new and easy way to do this without remembering to keep track of PropertyChanged?.Invoke(nameof(Delta)); in every location
public class YourClass : INotifyPropertyChanged
{
private int _delta;
public int Delta
{
get { return _delta; }
set {
_delta = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged();
}
}
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
public YourClass()
{
}
// Create the OnPropertyChanged method to raise the event
// The calling member's name will be used as the parameter.
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
It makes use of CallerMemberName for skipping manual entries for property name. More details on this MSDN Doc
I have to build a chat app in WPF; I want to use DataBinding (still learning it) and want to do it in the right way. I've built a Buddy class in this way:
public class Buddy: INotifyPropertyChanged
{
private String _name;
private String _status;
public String Name
{
get
{
return _name;
}
set
{
_name = value;
NotifyPropertyChanged("Name");
}
}
public String Status
{
get
{
return _status;
}
set
{
_status = value;
NotifyPropertyChanged("Status");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I don't know which is the best way to handle BuddyList. Should I create a BuddyList class with Add and List method and then DataBinding to an instance of that class? What is the best way to do it?
You can use INotifyCollectionChanged Interface to create your BuddyListClass
Look here for an example: Usage of INotifyCollectionChanged
Also you can use ObservableCollection<T> Class.
If you want to bind collections of items you should use the
ObservableCollection class
and another suggestions create and base class that implement INotifyPropertyChanged interface,
and derive from it each class that you want to bind to UI.
I think your class definition looks just fine.
Regarding the list question I would expose my list as readonly for binding, and all the add, delete, edit functionality I would keep it private. To avoid informing manually your view for changes to your collection, I would use an ObservableCollection but exposing it to public as ReadOnlyObservableCollection.