I have a class defined like this:
class TouchScreenDisabledGrid:DataGrid,INotifyPropertyChanged
I want to change soome of my class behaviour depanding on it's properties, that are set threw the xaml when using it in a window.
For example the following:
<my:TouchScreenDisabledGrid x:Name="dataGridView" Tag="13" />
Will cause an exception if In my constructor I try to check this value:
public TouchScreenDisabledGrid(){
Console.WriteLine(this.Tag.ToString());
}
Why is that and how can I check the propery and use it?
Objects defined in XAML are constructed using the default constructor and then their properties are set. So imagine that this:
<my:TouchScreenDisabledGrid x:Name="dataGridView" Tag="13" />
Is the moral equivalent of this:
var g = new TouchScreenDisabledGrid();
g.Name = "dataGridView";
g.Tag = "13";
It should now be obvious why Tag is null inside your constructor, hence you are getting a NullReferenceException when you call ToString().
Continuing further, you cannot use the classical model of doing something inside the constructor that depends on object properties being set. You have to find another way of achieving your goal -- what way, depends on what exactly the goal is (for example you can use INotifyPropertyChanged to detect that a property has been set; or you can listen to an event that triggers later in the lifetime of the visual and fetch the values from there).
If the property is set in XAML it will not be set in the constructor. Use OnLoaded override to do this.
Related
The class I made exists of a bunch of properties. Most of the properties are included in the received dataset. After the deserialization of the dataset, I retreive a list of objects. So some of the properties where ignored by using 'jsonignore'.
In the objects I have a property for example called 'foo'. I want this property to be set before I continue.
A possible solution could be looping through the list and setting the property. --> but this seems like double work, because all items were just looped in the deserialization of json.net. Is it possible to override the deserialization so the property I want is set after all other properties (that were in the dataset)?
Can someone get me started? Thanks in advance.
There are several options to achieve what you want:
set the property foo in the class'es constructor,
use a CustomCreationConverter<T> to instantiate the class and set foo; there's a good example in Json.NET's documentation here,
use a [OnDeserialized] callback method; again, there's an example here.
I have a property, of a custom class, in C# that I have overridden the setter for. I want to compare a property of/in the custom class in the setter, like the following:
public DatabaseInfo CurrentDatabaseManagedSelection
{
get { return CurrentDatabaseManaged; }
set {
if (String.Equals(value.Name, CurrentDatabaseManaged.Name,StringComparison.OrdinalIgnoreCase))
return;
CurrentDatabaseManaged = DatabaseManagement.ReadDatabase(value.FileName);
}
}
Inside the DatabaseInfo class, there is a standard String property called Name.
However, when I run the program I get the following exception. Can anyone tell me why this happens and how to solve the issue please?
Exception has been thrown by the target of an invocation.
EDIT: I do set the value of the property which the setter above is for, in the constructor of the view model. I do this simply by setting CurrentDatabaseManagedSelection equal to an object of the DatabaseInfo class.
Think I might have found the problem... Well, I've solved it!
The issue was CurrentDatabaseManaged had not been initialized and so was equal to null when I tried setting the above property. I discovered this by adding a try.. catch in the setter method, and created a new String for CurrentDatabaseManaged.Name - the stack trace pointed to that line.
Hope that helps some one else in the future.
I have a property in a model which has auto property getter and setter:
[DataMember]
public Collection<DTOObjects> CollectionName { get; set; }
I get the following error when building the solution:
Microsoft.Usage : Change 'propertyname' to be read-only by removing the property setter.
However, when I remove the setter and run the code, an error occurs because it's trying to set the property! It appears it's asking me to remove the setter despite the fact it is being set somewhere in the code.
Has anyone else come accross this problem? What do I need to modify?
I'm going to guess this is a list/collection (or something similar), in which case yes - it is unusual to have a setter. A typical example might be:
private readonly List<Foo> items = new List<Foo>();
public List<Foo> Items { get { return items; } }
Most callers should not be trying to assign to that; they shouldn't need to - they can add/remove/enumerate/clear/etc the list without ever needing to assign it.
an error occurs because it's trying to set the property
Then consider changing that code so that it doesn't try to set the property. It should not need to in virtually all cases.
One solution is to initialize the Collection in the constructor...
public class Email
{
public Email()
{
To = new List<MailAddress>();
}
....
public List<MailAddress> To { get; }
}
Then just use .add in code:
Email oEmail = new Email();
oEmail.To.Add(new MailAddress("Foo#fighter.com", "Mr. Foo"));
Just suppress it, right click the error and click suppress in code & an attribute will be added to the property.
Generally you shouldn't have a public set for collections as this allows the list to be replaced, however with objects that are created or deserialized at runtime sometimes the public setter is necessary.
From the docs:
"You can suppress the warning if the property is part of a Data Transfer Object (DTO) class. Otherwise, do not suppress warnings from this rule."
If it's not part of a DTO:
"To fix a violation of this rule, make the property read-only. If the design requires it, add methods to clear and repopulate the collection."
The preferred manner of replacing a read-only collection property is to use the Clear and AddRange methods (or their equivalents).
https://learn.microsoft.com/en-us/visualstudio/code-quality/ca2227?view=vs-2019
I'm using the XamlServices.Transform to take an object model and serialize it to Xaml.
I've implemented a class which inherits from XamlXmlWriter which overrides WriteValue. I'm using this to reinstantiate a custom MarkupExtension back into the rendered Xaml. My code works fine except when the value of the property is null, in which case the WriteValue doesn't fire and I don't get chance to "swap out" the value in the overriden class.
A related issue is where a property has the same value as that specified by the System.ComponentModel.DefaultValue() attribute. For example say i've got a property in my object model decorated like this:
[DefaultValue(true)]
public Boolean IsVisible {get; set;}
Then the WriteValue method only fires if the IsVisible property is false (which kind of makes sense).
The Remarks section in the documentation (http://msdn.microsoft.com/en-us/library/system.xaml.xamlxmlwriter.writevalue.aspx) mentions something about null values, but I don't understand it:
The input value may be null, which
supports explicitly writing out null
as a serialized value. This behavior
uses the XamlLanguage.Null definition
as WriteStartObject input and then
immediately calls WriteEndObject.
How to I a) make the "WriteValue" fire when the property is null, and b) make the "WriteValue" fire when the property is the same as the DefaultValue Attribute?
I'm not sure if they are related, a solution for either of them would be very welcome.
Thanks,
Daniel
To answer ‘b’ first: The XamlObjectReader’s intended behavior is to skip properties whose value is the declared “default value” and we have no configuration feature to override that. Note that “default value” here is the one declared with the [DefaultValue()] attribute, not the C# language default(T), so things may not be as bad as you fear. I mean not every “0” in an “Int” property is skipped because it is the “default value”.
‘a’: The XamlXmlWriter’s output Node stream for a null value is not “WriteValue(null)”, but instead is “WriteStartObject(nullExtensions); WriteEndObject()”. This is the behavior the documentation you quoted was describing. So you should be fine. Look for StartObject “nullExtension” instead of value “null”.
Between these two:
With Property:
class WithProperty
{
public string MyString {get; set;}
}
With Field:
class WithField
{
public string MyString;
}
Apparently I'm supposed to pick the first one. Why?
I've heard the argument that the point here is to allow interface changes, but
if I have the second one, and change it to the first one, no other code should
ever have to change. When recompiled everything's just going to point to the
property instead.
Am I missing something important here?
The most important difference is the fact, that if you use a field, and later need to change it to a property (say, to enforce some validation), then all libraries calling your code will need to be recompiled. It's true that you can compile the exact same code if the name stays the same - but the consumers of your code will still need to be recompiled. This is because the IL generated to get the value is different between a field and a property. If it already is a property, you can make a change without forcing consumers of your code to change.
This may or may not be an issue for you. But the property is almost the same amount of code, and is considered best practice. I would always go for the property.
The property can be changed later if you need to add validation or other logic without breaking other assemblies.
Also, the property can be used with databinding.
The important part you are missing is the gravity of this statement:
When recompiled
When your code point to a field and you change it to point to a property of the same name, the C# itself doesn't change, but the resulting IL does - it generates a method call to the getter or setter as appropriate.
Not every app has all of it's pieces contained in a single distributed unit. Many apps rely on interfaces for pluggability/expandability. If you have an app with an interface to a field and you want to change it to a property to take advantage of the power of properties, the app has to be recompiled and redistributed. You might as well just make it a property in the first place.
With a property, you can easily extend it to include new logic.
For example, if you need to add validation logic to the set.
This article goes into several additional reasons why you should prefer properties:
http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx