Using setter in ViewModel using another property - c#

I have the following ViewModel in my app and there is two BirthDate property (with / without time). When using set { } without body I encounter "Not using the value means that the accessor ignores the caller's intent which could cause unexpected results at runtime.". Then I added a private property and update set as set { birthDateWithTime = value; }. However, this time birthDateWithTime private property not sees to be used. Is there any mistake regarding to implementation below? I want to use both property separately and do not want to convert in JavaScript or code.
public class DemoViewModel
{
public int Id { get; set; }
public DateTime BirthDate { get; set; }
private string birthDateWithTime;
public string BirthDateWithTime {
get { return BirthDate.ToString("dd/MM/yyyy - HH:mm"); }
set { birthDateWithTime = value; }
}
}

#Gabriel Llorico answer is correct. or maybe you can try another one.
private DateTime _birthDate;
public DateTime BirthDate{
get{
return _birthDate;
}
set{
this._birthDate = value;
this.BirthDateWithTime = this._birthDate.ToString("dd/MM/yyyy - HH:mm");
}
}
public string BirthDateWithTime{get;set;}

try this if it is solely dependent on BirthDate
public string BirthDateWithTime
{
get
{
return BirthDate.ToString("dd/MM/yyyy - HH:mm");
}
}

Or just use a body-property style.
public string BirthDateWithTime => BirthDate.ToString("dd/MM/yyyy - HH:mm");

If you need to set BirthDateWithTime, just set in the BirthDate property, so both are updated.

Related

XML Deserialization and string format

I have an XML like this:
"<ArrayOfClsLog xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
<ClsLog>
<Subject>sth</Subject>
<Value>123456</Value>
<Comment>val</Comment>
</ClsLog>
</ArrayOfClsLog>"
and with this code I desterilize it:
var tmpSerializer = new XmlSerializer(typeof(ObservableCollection<ClsLog>));
tmpResult = tmpSerializer.Deserialize(tmpReader) as ObservableCollection<ClsLog>;
here is my ClsLog:
public class ClsLog
{
public string Subject { get; set; }
public string Value {get; set;}
public string Comment { get; set; }
}
Everything is fine except:
Big Problem
I want the content of value which can be a number like 123456 converts into 123,456
So I've changed Clslog to :
public class ClsLog
{
public string Subject { get; set; }
public string Value {
get
{
return decimal.Parse(Value.ToString()).ToString("N2", System.Globalization.CultureInfo.InvariantCulture);
}
set
{ }
}
public string Comment { get; set; }
}
But nothing changed, also I've tried to change tmpResult with LINQ:
tmpResult=tmpResult.ToList().ForEach(i => i.Value =
decimal.Parse( i.Value.ToString()).ToString("N2", System.Globalization.CultureInfo.InvariantCulture));
So bad exception happened and turned out I can't change it manually.
Question
How I can fix it? (make value from 123456 to 123.456)
You are declaring this property wrong.
public string Value //why a string why not a decimal?
{
get
{
// you have an infinite recursion here
return decimal.Parse(Value.ToString()).ToString("N2", System.Globalization.CultureInfo.InvariantCulture);
}
set { } // the setter is empty anyway so youcan't set it.
}
Instead try this
private decimal _value; // internal field
public decimal Value
{
get
{
return _value; // return internal field
}
set
{
_value = value / 1000; // set the internal field to the value / 1000
}
}

Setting only a setter property

I have an object model that has a property like this:
public class SomeModel
{
public string SomeString { get; set; }
public void DoSomeWork()
{
....
}
}
I want the DoSomeWork function to execute automatically after the SomeString property changes. I tried this but it's not working:
public string SomeString { get; set { DoSomeWork(); } }
What's the correct syntax?
Use a private field instead, like this ...
public class SomeModel
{
private string someString = "";
public string SomeString {
get { return this.someString; }
set {
this.someString = value;
this.DoSomeWork();
}
}
public void DoSomeWork()
{
....
}
}
You can't do this with automatic properties - you'll have to create a "manual" property backed by a field.
private string _someString;
public string SomeString
{
get { return _someString; }
set
{
_someString = value;
DoSomeWork();
}
}
If you really can't deal with this boilerplate (say you'd have to do this hundreds of times), consider using an AOP framework like PostSharp to implement this on your behalf - you'd just need to declare an automatic property and an attribute to get the binary rewriter to implement the desired scheme.
This will work...
private string _someString;
public string SomeString { get { return _someString; } set { _someString = value; DoSomeWork(); } }
private string _someString;
public string SomeString
{
get
{
return _someString;
}
set
{
DoSomeWork();
_someString = value;
}
}
C# team has introduced the auto-implement properties in C# 3.0. with the logic of minimizing the model making which is backed by an anonymous field created by compiler. this one is used when you don't need to implement any additional logic on a property of an object class. so it just followed as.
public string Name{ get; set;}// auto-implemented property. no additional logic.
if we want to add some logic as you want to add one function. we must be writing a manual property backed by a private field as like below.
private string _Name;
public string Name
{
get {return _Name;}
set {
_Name=value;
DoSomething(); //Additional logic implemented.
}
}

How can I make it so my field is only set the one time?

I have a field in my model class that's coded as follows:
public string CreatedBy
{
get { return _CreatedBy; }
set { _CreatedBy = value; Created = DateTime.Now; }
}
public DateTime? Created { get; set; }
When the CreatedBy field is populated then it fills out the Created date automatically. The problem for me is that if I again set the CreatedBy field (yes it can happen) then the date gets updated with the current date again.
Is there a way that I can make it so the CreatedBy and the Created fields can be populated just once?
Can't you check, within the set, whether there is already a value and simply not set the new value?
Use a backing field and check whether the value has been set already - if so, leave it unchanged:
private DateTime? created;
public DateTime? Created
{
get { return created; }
set { if (created == null) created = value; }
}
Make use of constructor and iniailize the property to defult value you want
public classConstructor()
{
propertyName = defaultValue;
}
Here's a quick way: use the ?? operator. If Created is null, it will go to DateTime.Now.
public string CreatedBy
{
get { return _CreatedBy; }
set { _CreatedBy = value; Created = Created ?? DateTime.Now; }
}
public DateTime? Created { get; set; }
In that case it would probably be best to include CreatedBy in the constructor. This would imply "create-time" semantics:
public string CreatedBy
{
get;
private set;
}
public DateTime? Created
{
get;
private set;
}
public Model(..., string createdBy)
{
this.CreatedBy = createdBy;
this.Created = DateTime.Now;
}
// another option, if you don't like the ctor route
public void AssignCreator(string createdBy)
{
if (this.Created.HasValue) throw new InvalidOperationException();
this.CreatedBy = createdBy;
this.Created = DateTime.Now;
}
Your other option would be to throw an InvalidOperationException in the property setter if Created is non-null.

Can I simplify this C# in my ViewModel?

In my code I have the following:
viewModel.Note.Modified = DateTime.Now;
viewModel.Note.ModifiedBy = User.Identity.Name;
and in my view:
[DisplayName("Modified")]
public DateTime Modified { get; set; }
[DisplayName("Modified By")]
public string ModifiedBy { get; set; }
Could I just have my code change ModifiedBy and then have some code that runs in the ViewModel that changes the date of Modified when the Modified by is changed?
The way to do this will depend on how much logic you want in your view. If you don't mind some logic there, you can do something like this:
[DisplayName("Modified")]
public DateTime Modified { get; set; }
private string m_ModifiedBy
[DisplayName("Modified By")]
public string ModifiedBy {
get { return m_ModifiedBy; }
set{ m_ModifiedBy = value; Modified = DateTime.Now; }
}
If you want the logic in your ViewModel, you can do something like this: ( assuming that viewModel is a class variable )
public void SetModifiedBy(string modifiedBy) {
viewModel.Note.Modified = DateTime.Now;
viewModel.Note.ModifiedBy = modifiedBy;
}
Then you would just call SetModifiedBy(User.Identity.Name) and both values would be updated.
If viewModel.Note is a reference to a NoteViewModel instance, then you can use the following:
public class NoteViewModel{
private DateTime? m_Modified;
private string m_ModifiedBy;
// note that you do not need the DisplayNameAttribute, because the default
// display name is the property name
public DateTime Modified {
get { return m_Modified ?? DateTime.Now; }
}
[DisplayName("Modified By")]
public string ModifiedBy {
get { return m_ModifiedBy ?? string.Empty; }
set {
if(value!=null) {
m_ModifiedBy = value;
m_Modified = DateTime.Now;
}
}
}
}
Then in your "code" (I'm guessing you meant the controller?), you can just do:
viewModel.Note.ModifiedBy = User.Identity.Name;
and you will have the intended result.
Side Note: Depending on the audience of your application, you may want to consider using DateTime.UtcNow for localization purposes. DateTime.Now will return the current DateTime on the server, which is dependent on the server's location. If you are displaying this data to the user, it is likely that you will want to either (a) specify the time zone, or (b) localize the time to the time zone of the client machine

DateTime How To

When creating a class what is the syntax to define a public property for that class as a DateTime type rather than string?
If you want a date object, with class-controlled formatting, you need two properties:
public DateTime DateField { get; set; }
// a read only string
public String DateFieldString {
get { return DateField.ToString(/* your format */); }
}
EDIT
ASP.NET: BoundField's DataFormatString property looks to be what you want.
<asp:BoundField
DataField="EventDate"
HeaderText="Event Date"
DataFormatString="{0:MM/dd/yyyy}"/>
Easy as (pumpkin) pie. Happy Thanksgiving!
public class MyClass {
public DateTime MyDate { get; set; }
public string MyFormattedDate { get { return MyDate.ToString(myFormat); } }
}
Something like
public class TestClas
{
DateTime dtDate;
public DateTime DtDate
{
get
{
return dtDate;
}
set
{
dtDate = value;
}
}
}
and to get and set the field you can use
TestClas objDate = new TestClas();
// set date
objDate.DtDate = DateTime.Now;
// get date
DateTime dtCurDate = objDate.DtDate;
Edit
It would be better not to implement the formatting inside the property. Make the formatting inside the gridview. Otherwise if you need another formatting then you would have to create another property.
using System;
public class Customer {
private DateTime createDate;
public DateTime CreateDate {
get { return createDate; }
set { createDate = value; }
}
}

Categories

Resources