In the examples for coding with the MVVM pattern and WPF binding, they use INotifyPropertyChanged when it's a single value and ObservableCollection when it is a list of values.
I've also read, you cannot use static variables with INotifyPropertyChanged, but you can with ObservableCollection. I'd like to bind to a static variable.
The easiest (to me at least) workaround, is to use an ObservableCollection and always just use and bind to index 0. Is this appropriate to do? Is there any benefit to using INotifyPropertyChanged instead of an ObservableCollection?
For example:
This seems to be the simplest workaround:
public static ObservableCollection<int> MyValues { get; set; }
<TextBox Text="{Binding MyValue[0]}">
For wanting to do this:
private static int _myValue;
public static int MyValue //does not work
{
get { return _myValue; }
set { _myValue = value; OnPropertyChange(); }
}
<TextBox Text="{Binding MyValue, UpdateSourceTrigger=PropertyChanged}">
I don't think your analogy is fair(Comparing ObservableCollection with directly with Primitive Type property). Compare ObservableCollection to below class
public class MyClass : INotifyPropertyChanged
{
private string text;
public string Text
{
get { return text; }
set { text = value;
RaiseChange("Text");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseChange(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
}
Now both below will behave same:
public static MyClass Text { get; set; }
public static ObservableCollection<string> Text { get; set; }
If you perform Text.Text = "Hello" for MyClass or Text[0] = "Hello" for ObservableCollection, both will reflected in same way.
Now if you have to use a static property for binding then instead of ObservableCollection I'll advice you to write your new class
cause ObservableCollection has many internal implementations which
probably is of no use to you any actually consuming memory &
perforamnce.
This link may help, it shows the difference between List, ObservableCollection and INotifyPropertyChanged.
Hope this help
Related
I am unable to understand a thing which is as follows. My project is in Prism 4.1 Sliverlight 5. I'm Using MVVM pattern.
I've a static class like this
{
public static class RegionNames
{
public static string AUTH_LOGIN_REGION = "AuthRegion";
public static string TAB_TEST_REGION = "TabRegion";
public static string USER_TAB_REGION="UserTabRegion";
}
}
I tried to use this class in Shell.xmal like below.
<Grid.Resources>
<inf:RegionNames x:Key="rName"></inf:RegionNames>
</Grid.Resources>
Now this Resource I used in textblock
Result :No text appeared.
<TextBlock Text="{Binding Source={StaticResource rNamee}, Path=USER_TAB_REGION}" Margin="20"></TextBlock>
Now I changed this class like below:
{
public class RegionNames : INotifyPropertyChanged
{
public static string AUTH_LOGIN_REGION = "AuthRegion";
public static string TAB_TEST_REGION = "TabRegion";
public static string USER_TAB_REGION="UserTabRegion";
public RegionNames() {
AuthReginName = "HOLY COW POW POW !!";
}
private string _authReginName;
public string AuthReginName {
get {
return _authReginName;
}
set {
_authReginName = value;
OnPropertyChanged("AuthReginName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
And used it like this
<TextBlock Text="{Binding Source={StaticResource rNamee}, Path=AuthReginName}"></TextBlock>
Result : Text Appeared
this time it worked. Why? My static defied string values are not coming?.
Is there any relation with Object creation of class & Setting Properties values?
First of all for instance objects you can bind only with properties, that's why second solution works for you. (You can't bind with fields)
And for static properties you can bind with fields but you need to use x:Static markup extension. (same goes for properties as well)
<TextBlock Text="{x:Static inf:RegionNames.USER_TAB_REGION}" Margin="20"/>
My Second Question with this thread About x:Static
For Silverlight 5 who want to Use x:Static in xaml.
http://brianlagunas.com/creating-a-silverlight-5-static-markup-extension/
is Helpful & Worked for me.
I think I may be using the DependencyObject incorrectly.
I have a generic class that implements the DependencyObject called Person with the properties FirstName and LastName.
public class Person : DependencyObject
{
public static readonly DependencyProperty FirstNameProperty =
DependencyProperty.Register("FirstName", typeof(string), typeof(Person));
public string FirstName
{
get { return (string)GetValue(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
public static readonly DependencyProperty LastNameProperty =
DependencyProperty.Register("LastName", typeof(string), typeof(Person));
public string LastName
{
get { return (string)GetValue(LastNameProperty); }
set { SetValue(LastNameProperty, value); }
}
}
Then I have a xaml control with its datacontext set to my ViewModel class. Inside the ViewModel class I have a property called UserName that gets/sets a Person. The text box is bound to the UserName.FirstName property. It can populate the textbox correctly but can't seem to call the set when I enter characters and tab out. I think the issue is the two level property binding. For design reasons I need to access it through two levels of properties. Any suggestions?
Here is my xaml:
<TextBox Width="100" Margin="10,0,0,0" Text="{Binding Path=UserName.FirstName, Mode=TwoWay}" />
Here is my property in the view model class:
public Person UserName
{
get
{
return person;
}
set
{
person = value;
}
}
I've also tried it this way too:
public Person UserName
{
get
{
return person;
}
set
{
person.FirstName = value.FirstName;
}
}
Your property will not be called from the binding, the property is only there because of the pattern so it is easily visible from code.
The binding sets the dependency property directly.
Why do you want dependency properties in this situation? Dependency properties are relevant on controls - for your scenario use regular properties and INotifyPropertyChanged - the code will be simpler that way :)
If you do want notification when a dependencyproperty is changed you have to add a static eventhandler to the DependencyProperty.Register(...) call.
Agree with rune Andersen.
You should use INotifyPropertyChanged.
public class Person :INotifyPropertyChanged
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; OnPropertyChanged("FirstName"); }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; OnPropertyChanged("LastName"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
Ok I'll make this very simple! Here are viewmodels :
public class ObjectsModel
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private string _objectName;
public string ObjectName
{
get
{
return _objectName;
}
set
{
if (value != _objectName)
{
_objectName = value;
PropertyChanged(this, new PropertyChangedEventArgs("ObjectName"));
}
}
}
public IEnumerable<Object> Objects {get;set;}
public ICommand AddCommand { get; private set; }
public ICommand SaveChangesCommand { get; private set; }
myDomainContext context = new myDomainContext();
public ObjectsModel()
{
objects = context.Objects;
context.Load(context.GetObjectsQuery());
}
}
public class InventoryModel
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public IEnumerable<Inventory> Inventories {get;set;}
public ICommand AddCommand { get; private set; }
public ICommand SaveChangesCommand { get; private set; }
myDomainContext context = new myDomainContext();
public ObjectsModel()
{
objects = context.Objects;
context.Load(context.GetObjectsQuery());
}
}
So what I'm trying to do is in my second form where I want to add an inventory for an object, I have to select the object in a combobox. The question is, how do I fill my combobox? Create another instance of the "ObjectsModel" in the InventoryModel? or use another "context" where I would query the other table? Or is there an easier Xaml approach? If I'm not clear, tell me I'll put more examples/code.
tx a lot!
You want to bind the contents of the combobox to a list of items provided by your ViewModel and bind the selected item to another property on the same ViewModel.
Please get into the habit of naming actual view models to end in "ViewModel", rather than "Model", so they do not clash with your other "real" models. It actually looks like you are binding directly to your business models instead of ViewModels (which is not good).
public class myClass : INotifyPropertyChanged
{
public string myName(string myNameIs)
{
Name = myNameIs;
return myNameIs;
}
public string My = "Hasan";
public string Name {
get { return My; }
set
{
My = value;
OnPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
// Raise the PropertyChanged event
this.PropertyChanged( this, new PropertyChangedEventArgs(
propertyName));
}
}
}
.
XAML:
<TextBlock Height="42" Margin="107,245,0,0" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top" HorizontalAlignment="Left" Width="159" DataContext="{Binding Source={StaticResource myClassDataSource}}"/>
This is working. But when i update property then it isn`t work?
Your code is rather confusing, you seem to be all over the place with it. I know this isn't the question you asked, but i thought i would point this out anyway:
your member variable is declared as public (public string My = "Hasan";)
your member variable has a totally different name to its property (My and Name)
you have a setter for the public property, and also a setting function (myName(string myNameIs))
you are returning the same value from the setting function as what you passed in
Here is an example of how you could rewrite it:
public class MyClass : INotifyPropertyChanged
{
//normal default constructor
public MyClass()
{
_name = "Hasan";
}
//extra constructor for when you need to set the name to something other than the default
//although this is really only useful if you have no setter on the Name property
public MyClass(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
// Raise the PropertyChanged event
this.PropertyChanged(this, new PropertyChangedEventArgs(
propertyName));
}
}
private string _name;
}
You just need to set the TextBlock (or it's parent's) DataContext property to an instance of this class.
Next bind the Text property to the backing property like this
<TextBlock Text="{Binding Name}"/>
Try going through a few tutorials online (or a book) instead of trying to forge your way through. It's easy once you get how DataBinding works.
Update: Once I formatted your question correctly, I could see the XAML you are using...
The mistake here is that you're trying to use the ElementName property (which is used to bind one UI element with another by name). This isn't what you're trying to achieve.
I have the following class
public class LanguagingBindingSource : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Dummy
{
get { return String.Empty; }
set
{
PropertyChanged(this, new PropertyChangedEventArgs("Dummy"));
}
}
}
that is bound to elements in XAML like this
Text="{Binding Dummy,Source={StaticResource languageSource},Converter={StaticResource languageConverter},ConverterParameter=labelColor}"
The sole purpose of the LanguageBindingSource class and its Dummy method is to allow property notifications to update the bindings when one or more resources change. The actual bound values are provided by the converter, looking up resources by the names passed as parameters. See the comments on this answer for more background.
My problem is that the resources are changed by a process external to the XAML pages containing the bindings and I need a single static method that I can call to trigger property change notification for all instances of the binding. I'm struggling to figure out just how I might do that. All ideas will be most appreciated.
Modify your class as follows:-
public class LanguagingBindingSource : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate {};
public static void FirePropertyChanged(string key)
{
((LanguagingBindingSource)Application.Resources[key]).NotifyPropertyChanged("Dummy");
}
private void NotifyPropertyChanged(string name)
{
PropertyChanged(this, new PropertyChangedEventArgs(name);
}
public string Dummy
{
get { return String.Empty; }
set
{
NotifyPropertyChanged("Dummy"));
}
}
}
Now are any point where you need to fire off this change use:-
LanguagingBindingSource.FirePropertyChanged("languageBindingSource");
Where "languageBindingSource" is the resource key that you are also using in your binding Source property.