I have defined a Value Converter in my PCL like this:
class EmployeeToStringValueConverter : MvxValueConverter<Employee, string>
{
protected override string Convert(Employee value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString();
}
}
And I'm using it in an Android .axml layout like this:
local:MvxBind="Text EmployeeToString(SearchResult)"
(SearchResult is defined in the ViewModel as a public Employee property)
But it is not working (meaning: if I put a breakpoint in the Converter call, it is never executed).
However, I've also defined the following converter:
public class NegateBoolValueConverter : MvxValueConverter<bool, bool>
{
protected override bool Convert(bool value, Type targetType, object parameter, CultureInfo culture)
{
return !value;
}
}
And I'm using it like so:
local:MvxBind="Enabled NegateBool(IsLoggedIn)"
(IsLoggedIn is a bool public property in the ViewModel)
And this works perfectly.. Any idea so as to what may be going on with the first one that's not working?
I believe you are missing a public access modifier on your converter
Changing
class EmployeeToStringValueConverter : MvxValueConverter<Employee, string>
to
public class EmployeeToStringValueConverter : MvxValueConverter<Employee, string>
should do the trick.
Related
I have implemented a Xamarin Forms SearchHandler in my Shell project. I want to be able to "hide" it (and unhide it). There is no IsVisible property on it - any ideas how to hide the SearchHandler control?
I figured it out - the property is actually SearchBarVisibility.
In my case, I created a value converter to and bound SearchBarVisibility to a property in my ViewModel.
My ValueConverter looks like this:
public class SearchVisibleConvert : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
SearchBoxVisibility searchBoxVisibility = SearchBoxVisibility.Expanded;
if (value != null)
{
switch (value)
{
case "Hidden":
searchBoxVisibility = SearchBoxVisibility.Hidden;
break;
case "Collapsible":
searchBoxVisibility = SearchBoxVisibility.Collapsible;
break;
default:
searchBoxVisibility = SearchBoxVisibility.Expanded;
break;
}
}
return searchBoxVisibility;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
My xaml looks like this:
<Shell.SearchHandler>
<controls:RouteSearchHandler
x:Name="RouteSearch"
BackgroundColor="White"
DisplayMemberName="Street1"
SearchBoxVisibility="{Binding TopSearchVisibility, Converter={StaticResource visibleConvert}}"
ShowsResults="True" />
</Shell.SearchHandler>
To set the Date attribute in xaml equal today we can use Today attribute as following:
xmlns:system="clr-namespace:System;assembly=mscorlib"
<DatePicker Date="{x:Static system:DateTime.Today}"/>
I've tried to set it by using AddDays method but it couldn't help.
<DatePicker Date="{x:Static system:DateTime.Today.AddDays(-1)}"/> Does not work.
So is there a way?
After some discussions the best answer I have found is using a helper like following:
In xaml:
xmlns:helpers="clr-namespace:Helpers"
<DatePicker Date="{x:Static helpers:DateTimeHelper.Yesterday}"/>
While helper is:
namespace Helpers
{
public class DateTimeHelper {
public static System.DateTime Yesterday
{
get { return System.DateTime.Today.AddDays(-1); }
}
}
}
You can set the date from the controller.
<DatePicker x:Name="PostingDatePicker" />
PostingDatePicker.Date = DateTime.Today.AddDays(-1);
Another way is that you bind the date from your ViewModel,
Xaml
<DatePicker x:Name="PostingDatePicker" Date="{Binding PostingDate}"/>
ViewModel
public DateTime PostingDate {get; set;}
PostingDate = DateTime.Today.AddDays(-1);
Updated Answer:
If you want to update the date only through XAML, you can use converters,
<DatePicker x:Name="PostingDatePicker" Date="{Binding PostingDate, Converter={local:DateConverter}}"/>
create a class which inherits IValueConverter,
public class DateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
return DateTime.Today.AddDays(-1);
}
catch (Exception)
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
At runtime, your datepicker date will be updated with yesterday's date.
I get the following exception when I send a simple JSON structure implementing the interface IMessage:
Could not create an instance of type TestService2.IMessage. Type is an interface or abstract class and cannot be instantiated. Path 'Id', line 2, position 7.
I absolutely agree that using classes is the way to go!
If, however, for some obscure/Stupid reason, you have to use interfaces like me, there is a simple way of mapping it to a class with JSON.
In the Startup Method, define the Contracts for the interface:
services.AddMvc()
.AddJsonOptions(o => { o.SerializerSettings.ContractResolver.ResolveContract(typeof(IMessage)).Converter = new MyJsonConverter<IMessage, Message>();})
Where IMessage is said interface, and MyJsonConverter is derived from JsonConverter, for example:
public class MyJsonConverter<Tin, Tout> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
//Your logic here
return (objectType == typeof(Tin) );
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
//deserializing from the implementation Class
return serializer.Deserialize<Tout>(reader);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//use standard serialization
serializer.Serialize(writer, value);
}
}
I'm building an OData v3 Web API with Entity Framework 6.0 Code First.
Everything works well and I can execute CRUD operations back to the api server.
However I'm using Spatial Types and some of my entities have DbGeometry properties. When I try to update/post an entity with a DbGeometry type from a client application (just a console application for tests) I get this DataServiceRequestException:
No parameterless constructor defined for this object.
It took me a while but I identified the DbGeometry type as the responsible. I already looked at this topic here and made a custom JsonConverter, where I applied to the property:
[Required]
[JsonConverter(typeof(DbGeometryConverter))]
[Column("geometria")]
public DbGeometry Geometria { get; set; }
That didn't worked. The object is not deserialized on the web api server unless I remove the DbGeometry property.
I also tried to change the Global json serializer behavior
var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
jsonFormatter.SerializerSettings.Converters.Add(new DbGeometryConverter());
Also futile. I really need the DbGeometry properties. What else can I do to work around this issue?
A little late, but for those who'll seek an answer:
I've managed to do it with the exact same code on a controller level. The idea was taken from this SO Question&Answer.
So, here is the code including the DbGeometryConverter.
DbGeometryConverter.cs:
public class DbGeometryConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsAssignableFrom(typeof(DbGeometry));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var location = JObject.Load(reader);
var token = location["Geometry"]["WellKnownText"];
string geom = token.ToString();
token = location["Geometry"]["CoordinateSystemId"];
int srid = token != null ? int.Parse(token.ToString()) : 0;
var converted = DbGeometry.FromText(geom, srid);
return converted;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanWrite => false;
}
CustomJsonAttribute.cs:
public class CustomJsonAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
var formatter = controllerSettings.Formatters.JsonFormatter;
formatter.SerializerSettings.Converters.Add(new DbGeometryConverter());
}
}
And [CustomJson] attribute on a controller that uses DbGeometry.
I'm trying to bind a TextBlock to a TimeSpan, but I need to format is so that if TotalMinutes is less then 60 it should show "X min" else it should show "X h".
Its it possible? That might require tom logic test in the xaml?
You should use custom IValueConverter implementation. There are several tutorials about that, e.g. Data Binding using IValueConverter in Silverlight.
Your IValueConverter implementation should look like that:
public class TimeSpanToTextConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is TimeSpan))
throw new ArgumentException("value has to be TimeSpan", "value");
var timespan = (TimeSpan) value;
if (timespan.TotalMinutes > 60)
return string.Format("{0} h", timespan.Hours.ToString());
return string.Format("{0} m", timespan.Minutes.ToString());
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}