How can I refresh the following ObservableCollection?
public class ViewModelProperties
{
private ObservableCollection<ServerProperties> properties;
public ObservableCollection<ServerProperties> Properties
{
get
{
properties = new ObservableCollection<ServerProperties>();
for (var lineNumber = 0; lineNumber < MainWindow.lineCount; lineNumber++)
{
if (MainWindow.textProperties[lineNumber, 0] == null) break;
properties.Add(new ServerProperties(MainWindow.textProperties[lineNumber, 0],
MainWindow.textProperties[lineNumber, 1]));
}
return properties;
}
}
}
public class ServerProperties
{
private string property;
private string value;
public ServerProperties()
{
}
public ServerProperties(string property, string value)
{
Property = property;
Value = value;
}
public string Property
{
get
{
return this.property;
}
set
{
this.property = value;
}
}
public string Value
{
get
{
return this.value;
}
set
{
this.value = value;
}
}
public override string ToString()
{
return string.Format("[Property : {0}]", Value);
}
}
I changed the value of textProperties[,] and now I'd like to overwrite the previous content of the collection with the current content of textProperties[,].
What would be the simplest way to do this?
Any help would be appreciated.
Start off by implementing INotifyPropertyChanged in your ViewModel as well as in the ServerProperties object. This way you can raise the PropetyChanged event which will pass back to the user interface.
ViewModel
public class ViewModelProperties : INotifyPropertyChanged {
public event ProeprtyChangedEventHandler PropertyChanged;
private ObservableCollection<ServerProperties> properties = new ObservableCollection<ServerProperties>();
public ObservableCollection<ServerProperties> Properties {
get { return properties;}
set {
properties = value;
this.RaisePropertyChangedEvent("Properties");
}
}
private void RaisePropertyChanged(string propertyName) {
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Implementing this on the ServerProperties object as well will allow you to change the objects, at any level, and have it bubble up to the interface.
Lastly look into your population code and in order to get the property to update successfully first populate it to a List then re-initialise the ObservableCollection using the List.
Properties = new ObservableCollection<ServerProperties>(propertiesList);
This also allows you to better handle the creation of your ObservableCollection and perform tests before posting the output to the interface. Hope it helps.
For example, one of the simpler solutions could be
public class ViewModelProperties
{
private ObservableCollection<ServerProperties> properties = new ObservableCollection<ServerProperties>();
public ObservableCollection<ServerProperties> Properties
{
get
{
return properties;
}
}
public void SetProperties()
{
properties.Clear();
for (var lineNumber = 0; lineNumber < MainWindow.lineCount; lineNumber++)
{
if (MainWindow.textProperties[lineNumber, 0] == null) break;
properties.Add(new ServerProperties(MainWindow.textProperties[lineNumber, 0],
MainWindow.textProperties[lineNumber, 1]));
}
}
}
Any time you wish to add new items to OC, just call the SetProperties method.
Related
I have an object which contain a list of this object.
when the user click on a button I want to add a new object
to one of the object in the list per an index. for example if the index is equal to 2
I want to add an object to the object.object.object(new object()).
how am I trying to get the correct object inside the inifinte object.
any better method then this one?
private void addToCommand(int indexTreeView, ClassForTest.CommadStructure CS)
{
if (_indexTreeView == 0)
{
_OCommandStructure.Add(CS);
}
else if (_indexTreeView==1)
{
_OCommandStructure[_OCommandStructure.Count - 1].SubCommandStructure.Add(CS);
}
else if (_indexTreeView == 2)
{
_OCommandStructure[_OCommandStructure.Count - 1].SubCommandStructure[_OCommandStructure[_OCommandStructure.Count - 1].SubCommandStructure.Count-1].SubCommandStructure.Add(CS);
}
}
public class CommadStructure : INotifyPropertyChanged
{
private string _Controller;;
private ObservableCollection<CommadStructure> _SubCommandStructure;
public string NameOfCommand
{
get => _NameOfCommand;
set
{
_NameOfCommand = value;
NotifyPropertyChanged();
}
}
public ObservableCollection<CommadStructure> SubCommandStructure
{
get => _SubCommandStructure;
set
{
_SubCommandStructure = value;
// NotifyPropertyChanged();
}
}
public ObservableCollection<object> Items
{
get
{
ObservableCollection<object> childNodes = new ObservableCollection<object>();
foreach (var group in this.SubCommandStructure)
childNodes.Add(group);
return childNodes;
}
}
public CommadStructure()
{
NameOfCommand = "";
}
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Given:
public class MyClass : INotifyPropertyChanged
{
public List<string> _TestFire = new List<string>();
string _StringProp;
public string StringProp
{
get
{
return _StringProp;
}
set
{
if (_StringProp != value)
{
_StringProp = value;
RaisePropertyChanged("StringProp");
_TestFire.Add("fired " + DateTime.Now);
}
}
}
}
When you serialize and then deserialize this class, it fires the RaisePropertyChanged event, which is undesirable. Is it possible to prevent this event from being fired when the class gets deserialized?
var MyclassInstance = new MyClass() { StringProp = "None" };
MyclassInstance._TestFire.Clear(); // Clear property change history
var serobj = JsonConvert.SerializeObject();
var newitem = JsonConvert.DeserializeObject<MyClass>(serobj);
// newitem._TestFire.Count == 1, the set method was executed
Is there a way to get a bool value if the class is being deserialized?
So then I could do:
set
{
if (_StringProp != value)
{
_StringProp = value;
if (!Deserializing)
{
RaisePropertyChanged("StringProp");
_TestFire.Add("fired " + DateTime.Now);
}
}
}
Yes, you can do what you want by implementing the OnDeserializing and OnDeserialized serialization callback methods in your class. In the OnDeserializing method, set your private _isDeserializing variable to true, and in OnDeserialized set it back to false. I would recommend doing the _isDeserializing check inside the RaisePropertyChanged method so you don't have duplicate code inside every property.
So you would end up with something like this:
public class MyClass : INotifyPropertyChanged
{
public List<string> _TestFire = new List<string>();
string _StringProp;
public string StringProp
{
get
{
return _StringProp;
}
set
{
if (_StringProp != value)
{
_StringProp = value;
RaisePropertyChanged("StringProp");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
// don't raise the event if the property is being changed due to deserialization
if (_isDeserializing) return;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
_TestFire.Add(propertyName + " was fired " + DateTime.Now);
}
bool _isDeserializing = false;
[OnDeserializing]
internal void OnDeserializingMethod(StreamingContext context)
{
_isDeserializing = true;
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
_isDeserializing = false;
}
}
Working demo: https://dotnetfiddle.net/QkOcF4
Another way you could solve this problem is to mark your public properties with [JsonIgnore] and then mark the corresponding backing fields with [JsonProperty], specifying the property name to use in the JSON. This would allow Json.Net to set the backing fields directly and not execute any of the mutator logic.
public class MyClass : INotifyPropertyChanged
{
public List<string> _TestFire = new List<string>();
[JsonProperty("StringProp")]
string _StringProp;
[JsonIgnore]
public string StringProp
{
get
{
return _StringProp;
}
set
{
if (_StringProp != value)
{
_StringProp = value;
RaisePropertyChanged("StringProp");
_TestFire.Add("StringProp was fired " + DateTime.Now);
}
}
}
...
}
Working demo: https://dotnetfiddle.net/jc7wDu
Please assume this entire question deals in code, without any XAML.
I have a static ObservableCollection named myStaticList. It's a part of a non-static class named myClass.
public class myClass
{
public static ObservableCollection<CheckBoxStructure> myStaticList { get; set; }
static myClass()
{
myStaticList = new ObservableCollection<CheckBoxStructure>();
}
}
And the definition of CheckBoxStructure:
public class CheckBoxStructure
{
public string Description { get; set; }
public bool IsSelected { get; set; }
}
In addition, there's an array of checkboxes called checkBoxArray[], holding 3 elements. each checkbox has as content a textbox.
What I want to do is programmatically bind (two-way) these two, in such a manner that the IsChecked property of the checkboxes in the checkBoxArray[] array will bind to the IsSelected property of the myStaticList's CheckBoxStructure, and similarly so between the text of the textboxes inthe checkboxes' content and the Description property of the myStaticList's CheckBoxStructure.
In addition, I would like to avoid using loops, since it is preferable that this two lists will update each other if they change in size.
How is this possible?
Thanks!
Using XAML, an easy way would be to the declare an ItemsControl and a DataTemplate for it so that you can have a UserControl (CheckBox and TextBox inside) with its DataContext being a CheckBoxStructure. This way the bindings work between CheckBox.IsChecked and IsSelected property and between TextBox.Text and Description property.
If you need to this only in code then you would have to create same behavior (ItemsControl with a DataTemplate). You have at least 2 options
1.
DataTemplate template = new DataTemplate();
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(StackPanel));
template.VisualTree = factory;
FrameworkElementFactory childFactory = new FrameworkElementFactory(typeof(CheckBox));
childFactory.SetBinding(CheckBox.IsChecked, new Binding("IsSelected"));
factory.AppendChild(childFactory);
childFactory = new FrameworkElementFactory(typeof(TextBox));
childFactory.SetBinding(Label.ContentProperty, new Binding("Description"));
factory.AppendChild(childFactory);
2.
MemoryStream sr = null;
ParserContext pc = null;
string xaml = string.Empty;
xaml = "<DataTemplate><StackPanel><TextBlock Text="{Binding Description"/><CheckBox IsChecked="{Binding IsSelected"/></StackPanel></DataTemplate>";
sr = new MemoryStream(Encoding.ASCII.GetBytes(xaml));
pc = new ParserContext();
pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
DataTemplate datatemplate = (DataTemplate)XamlReader.Load(sr, pc);
this.Resources.Add("dt", datatemplate);
Later edit, after discussion from comments; this example works only one way of binding but is easily to make it two ways. Please note that this is only a trivial example of a concept and is not complete: you need to modify the list classes to suit how you wish for objects to be paired, you may need to add more guards for corner cases, you may need to make it thread safe and so on...
First the basic binding objects:
class Binder
{
public Binder()
{
_bindings = new Dictionary<string, List<string>>();
}
private INotifyPropertyChanged _dataContext;
public INotifyPropertyChanged DataContext
{
get { return _dataContext; }
set
{
if (_dataContext != null)
{
_dataContext.PropertyChanged -= _dataContext_PropertyChanged;
}
_dataContext = value;
_dataContext.PropertyChanged += _dataContext_PropertyChanged;
}
}
void _dataContext_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (_bindings.ContainsKey(e.PropertyName))
{
var bindableType = _dataContext.GetType();
var bindableProp = bindableType.GetProperty(e.PropertyName);
if (bindableProp == null)
{
return;
}
var binderType = this.GetType();
foreach (var binderPropName in _bindings[e.PropertyName])
{
var binderProp = binderType.GetProperty(binderPropName);
if (binderProp == null)
{
continue;
}
var value = bindableProp.GetValue(_dataContext);
binderProp.SetValue(this, value);
}
}
}
Dictionary<string, List<string>> _bindings;
public void AddBinding(string binderPropertyName, string bindablePropertyName)
{
if (!_bindings.ContainsKey(bindablePropertyName))
{
_bindings.Add(bindablePropertyName, new List<string>());
}
_bindings[bindablePropertyName].Add(bindablePropertyName);
}
}
class Bindable : INotifyPropertyChanged
{
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Then the holding lists for them:
class BindableList<T> : List<T> where T : Bindable
{
public event Action<T> ItemAdded;
public new void Add(T item)
{
base.Add(item);
NotifyItemAdded(item);
}
private void NotifyItemAdded(T item)
{
if (ItemAdded != null)
{
ItemAdded(item);
}
}
}
class BinderList<T> : List<T> where T : Binder
{
public BinderList()
{
_bindingRules = new Dictionary<string, string>();
}
private BindableList<Bindable> _dataContextList;
public BindableList<Bindable> DataContextList
{
get { return _dataContextList; }
set
{
if (_dataContextList != null)
{
_dataContextList.ItemAdded -= _dataContextList_ItemAdded;
}
_dataContextList = value;
_dataContextList.ItemAdded += _dataContextList_ItemAdded;
}
}
void _dataContextList_ItemAdded(Bindable obj)
{
foreach (var pair in _bindingRules)
{
this[Count-1].AddBinding(pair.Key, pair.Value);
this[Count - 1].DataContext = obj;
}
}
private Dictionary<string, string> _bindingRules;
public void AddBindingRule(string binderPropertyName, string bindablePropertyName)
{
_bindingRules.Add(binderPropertyName, bindablePropertyName);
}
}
Now the actual classes with properties:
class BinderElement : Binder
{
private string _description;
public string Description
{
get { return _description; }
set { _description = value; }
}
}
class BindableElement : Bindable
{
private string _description;
public string Description
{
get
{
return _description;
}
set
{
_description = value;
NotifyPropertyChanged("Description");
}
}
}
And an example to use them:
static void Main(string[] args)
{
var bindableList = new BindableList<Bindable>();
var binderList = new BinderList<BinderElement>()
{
new BinderElement(),
new BinderElement()
};
binderList.DataContextList = bindableList;
binderList.AddBindingRule("Description", "Description");
bindableList.Add(new BindableElement());
bindableList.Add(new BindableElement());
((BindableElement)bindableList[1]).Description = "This should arrive in BinderElement Description property";
Console.WriteLine(binderList[1].Description);
Console.ReadLine();
}
I do have a WPF binding question here.
Following Setup:
I do have a class (ActionService) having a name and a ObservableCollection of subitems (also a class named Step). A Step has a flag that shows if the Step is allready done (IsDone).
I bind a form to the ActionService and display all kind of things.
Everything works as aspected and i have just the essential parts in my snippet.
Now I need one more thing that i can not get work. I want the ActionService to know by binding how many of its Steps are open (IsDone == false). I you open a childform with one of the steps and change the IsDone-State, the mother form should get the new count on the fly.
And I'm to dumb to get a correct solution on the way ;-)
Thanks for your help or a best practise.
public class ActionService : BaseObject
{
public ActionService()
{
}
private String name;
public String Name
{
get { return this.name; }
set
{
this.name = value;
raisePropertyChanged("Name");
}
}
public ObservableCollection<Step> actionsteps;
public ObservableCollection<Step> ActionSteps
{
get { return this.actionsteps; }
set
{
this.actionsteps = value;
raisePropertyChanged("ActionSteps");
}
}
}
public class Step : BaseObject
{
public Step()
{
}
private String description;
public String Description
{
get { return this.description; }
set
{
this.description = value;
raisePropertyChanged("Description");
}
}
private Boolean isdone;
public Boolean IsDone
{
get { return this.isdone; }
set
{
this.isdone = value;
raisePropertyChanged("IsDone");
}
}
}
public class BaseObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void raisePropertyChanged(String parPropertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(parPropertyName));
}
}
}
You can create a new property in your ActionService class:
public bool IsDone
{
get
{
return ActionSteps.Count(x => x.IsDone) == ActionSteps.Count;
}
}
If the count of Steps in the ActionSteps list where the IsDone property is true is equal to the number of Steps in the ActionSteps list, then return true, else, return false.
To subscribe to the Steps property changed event, when you add an item to the collection, you simply need to subscribe to the PropertyChanged event:
//Create the item and subscribe to propertychanged.
Step item = new Step();
item.PropertyChanged += item_PropertyChanged;
//Add the item to the list.
ActionSteps.Add(item);
And your method will look like this:
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsDone")
raisePropertyChanged("IsDone");
}
My Class relation is like this Model:
Class MainModel
{
data data1 = new data();
public override string LFE
{
get { return data1.lnf.ToString(); }
set { data1.lnf = Convert.ToByte(value); }
}
public override UInt16 GetRsBValue(int index)
{
return (byte)this.data1.CConfig[index].Bline;
}
public override void SetRsBValue(UInt16 value, int index)
{
byte[] arr = BitConverter.GetBytes(value);
this.data1.CConfig[index].Bline = arr[0];
}
}
Class data
{
public byte Bline
{
get { return this.bline; }
set { this.bline = value; }
}
public byte lnf
{
get { return this.ln_frequency; }
set { this.ln_frequency = value; }
}
}
Class ViewModel : INotifyPropertyChange
{
public UInt16 Rschange
{
get
{
return this.eObj.GetRsBValue(this.index);
}
set
{
this.eObj.SetRsBValue(value, this.Index);
this.OnPropertyChanged(new PropertyChangedEventArgs("Rschange"));
this.eObj.writedata(DefaultFileName);
}
}
public string LF
{
get
{
return this.eObj.LFE;
}
set
{
this.eObj.LFE = value;
this.OnPropertyChanged(new PropertyChangedEventArgs(" LF"));
}
}
}
In Model side I have created instance of data class in main Model.
I'm getting data from other application to my application. I'm getting that updated value till data class but it's not showing that value in MainModel. So It's not updating mu UI at all. Please tell me how can I update my UI when I'm getting value from other application.
P.S: I don't want to create Model class instance in ViewModel side and I have 10 properties and 10 method like this in my class.
You have a typo in your call to property changed in your LF property.
// note the extra space V
this.OnPropertyChanged(new PropertyChangedEventArgs(" LF"));
If you create your property changed handler like this:
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
You can prevent such typos by using the following syntax:
public string LF
{
get
{
return this.eObj.LFE;
}
set
{
this.eObj.LFE = value;
this.OnPropertyChanged();
}
}