Is it possible to bind data using Type-Qualified (see Single Property, Attached or Otherwise Type-Qualified section) syntax in WinRT?
What I want to get is to have possibility to bind to an item of my ViewModel which is an interface:
public interface IViewModel {
INewsContainer ItemHost {get;}
}
public interface INewsContainer {
ObservableCollection<INews> News {get;}
}
class ViewModel: IViewModel, INewsContainer {
// ....
public INewsContainer ItemHost { get { return this; } }
// ...
ObservableCollection<INews> news;
ObservableCollection<INews> INewsContainer.News { get { return news; } }
}
Normally, in WPF binding like the following one works fine (assuming DataContext is an instance of ViewModel):
<ListView Grid.Column="1"
ItemsSource="{Binding Path=ItemHost.(vm:INewsContainer.News)}" />
But if I try doing so in WinRT it fails with log in Immediate Window:
A first chance exception of type 'Windows.UI.Xaml.Markup.XamlParseException' occurred (...) Failed to assign to property 'Windows.UI.Xaml.Data.Binding.Path'. [Line: 35 Position: 17]
"Regular" binding, i.e. Path=ItemHost.News doesn't work either. It states that News property cannot be found in an instance of class ViewModel.
Workaround
This workaround works fine but I really hate having a converter over here :(
If you want to do that, you need to implement the interface both explicitly and implicitly.
Like this:
public interface IViewModel
{
string Name { get; set; }
}
public class ViewModel : IViewModel
{
public ViewModel()
{
(this as IViewModel).Name = "Jerry";
}
public string Name
{
get { return (this as IViewModel).Name; }
set { (this as IViewModel).Name = value; }
}
string IViewModel.Name { get; set; }
}
Then you can do this
<Grid Background="Black">
<Grid.DataContext>
<local:ViewModel/>
</Grid.DataContext>
<TextBlock Text="{Binding Name}" />
</Grid>
Read: http://msdn.microsoft.com/en-us/library/aa288461(v=vs.71).aspx
Best of luck.
Related
When I follow the FluentValidation docs and copy the FluentValidationm error to the ModelState dictionary, only simple properties will cause asp-validation-for attributes to work. When I use a complex property it will not work unless I prepend the class name to the ModelState key.
.NET 7, FluentValidation 11.4.0, RazorPages.
HTML
<form method="post">
<div asp-validation-summary="All"></div>
<input type="text" asp-for="Sample.TestValue" />
<!-- Wont work unless prepend "Sample" to ModelState dictionary error key -->
<span asp-validation-for="Sample.TestValue"></span>
<button type="submit">Do it</button>
</form>
CodeBehind
namespace ValForTest.Pages;
using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
public class SampleValidator : AbstractValidator<Sample>
{
public SampleValidator()
{
RuleFor(x => x.TestValue)
.MaximumLength(1);
}
}
public class Sample
{
public string? TestValue { get; set; }
}
public class IndexModel : PageModel
{
[BindProperty]
public Sample Sample { get; set; }
public void OnPost()
{
var validator = new SampleValidator();
var result = validator.Validate(this.Sample);
foreach (var error in result.Errors)
{
this.ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
// This works!!! Code smell though. Better way to do this??
// this.ModelState.AddModelError($"{nameof(Sample)}.{error.PropertyName}", error.ErrorMessage);
}
}
public void OnGet() { }
}
Result:
asp-validation-summary works, asp-validation-for does not.
However, if I uncomment my // this works line where I add the "fully qualified" property name which includes the complex class name, then it will show the asp-validation-for span:
How can I tell FluentValidation to add the class name to the properties?
I am trying to get the input from a text box from the backoffice console.What is the proper way to get the input?
I tried following the link:
https://hybrisdiary.com/2018/10/15/backoffice-customization/
public class MyCustomInputController extends DefaultWidgetController
{
private Textbox textInput;
#Override
public void initialize(final Component comp)
{
super.initialize(comp);
}
#ViewEvent(componentID = "submitButton", eventName = Events.ON_CLICK)
public void doOperation()
{
textInput.getText()
//This is throwing a Null Pointer Exception
}
}
Expected result : Getting input from the following field:
<textbox id="textInput"/>
Actual result : Null pointer rexception
Individual back-office elements must be declared with #Wire annotation.
#Wire
private Textbox textInput;
I am creating a rule set engine that looks kinda like a unit test framework.
[RuleSet(ContextA)]
public class RuleSet1
{
[Rule(TargetingA)]
public Conclusion Rule1(SubjectA subject)
{ Create conclusion }
[Rule(TargetingA)]
public Conclusion Rule2(SubjectA subject)
{ Create conclusion }
[Rule(TargetingB)]
public Conclusion Rule3(SubjectB subject)
{ Create conclusion }
}
[RuleSet(ContextB)]
public class RuleSet2
{
[Rule(TargetingB)]
public Conclusion Rule1(SubjectB subject)
{ Create conclusion }
[Rule(TargetingA)]
public Conclusion Rule2(SubjectA subject)
{ Create conclusion }
[Rule(TargetingB)]
public Conclusion Rule3(SubjectB subject)
{ Create conclusion }
}
public class Conclusion()
{
// Errorcode, Description and such
}
// contexts and targeting info are enums.
The goal is to create an extensible ruleset that doesn't alter the API from consumer POV while having good separation-of-concerns within the code files. Again: like a unit test framework.
I am trying to create a library of these that expose the following API
public static class RuleEngine
{
public static IEnumerable<IRuleSet> RuleSets(contextFlags contexts)
{
{
return from type in Assembly.GetExecutingAssembly().GetTypes()
let attribute =
type.GetCustomAttributes(typeof (RuleSetAttribute), true)
.OfType<RuleSetAttribute>()
.FirstOrDefault()
where attribute != null
select ?? I don't know how to convert the individual methods to Func's.
}
}
}
internal interface IRuleset
{
IEnumerable<Func<SubjectA, Conclusion>> SubjectARules { get; }
IEnumerable<Func<SubjectB, Conclusion>> SubjectBRules { get; }
}
...which allows consumers to simply use like this (using foreach instead of LINQ for readability in this example)
foreach (var ruleset in RuleEgine.RuleSets(context))
{
foreach (var rule in ruleset.SubjectARules)
{
var conclusion = rule(myContextA);
//handle the conclusion
}
}
Also, it would be very helpful if you could tell me how to get rid of "TargetingA" and "TargetingB" as RuleAttribute parameters and instead use reflection to inspect the parameter type of the decorated method directly. All the while maintaining the same simple external API.
You can use Delegate.CreateDelegate and the GetParameters method to do what you want.
public class RuleSet : IRuleSet
{
public IEnumerable<Func<SubjectA, Conclusion>> SubjectARules { get; set; }
public IEnumerable<Func<SubjectB, Conclusion>> SubjectBRules { get; set; }
}
public static class RuleEngine
{
public static IEnumerable<IRuleSet> RuleSets() // removed contexts parameter for brevity
{
var result = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.GetCustomAttributes(typeof(RuleSetAttribute), true).Any()
let m = t.GetMethods().Where(m => m.GetCustomAttributes(typeof(RuleAttribute)).Any()).ToArray()
select new RuleSet
{
SubjectARules = CreateFuncs<SubjectA>(m).ToList(),
SubjectBRules = CreateFuncs<SubjectB>(m).ToList()
};
return result;
}
}
// no error checking for brevity
// TODO: use better variable names
public static IEnumerable<Func<T, Conclusion>> CreateFuncs<T>(MethodInfo[] m)
{
return from x in m
where x.GetParameters()[0].ParameterType == typeof(T)
select (Func<T, Conclusion>)Delegate.CreateDelegate(typeof(Func<T, Conclusion>), null, x);
}
Then you can use it like this:
var sa = new SubjectA();
foreach (var ruleset in RuleEngine.RuleSets())
{
foreach (var rule in ruleset.SubjectARules)
{
var conclusion = rule(sa);
// do something with conclusion
}
}
In your LINQ query you headed straight for RuleSetAttribute, and so lost other information. If you break the query in several lines of code you can get methods from the type with GetMethods(), and then you can call GetCustomAttribute<RuleAttribute>().
I've been bumbling along with EF5 but I cant seem to get two domain classes to map to a single database table.
The error I get is:
Message: "The type 'Basd.Erp.Wms.Purchasing.SupplierProfile' has already been configured as an entity type. It cannot be reconfigured as a complex type."
This is my DbContext:
public class PurchasingContext : DisconnectedEntityContext
{
public DbSet<SupplierCard> Suppliers { get; set; }
public DbSet<PurchaseCategory> PurchaseCategories { get; set; }
public PurchasingContext() : this("Basd.Erp.Wms") { }
public PurchasingContext(string connectionStringName) : base(connectionStringName) { }
public static PurchasingContext GetInstance(EfDataProvider provider) { return new PurchasingContext(provider.ConnectionStringName); }
}
}
These are my classes:
namespace Basd.Erp.Wms.Purchasing
{
public class SupplierCard : ContactCard, ISupplierCard
{
private ICollection<PurchaseCategory> _purchaseCategories;
public ICollection<PurchaseCategory> PurchaseCategories
{
get { return _purchaseCategories; }
set { SetNotifyField(ref _purchaseCategories, value, () => PurchaseCategories); }
}
public SupplierProfile Profile { get; protected set; }
private SupplierCard()
{
this.Profile = new SupplierProfile();
this.PurchaseCategories = new Collection<PurchaseCategory>();
}
public SupplierCard(long id, string alf, string name)
: this(id, alf, new SimpleNameHolder(name), new Collection<IPhysicalAddress>(), new DigitalAddresses()) { }
public SupplierCard(long id, string alf, INameHolder nameHolder,
ICollection<IPhysicalAddress> physicalAddresses, IDigitalAddresses digitalAddresses)
: this(id, alf, nameHolder, physicalAddresses, digitalAddresses, null) { }
public SupplierCard(long id, string alf, INameHolder nameHolder,
ICollection<IPhysicalAddress> physicalAddresses, IDigitalAddresses digitalAddresses, IValidatableObject validator)
: base(id, alf, nameHolder, physicalAddresses, digitalAddresses, validator)
{
this.Profile = new SupplierProfile();
this.PurchaseCategories = new Collection<PurchaseCategory>();
}
}
}
public class SupplierProfile : AbstractAspect
{
private TradingEntity _incType;
public TradingEntity BusinessType
{
get { return _incType; }
set
{
if (_incType != null) { this.DeregisterSubPropertyForChangeTracking(this.BusinessType); }
_incType = value; this.OnPropertyChanged("TradingType");
this.RegisterSubPropertyForChangeTracking(this.BusinessType);
}
}
private bool _emailOk;
private bool _smailOk;
public bool MarketingEmailOk
{
get { return _emailOk; }
set { _emailOk = value; this.OnPropertyChanged("MarketingEmailOk"); }
}
public bool MarketingSmailOk
{
get { return _smailOk; }
set { _smailOk = value; this.OnPropertyChanged("MarketingSmailOk"); }
}
public SupplierProfile()
: base()
{
this.BusinessType = new TradingEntity(ContactLegalType.Limited);
}
}
}
These are my configuration classes:
[Export(typeof(IEntityConfiguration))]
public class SupplierCardConfiguration
: EntityTypeConfiguration<SupplierCard>, IEntityConfiguration
{
public SupplierCardConfiguration()
{
this.ToTable("SupplierCard", "erp_wms");
HasKey(u => u.Id);
Property(u => u.Id).HasColumnName("SupplierId");
Ignore(u => u.UsePropertyNotifications);
Property(u => u.Profile.MarketingEmailOk).HasColumnName("MarketingEmailOk");
HasMany(i => i.PurchaseCategories)
.WithMany(c => c.Suppliers)
.Map(mc =>
{
mc.MapLeftKey("CategoryId");
mc.MapRightKey("SupplierId");
mc.ToTable("SupplierPurchaseCategory", "erp_wms");
});
}
public void AddConfiguration(ConfigurationRegistrar registrar)
{
registrar.Add(this);
}
}
[Export(typeof(IEntityConfiguration))]
public class SupplierProfileConfiguration
: EntityTypeConfiguration<SupplierProfile>, IEntityConfiguration
{
public SupplierProfileConfiguration()
{
this.ToTable("SupplierCard", "erp_wms");
Ignore(u => u.UsePropertyNotifications);
Property(u => u.MarketingEmailOk).HasColumnName("MarketingEmailOk");
}
public void AddConfiguration(ConfigurationRegistrar registrar)
{
registrar.Add(this);
}
}
UPDATE:
Ok so Ive tried ignoring SupplierProfile as per suggestion that changed nothing. I then tried removing the configuration class for Supplier Profile and left
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<SupplierProfile>();
base.OnModelCreating(modelBuilder);
}
and that generated an error:
{"The property 'Profile' is not a declared property on type
'SupplierCard'. Verify that the property has not been explicitly
excluded from the model by using the Ignore method or
NotMappedAttribute data annotation. Make sure that it is a valid
primitive property."}
[System.InvalidOperationException]: {"The property 'Profile' is not a declared property on type 'SupplierCard'. Verify that the
property has not been explicitly excluded from the model by using the
Ignore method or NotMappedAttribute data annotation. Make sure that it
is a valid primitive property."}
I then tried removing the
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<SupplierProfile>();
base.OnModelCreating(modelBuilder);
}
while leaving out the configuration class for SupplierProfile and that generates the error:
Message: "Invalid column name
'Profile_BusinessType_ContactLegalType'.\r\nInvalid column name
'Profile_BusinessType_TradingSince'.\r\nInvalid column name
'Profile_BusinessType_State'.\r\nInvalid column name
'Profile_BusinessType_UsePropertyNotifications'.\r\nInvalid column
name 'MarketingEmailOk'.\r\nInvalid column name
'Profile_MarketingSmailOk'.\r\nInvalid column name
'Profile_State'.\r\nInvalid column name
'Profile_UsePropertyNotifications'.\r\nInvalid column name
'OwnerId'.\r\nInvalid column name 'State'."
So like I said, just **bumbling** along ;)
After reading this I think it might have something to do with your relationship in your SupplierCard class.
public class SupplierCard : ContactCard, ISupplierCard
{
public SupplierProfile Profile { get; protected set; }
}
I'm guessing it registering as a complex type when SupplierCard is mapped.
A suggested way to fix it is to ignore it.
modelBuilder.Ignore<SupplierProfile>();
I've never run into this problem myself, so not sure if this'll help.
So after a lot of mucking around it turns out the underlying problem is a bug in Entity Framework 5. This bug has been fixed in EF6 beta. All other errors were in fact just masking this underlying error.
The following explaination is not terribly good as I dont fully understand it myself.
Short answer is: Use EF6 or otherwise modify EF5 source code.
Turns out that if you have a class in assembly B, that has a property of a type of enum defined in Assembly A, EF5 gets confused and thinks the enum is missing or somehow unavailable and sets about trying to generate the type itself.
So I had:
Assembly A containing enum type AA.
Assembly B referencing Assembly A so a contained class BB could have a property of type AA.
An EF5 data layer Assembly referencing both Assembly A & B.
An EF5 configuration layer Assembly referencing both Assembly A & B.
And it failed.
But if I "simply" move enum type AA into Assembly B then everything works.
This is of course is completely useless because then I set up all kinds of dependencies on Assembly B for any Assembly that has a member who needs an enum AA. But that is the test.
To top it off there also appears to be some particular set of circumstances in which everything I just said does not apply due to the order assemblies are loaded at runtime. The order of this loading cannot be forced i.e. it's non-determinant so it's pot luck.
If I'm trying to serialize a normal CLR object, and I do not want a particular member variable to be serialized, I can tag it with the
[NonSerialized]
attribute. If I am creating a table services entity, is there an equivalent attribute I can use to tell Azure table services to ignore this property?
For Version 2.1 there is a new Microsoft.WindowsAzure.Storage.Table.IgnoreProperty attribute. See the 2.1 release notes for more information: http://blogs.msdn.com/b/windowsazurestorage/archive/2013/09/07/announcing-storage-client-library-2-1-rtm.aspx.
There's no equivalent I know of.
This post says how you can achieve the desired effect - http://blogs.msdn.com/b/phaniraj/archive/2008/12/11/customizing-serialization-of-entities-in-the-ado-net-data-services-client-library.aspx
Alternatively, if you can get away with using "internal" rather than "public" on your property then it will not get persisted with the current SDK (but this might change in the future).
For version 2.0 of the Table Storage SDK there is a new way to achieve this.
You can now override the WriteEntity method on TableEntity and remove any entity properties that have an attribute on them. I derive from a class that does this for all my entities, like:
public class CustomSerializationTableEntity : TableEntity
{
public CustomSerializationTableEntity()
{
}
public CustomSerializationTableEntity(string partitionKey, string rowKey)
: base(partitionKey, rowKey)
{
}
public override IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
var entityProperties = base.WriteEntity(operationContext);
var objectProperties = this.GetType().GetProperties();
foreach (PropertyInfo property in objectProperties)
{
// see if the property has the attribute to not serialization, and if it does remove it from the entities to send to write
object[] notSerializedAttributes = property.GetCustomAttributes(typeof(NotSerializedAttribute), false);
if (notSerializedAttributes.Length > 0)
{
entityProperties.Remove(property.Name);
}
}
return entityProperties;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class NotSerializedAttribute : Attribute
{
}
Then you can make use of this class for your entities like
public class MyEntity : CustomSerializationTableEntity
{
public MyEntity()
{
}
public string MySerializedProperty { get; set; }
[NotSerialized]
public List<string> MyNotSerializedProperty { get; set; }
}