Cant set formatString in SmartDate?

Cant set formatString in SmartDate?

Old forum URL: forums.lhotka.net/forums/t/7688.aspx


Nemisis posted on Monday, September 28, 2009

Hi everyone, i have the following code

Private Shared FailedDateProperty As BSLPropertyInfo(Of SmartDate) = RegisterProperty(New BSLPropertyInfo(Of SmartDate)("FailedDate"))
Public ReadOnly Property FailedDate() As String
    Get
        Return GetPropertyConvert(Of SmartDate, String)(FailedDateProperty)
    End Get
End Property

But i want to return this particular date in a different format to the other SmartDates throughout the system.  In my DataPortal_Create method i have the following code to create a new smartdate with the format string that i want.

Dim failDate As New SmartDate(True)
failDate.FormatString = "f"
LoadProperty(FailedDateProperty, passwordDate)

Now i have to load the value in my DataPortal_Fetch method using this:

LoadProperty(Of SmartDate)(FailedProperty, .GetSmartDate("FailedDate"))

but i cannot figure out how to set FormatString property of the managed field?  I get an error from intellisense saying "Expression is a value and therefore cannot be a target of an assignment"

I have tried the following lines.

ReadProperty(Of SmartDate)(FailedDateProperty).FormatString = "f"
GetProperty(Of SmartDate)(FailedDateProperty).FormatString = "f"

Sorry if i am having a stupid moment, it is a monday afterall.

Is it a case that i should be loading the value into a variable, setting the formatstring and then loading the variable into my managed field?

RockfordLhotka replied on Tuesday, September 29, 2009

The get/read/load/set helpers should maintain whatever format you set initially for the default SmartDate value of the property. And they should maintain whether empty means infinitely large or small.

In other words, you should be able to specfy a default SmartDate value on the RegisterProperty() call to define the basic settings of the value.

rfcdejong replied on Wednesday, July 14, 2010

Ok this is an old topic, but i've the same problem.. and there isn't a solution if u ask me.
I tried to set a default SmartDate in the RegisterProperty() but the SmartDate is lacking a constructor to set the formatstring

This is the code in the business object.

internal
static PropertyInfo<SmartDate> DtmExportEndProperty = RegisterProperty<SmartDate>(c => c.DtmExportEnd, "Einddatum export", new SmartDate());
public string DtmExportEnd
{
   
get { return GetPropertyConvert<SmartDate, string>(DtmExportEndProperty); }
}


For now a workaround while loading it

var exportEnd = new SmartDate(dbItem.DtmExportEnd, true);
exportEnd.FormatString =
"f";
LoadProperty(item,
ExportInfoItem.DtmExportEndProperty, exportEnd);

PS: Somehow noone within the company is using the SmartDate, most people just use DateTime or Nullable<DateTime> and have a valueconverter in wpf.. but i just wanted to use the SmartDate :)

RockfordLhotka replied on Wednesday, July 14, 2010

How about this:

new SmartDate { Format = "d" }

 

rfcdejong replied on Wednesday, July 14, 2010

i tried it, but it still shows the default format 

internal static PropertyInfo<SmartDate> DtmExportStartProperty = RegisterProperty<SmartDate>(c => c.DtmExportStart, "Startdatum van de export", new SmartDate() { FormatString = "g" });

The SmartDate doesn't seem to work, i solved it without a SmartDate and without wpf valueconverter.
Not really how i want it..

return GetProperty(DtmExportStartProperty).HasValue ? GetProperty(DtmExportStartProperty).Value.ToString("g", CultureInfo.CreateSpecificCulture("nl-NL")) : string.Empty;

RockfordLhotka replied on Wednesday, July 14, 2010

SmartDate is primarily intended for use in creating a string property, not a public SmartDate property:

  [Serializable]
  public class SDtest : BusinessBase<SDtest>
  {
    public static PropertyInfo<Csla.SmartDate> TextDateProperty =
      RegisterProperty<Csla.SmartDate>(c => c.TextDate, null, new Csla.SmartDate { FormatString = "g" });
    public string TextDate
    {
      get { return GetPropertyConvert<Csla.SmartDate, string>(TextDateProperty); }
      set { SetPropertyConvert<Csla.SmartDate, string>(TextDateProperty, value); }
    }
  }

In this case the format is preserved, because SetPropertyConvert() understands how to preserve the format of an existing SmartDate as it updates the value.

If you are directly exposing the SmartDate value, then you need to understand and deal with more detail on your own.

Before I go further, I really must question why you'd expose a SmartDate directly? What are you gaining that you can't get by using the nullable DateTime? type?

SmartDate is a value type, not a reference type. So when you expose a SmartDate property, you must understand that .NET uses value type semantics when working with the property.

What this means is that when you set the property, you are setting it to a new SmartDate value.

obj.MyDate = DateTime.Now; // casts the DateTime to a new SmartDate

The key here is to understand that C# (or VB) does an implicit cast of DateTime.Now into a new SmartDate instance, which is then assigned to the property.

Of course this new SmartDate is entirely unaware of the previous value - they are completely separate values. So there's no way for this new SmartDate to mystically know about the state of the previous property value - they are completely separate values.

So you've set the FormatString on one SmartDate - but that has no impact on other SmartDate values in your application.

One solution is to interact with the existing SmartDate value rather than setting the property to a new SmartDate:

obj.MyDate.Date = DateTime.Now; // sets the existing SmartDate value to a new value

This approach means your property has the same value - the same SmartDate - but the SmartDate itself now has a new Date (and therefore Text) value.

Another solution is to do what SetPropertyConvert() does, which is to understand the special semantics of SmartDate. What I mean by this, is that SetPropertyConvert() knows to initialize the new SmartDate with the state of the previous SmartDate value, including FormatString.

Yet another solution is to call the static SetDefaultFormatString method of the SmartDate type to globally set the default format string for all SmartDate values across your entire application.

rfcdejong replied on Friday, July 16, 2010

hmm.. i never sad i was exposing the SmartDate property directly.
Anyway, since noone was using the SmartDate i was just going to see if it's "smart" to use it in our projects.

The SetDefaultFormatString isn't that good because mostly it's ok to have only the Date and not the Time.

Below didn't... with LoadProperty(), but it might work with SetPropertyConvert, maybe even with LoadPropertyConvert, but i didn't use that.

internal static PropertyInfo<SmartDate> DtmExportStartProperty = RegisterProperty<SmartDate>(c => c.DtmExportStart, "Startdatum van de export", new SmartDate() { FormatString = "g" });
public string DtmExportEnd
{
   
get { return GetPropertyConvert<SmartDate, string>(DtmExportEndProperty); }
}

RockfordLhotka replied on Friday, July 16, 2010

It is the zzzConvert() methods that do the work of converting the value safely, so it won't do what you want if you use anything other than those methods.

SetProperty/LoadProperty/etc all follow the normal .NET behaviors for value types as I described in my previous post.

Russ replied on Friday, July 16, 2010

Here is a simple way that I use to change the format of a smartdate property. 

private static PropertyInfo<SmartDate> CreatedDateProperty =

    RegisterProperty<SmartDate>(c => c.CreatedDate, "Created Date");

public string CreatedDate

{

  get { return GetProperty(CreatedDateProperty).ToString("dd-MMM-yyyy hh:mm tt"); }

  set { SetPropertyConvert<SmartDate, string>(CreatedDateProperty, value); }

}

 Hope this helps.

Russ.

decius replied on Wednesday, August 18, 2010

Russ

Here is a simple way that I use to change the format of a smartdate property. 

private static PropertyInfo<SmartDate> CreatedDateProperty =

    RegisterProperty<SmartDate>(c => c.CreatedDate, "Created Date");

public string CreatedDate

{

  get { return GetProperty(CreatedDateProperty).ToString("dd-MMM-yyyy hh:mm tt"); }

  set { SetPropertyConvert<SmartDate, string>(CreatedDateProperty, value); }

}

 Hope this helps.

Russ.

 

I ran into this same problem. This was also the path I started going down, but wasn't confident I wasn't missing some kind of logic that the GetPropertyConvert method encapsulated... This solution, of course, assumes that the SmartDate is never null which I suppose could be argued to be bad practice. But this solves my problem easily.... Seeing someone else suggest the same thing makes me feel a little safer.

With this though, I have to wonder, what was really the purpose of creating the GetPropertyConvert method if the above syntax is indeed deemed appropriate?

 

 

 

RockfordLhotka replied on Wednesday, August 18, 2010

Various parts of CSLA have evolved over the past decade, including property syntax and SmartDate. I've tried to keep them all working together as much as possible, but I can't change the way things like core .NET work.

Value types are what they are. They might sometimes seem like reference types, but they aren't.

SmartDate is a value type, which comes with specific semantics we have to live with.

SetPropertyConvert() does include some special coding to try and preserve metastate properties like the format string as the value is set. This is absolutely not normal .NET behavior - it is something I've added in an effort to preserve a level of backward compatibility with the way SmartDate has traditionally been used - while also allowing people to use the new property syntax.

That's clearly not a perfect solution. My only meaningful alternative is to just drop the whole thing - maybe even drop SmartDate entirely (though I use it a lot, so I really don't consider that an alternative). But I could just say that, like other simple value types, SmartDate just works as it does, and if you need to do special formatting you have to do that in your own code - and the reality is that you may have to do that anyway.

If you have a workable solution I'm entirely open to it though - if there's a way to make things better that's great!

Copyright (c) Marimer LLC