I create a custom User Control which inherits from DataGridViewColumn.
Moreover, I added some properties in the control, but I can't modify them in design-time.
Even I set the default value as true, it's still false.
code:
public class ParaGridViewColumn : DataGridViewColumn
{
private bool _Necessary;
private bool _ReadOnlyEmpty;
[Description("Default cell status."), Category("Behavior"), DefaultValue(false)]
public bool Necessary { get { return _Necessary; } set { _Necessary = value;} }
[Description("When ReadOnly is true, clear value on the cell or not."), Category("Behavior"), DefaultValue(true)]
public bool ReadOnlyEmpty { get { return _ReadOnlyEmpty; } set { _ReadOnlyEmpty = value; }}
public ParaGridViewColumn()
{
this.CellTemplate = new ParaGridViewCell();
}
}
The new properties can shown on the window, but their default value are false.
I change them to true, entering and opening this window again, it's still false.
However, I can modify other properties regularly. It means I didn't lock this control.
Why is that?
Did I make something wrong?
Thanks a lot.
The first problem is with [DefaultValue(true)] for ReadOnlyEmpty while not setting the true value for it.
You have not set the default value for property to true.
In fact [DefaultValue(true)] help to CodeDomeSerizalizer to serialize value for this property if the property value is not equals to this default value.
You should set ReadOnlyEmpty= true in constructor or _ReadOnlyEmpty instead.
private bool _ReadOnlyEmpty=true;
The problem here is when you set property to true in property grid, when closing the form, serializer will not serialize true value, because you said it is default but you have not set it to true, so it will remain false.
The second problem is that if you want values persist, you should override Clone of base class and provide a clone copy that contains your custom properties.
public override object Clone()
{
ParaGridViewColumn column = (ParaGridViewColumn)base.Clone();
//Uncomment if you have ParaGridViewCell
//column.CellTemplate = (ParaGridViewCell)CellTemplate.Clone();
column.Necessary = this.Necessary;
column.ReadOnlyEmpty = this.ReadOnlyEmpty;
return column;
}
Well, I found the solution, losing an override clone function.
public override object Clone()
{
ParaGridViewColumn c = (ParaGridViewColumn)base.Clone();
c._Necessary = this._Necessary;
c._ReadOnlyEmpty = this._ReadOnlyEmpty;
return c;
}
Related
I have a WPF control that is supposed to be simple to (re)use. For that I have a custom type containing all the settings the control is supposed to represent and bind it over a DependencyProperty.
However, whenever I change one of the members in the control, the parent control gets the changes in the member (when evaluated through other means), but the PropertyChanged-Callback never gets triggered in the parent control.
public class Setting
{
public int Prop {get;set;}
//Other Properties, Constructor & Copy Constructor, etc.
public override bool Equals(object obj)
{
if (!(obj is Setting other)) return false;
return Prop == other.Prop;
}
}
public class SettingControl : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty SettingProperty = DependencyProperty.Register
(nameof(Settings), typeof(Setting), typeof(SettingControl),
new PropertyMetadata(default(Setting), OnValuePropertyChanged));
public Setting Settings
{
get => (Setting)GetValue(SettingProperty);
set
{
SetValue(SettingProperty, value);
OnPropertyChanged(nameof(Settings));
}
}
public int Prop
{
get => ((Setting)GetValue(SettingProperty))?.Prop ?? 0;
set
{
//Does not work:
var temp = (Setting)GetValue(SettingProperty);
temp.Prop = value;
Settings = temp;
OnPropertyChanged(nameof(Prop));
//Does not work:
Settings.Prop = value;
OnPropertyChanged(nameof(Prop));
OnPropertyChanged(nameof(Settings));
//**Does work**, and triggers the OnSettingChanged in the parent control,
//but is simply not great memory usage
Settings = new Setting(Settings){ Prop = value };
OnPropertyChanged(nameof(Prop));
}
}
}
//Relevant snippet from parent Control ViewModel:
public static readonly DependencyProperty SettingProperty =
DependencyProperty.Register(nameof(Settings), typeof(Setting), typeof(ControlViewModel),
new PropertyMetadata(default(Setting), (d, e) => ((ControlViewModel)d).OnSettingChanged()));
//OnSettingChanged() is never called
public Setting Settings
{
get => (Setting)GetValue(SettingProperty);
set //Set is never called when the member properties are changed
{
SetValue(SettingProperty, value);
OnPropertyChanged(nameof(Settings));
}
}
//Relevant snippet from parent xaml:
<local:SettingControl Width="300"
Settings="{Binding Path=Settings, Mode=TwoWay}"/>
// UpdateSourceTrigger=PropertyChanged doesn't help here either
An obvious solution of course would be to either wrap the Setting class into a SettingViewModel, or implement it as a ViewModel itself (small testing didn't show results anyway). This however would make the usage of the control a lot harder, and to some degree break MVVM (more than this already). There are also some XML things in the Setting class for serialization that I don't want to mess with.
One thing I noticed is that if the Equals function in Setting is coded to always return true the two ways of setting the member property that normally don't work, suddenly work and trigger the desired behavior.
Thanks in Advance.
I need to find a way to set the default value of ischecked to true, I am passing it as a parameter and I don't always set it.
ischecked is defined in my config files, I have multiple configs and in some it is defined and some it isn't. I won't get into why I use different configs. When it isn't define it is defaulted to false but I need it to be true.
function showSaveCardControl(ischecked) {
$(".saveCardControl").slideDown().find("input").prop("checked", ischecked);
}
if it hasn't been defined I need the checkbox to be checked basically but since the default is false it is unchecked.
Update:
I am passing an xml element to a c# property. The xml would be where I set the value of ischecked but since I haven't set it somewhere either in the xml or once it has been turned into a c# property it is set to false. I am guessing it is set as the property tries to call that xml value.
I have tried setting the default using an attribute.
[XmlElement("EasyPaySaveCardControlChecked")]
[DefaultValue(true)]
public bool ischecked { get; set; }
I have tried setting it using a constructor.
public className()
{
ischecked = true;
}
I have also tried making all the bools nullable and the value is still being set to false
none of these solutions work and I have no idea why. no matter what I do the property is set to false, if it was set to undefined it would be fine but bools have to defaulted to false
Try something like this:
function showSaveCardControl(ischecked) {
if ('undefined' === typeof ischecked) ischecked = true;
$(".saveCardControl").slideDown().find("input").prop("checked", ischecked);
}
this should do the trick :
function showSaveCardControl(ischecked) {
if(typeof ischecked == 'undefined')
ischecked = true;
$(".saveCardControl").slideDown().find("input").prop("checked", ischecked);
}
Assuming the property is part of a class then just set it's default value to true in the class constructor and it will be overwritten down the line if you have logic to set the value from the config.
public class LukesClass
{
public String whatever {get;set;}
public bool isChecked {get;set;}
public LukesClass()
{
isChecked = true;
}
}
Try using auto property initializers (C# 6.0 and higher):
public bool isRequired { get; set; } = true;
I had a single case where I needed an unspecified xml bool to import as true instead of false. The above code will result in isRequired being true when either the tags specify true, or when they do not exist. It will only be false when tags define it as false.
I am using DefaultValue attribute for the proper PropertyGrid behavior (it shows values different from default in bold). Now if I want to serialize shown object with the use of XmlSerializer there will be no entries in xml-file for properties with default values.
What is the easiest way to tell XmlSerializer to serialize these still?
I need that to support "versions", so when I change default value later in the code - serialized property gets value it had serialized with, not "latest" one. I can think about following:
Override behavior of PropertyGrid (use custom attribute, so it will be ignoreed by XmlSerializer);
Do sort of a custom xml-serialization, where ignore DefaultValue's;
Do something with object before passing it to XmlSeriazer so it won't contain DefaultValue's anymore.
But there is a chance I miss some secret property what allows to do it without much pain =D.
Here is an example of what I want:
private bool _allowNegative = false;
/// <summary>
/// Get or set if negative results are allowed
/// </summary>
[Category(CategoryAnalyse)]
[Admin]
[TypeConverter(typeof(ConverterBoolOnOff))]
//[DefaultValue(false)] *1
public bool AllowNegative
{
get { return _allowNegative; }
set
{
_allowNegative = value;
ConfigBase.OnConfigChanged();
}
}
//public void ResetAllowNegative() { _allowNegative = false; } *2
//public bool ShouldSerializeAllowNegative() { return _allowNegative; } *3
//public bool ShouldSerializeAllowNegative() { return true; } *4
If I uncomment (*1), then I have desired effect in PropertyGrid - properties with default values are displayed in normal text, otherwise text is bold. However XmlSerializer will NOT put properties with default value into xml-file and this is BAD (and I am trying to fix it).
If I uncomment (*2) and (*3), then it's totally same as uncommenting (*1).
If I uncomment (*2) and (*4), then XmlSerializer will always put properties into xml-file, but this happens because they do not have default value anymore and PropertyGrid shows all values in bold text.
As long as you don't need attributes in your Xml, if you use the DataContractSerializer instead you will get the behavior you desire.
[DataContract]
public class Test
{
[DataMember]
[DefaultValue(false)]
public bool AllowNegative { get; set; }
}
void Main()
{
var sb2 = new StringBuilder();
var dcs = new DataContractSerializer(typeof(Test));
using(var writer = XmlWriter.Create(sb2))
{
dcs.WriteObject(writer, new Test());
}
Console.WriteLine(sb2.ToString());
}
produces (minus namespaces etc)
<Test>
<AllowNegative>false</AllowNegative>
</Test>
You could use two properties:
// For property grid only:
[Category(CategoryAnalyse)]
[TypeConverter(typeof(ConverterBoolOnOff))]
[DefaultValue(false)]
[XmlIgnore]
public bool AllowNegative
{
get { return _allowNegative; }
set
{
_allowNegative = value;
ConfigBase.OnConfigChanged();
}
}
// For serialization:
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[TypeConverter(typeof(ConverterBoolOnOff))]
[XmlElement("AllowNegative")]
public bool AllowNegative_XML
{
get { return _allowNegative; }
set
{
_allowNegative = value;
ConfigBase.OnConfigChanged();
}
}
I believe what you are looking for is ShouldSerialize() and Reset(). Using these will expand your class a bit more (with two functions per property), however, it achieves specifically what you are looking for.
Here's a quick example:
// your property variable
private const String MyPropertyDefault = "MyValue";
private String _MyProperty = MyPropertyDefault;
// your property
// [DefaultValueAttribute("MyValue")] - cannot use DefaultValue AND ShouldSerialize()/Reset()
public String MyProperty
{
get { return _MyProperty; }
set { _MyProperty = value; }
}
// IMPORTANT!
// notice that the function name is "ShouldSerialize..." followed
// by the exact (!) same name as your property
public Boolean ShouldSerializeMyProperty()
{
// here you would normally do your own comparison and return true/false
// based on whether the property should be serialized, however,
// in your case, you want to always return true when serializing!
// IMPORTANT CONDITIONAL STATEMENT!
if (!DesignMode)
return true; // always return true outside of design mode (is used for serializing only)
else
return _MyProperty != MyPropertyDefault; // during design mode, we actually compare against the default value
}
public void ResetMyProperty()
{
_MyProperty = MyPropertyDefault;
}
Note that because you want to keep the PropertyGrid functionality in tact, you must know whether you are serializing or not when the ShouldSerialize() function is called. I suggest you implement some sort of control flag that gets set when serializing, and thus always return true.
Please note that you cannot use the DefaultValue attribute in conjunction with the ShouldSerialize() and Reset() functions (you only use either or).
Edit: Adding clarification for the ShouldSerialize() function.
Because there is currently no way to serialize a default value and let the PropertyGrid know that a property has its default value, you must implement a condition checking whether you are in design mode.
Assuming your class derives from a Component or Control, you have a DesignMode property which is set by Visual Studio at design time only. The condition looks as follows:
if (!DesignMode)
return true; // always return true outside of design mode (is used for serializing only)
else
return _MyProperty != MyPropertyDefault; // during design mode, we actually compare against the default value
Edit 2: We're not talking about Visual Studio's design mode.
With the above code in mind, create another property called IsSerializing. Set the IsSerializing property to true before calling XmlSerializer.Serialize, and unset it after.
Finally, change the if (!DesignMode) conditional statement to be if (IsSerializing).
This behaviour of the XmlSerializer can can be overwritten with
XmlAttributeOverrides
I borrowed the idea from here:
static public XmlAttributeOverrides GetDefaultValuesOverrides(Type type)
{
XmlAttributeOverrides explicitOverrides = new XmlAttributeOverrides();
PropertyDescriptorCollection c = TypeDescriptor.GetProperties(type);
foreach (PropertyDescriptor p in c)
{
AttributeCollection attributes = p.Attributes;
DefaultValueAttribute defaultValue = (DefaultValueAttribute)attributes[typeof(DefaultValueAttribute)];
XmlIgnoreAttribute noXML = (XmlIgnoreAttribute)attributes[typeof(XmlIgnoreAttribute)];
XmlAttributeAttribute attribute = (XmlAttributeAttribute)attributes[typeof(XmlAttributeAttribute)];
if ( defaultValue != null && noXML == null )
{
XmlAttributeAttribute xmlAttribute = new XmlAttributeAttribute(attribute.AttributeName);
XmlAttributes xmlAttributes = new XmlAttributes();
xmlAttributes.XmlAttribute = xmlAttribute;
explicitOverrides.Add(userType, attribute.AttributeName, xmlAttributes);
}
}
return explicitOverrides;
}
And made my self an an Attribute to decorate the classes which should emit the default values.
If you want do this for all classes, I'm sure you can adapt the whole concept.
Public Class EmitDefaultValuesAttribute
Inherits Attribute
Private Shared mCache As New Dictionary(Of Assembly, XmlAttributeOverrides)
Public Shared Function GetOverrides(assembly As Assembly) As XmlAttributeOverrides
If mCache.ContainsKey(assembly) Then Return mCache(assembly)
Dim xmlOverrides As New XmlAttributeOverrides
For Each t In assembly.GetTypes()
If t.GetCustomAttributes(GetType(EmitDefaultValuesAttribute), True).Count > 0 Then
AddOverride(t, xmlOverrides)
End If
Next
mCache.Add(assembly, xmlOverrides)
Return xmlOverrides
End Function
Private Shared Sub AddOverride(t As Type, xmlOverrides As XmlAttributeOverrides)
For Each prop In t.GetProperties()
Dim defaultAttr = prop.GetCustomAttributes(GetType(DefaultValueAttribute), True).FirstOrDefault()
Dim xmlAttr As XmlAttributeAttribute = prop.GetCustomAttributes(GetType(XmlAttributeAttribute), True).FirstOrDefault()
If defaultAttr IsNot Nothing AndAlso xmlAttr IsNot Nothing Then
Dim attrs As New XmlAttributes '= {New XmlAttributeAttribute}
attrs.XmlAttribute = xmlAttr
''overide.Add(t, xmlAttr.AttributeName, attrs)
xmlOverrides.Add(t, prop.Name, attrs)
End If
Next
End Sub
Because xsd.exe produces partial classes you can add this EmitDefaultValuesAttribute in seperate a file:
<EmitDefaultValuesAttribute()>
Public MyClass
Public Property SubClass() As MySubClass
End Class
<EmitDefaultValuesAttribute()>
Public MySubClass
End Class
Usage is as follows:
Dim serializer As New XmlSerializer(GetType(MyClass), EmitDefaultValuesAttribute.GetOverrides(GetType(MyClass).Assembly))
I'm writing an application, where I have quite a lot Properties of Type Boolean defined:
private bool kajmak = true;
public bool Kajmak
{
get { return kajmak ; }
set { kajmak = value; FirePropertyChanged(() => Kajmak); }
}
As you see, I set kajmak to true at the beginning..-the reason is nonrelevant-. (You might know that the default value of a bool variable is false).
Now, is there a way, to change the default value of a bool to true? So I would write:
private bool kajmak; //kajmak = true
instead of
private bool kajmak = true;
What could I do to achieve this?
C Sharp 6.0 has introduced a nice new way to do this:
public bool YourBool { get; set; } = true;
This is equivalent to the old way of:
private bool _yourBool = true;
public bool YourBool
{
get { return _yourBool; }
set { _yourBool = value; }
}
see this article http://blogs.msdn.com/b/csharpfaq/archive/2014/11/20/new-features-in-c-6.aspx
Because booleans are false by default, I use positive forms in my names, like IsInitialized, HasSomething etc. which I want to be false by default until I explicitly set them.
If you find you need something to be true by default, maybe you need to rename your variable so it makes more sense when the default is false.
In service:
public bool Kajmak { get; set; } = true;
No. There's no way to change the default value assigned by .NET. Your best bet is to either assign the appropriate default in the private member:
private book kajmak = false;
Or use the Constructor like you're supposed to and assign the class defaults there:
public class SomeClass
{
public SomeClass()
{
Kajmak = false;
}
public book Kajmak { get; set; }
}
No, there's no possibility to change the default value. If you could change the default-value, it wouldn't be the default anymore ;).
But to set the default-value to null, you could use this:
bool? kajmak;
But that's not what you want...
In the process of trying to do something similar, a colleague enlightened me to the bool? type. It can be true, false, or null, and does not object to being on the left side of such a comparator. This does not answer your question of how to default bool to true, but does solve your conceptual problem of wanting your variables to be definable as true by default.
I only post because this was the top result when I searched, and this information was helpful to me. Hopefully it will be to others who find this page.
You may create a class myBool that defaults to false and an implicit conversion from bool to your class.
As the topic suggests I have some problems with PropertyInfo.SetValue. To get to the point, here is my example - I have created my own class and the main thing about it is the presentation object:
using System;
using System.Reflection;
namespace TestingSetValue
{
public class Link
{
private object presentationObject = null;
private string captionInternal = string.Empty;
public Link (string caption)
{
captionInternal = caption;
}
public string CaptionInternal
{
get { return captionInternal; }
set { captionInternal = value; }
}
public bool Visible
{
get
{
if (PresentationObject != null)
{
PropertyInfo pi = PresentationObject.GetType().GetProperty("Visible");
if (pi != null)
{
return Convert.ToBoolean(pi.GetValue(PresentationObject, null));
}
}
return true;
}
set
{
if (PresentationObject != null)
{
PropertyInfo pi = PresentationObject.GetType().GetProperty("Visible");
if (pi != null)
{
pi.SetValue(PresentationObject, (bool)value, null);
}
}
}
}
public object PresentationObject
{
get { return presentationObject; }
set { presentationObject = value; }
}
}
}
Then, I do this:
private void btnShowLink_Click(object sender, EventArgs e)
{
Link link = new Link("Here I am!");
this.contextMenu.Items.Clear();
this.contextMenu.Items.Add(link.CaptionInternal);
link.PresentationObject = this.contextMenu.Items[0];
link.Visible = true;
lblCurrentVisibility.Text = link.Visible.ToString();
}
Now, I can imagine this doesn't look too logical/ economical, but it shows the essence of my real problem. Namely, why doesn't the visibility of presentation object (and the value of link.Visible) change, after I call:
link.Visible = true;
I simply do not know what else to do to make this work... Any help is deeply appreciated.
To make things even more interesting, the property Enabled behaves as expected of it...
PropertyInfo pi = PresentationObject.GetType().GetProperty("Enabled");
Could it be related to the fact that Visible is actually a property of ToolStripDropDownItem base base object, whereas Enabled is 'direct' property of ToolStripDropDownItem ?
It would have been easier to figure this out if you said upfront what class this is but now we know it is ToolStripDropDownItem which we can infer means WinForms.
What you are seeing is an oddity with the ToolStripItem's Visible property. It's setter & getter are not tied directly together. MSDN says
"The Available property is different from the Visible property in that
Available indicates whether the ToolStripItem is shown, while Visible
indicates whether the ToolStripItem and its parent are shown. Setting
either Available or Visible to true or false sets the other property
to true or false."
In other words, you want to use the Available property instead of the Visible property
Check http://msdn.microsoft.com/en-us/library/system.web.ui.control.visible.aspx. Maybe this is causing your problem.
There is very important piece of info:
If this property is false, the server control is not rendered. You should take this into account when organizing the layout of your page. If a container control is not rendered, any controls that it contains will not be rendered even if you set the Visible property of an individual control to true. In that case, the individual control returns false for the Visible property even if you have explicitly set it to true. (That is, if the Visible property of the parent control is set to false, the child control inherits that setting and the setting takes precedence over any local setting.)