Add another ViewModelLocator convention in Prism (not override) - wpf

The project (WPF) has these folders:
Views
ViewModels
SubViews
SubViewModels
How to get the Prism's ViewModelLocator working with them (Views> ViewModels & SubViews> SubViewModels), the solution I found only works with one convention:
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
var viewName = viewType.FullName.Replace(".ViewModels.", ".CustomNamespace.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{viewName}ViewModel, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}

You could opt for registration of the pairs (not as bad as it sounds because you have to register for navigation anyway).
Alternatively, you implement both conventions one after the other - take the view's name, subtract "Views" and add "ViewModels" and try to get the view model's type. If that fails, subtract "SubViews" and add "SubViewModels" and try again. You could even check for cross combinations (e.g. "SubViews.ViewA" and "ViewModels.ViewAViewModel")...

I solved it by checking the viewType and based on it, I return the appropriate ViewModel type:
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
string prefix;
if (viewType.FullName.Contains(".SubViews."))
{
prefix = viewType.FullName.Replace(".SubViews.", ".SubViewModels.");
}
else
{
prefix = viewType.FullName.Replace(".Views.", ".ViewModels.");
}
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{prefix}ViewModel, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}

Related

.NET Tag Helper to replicate #Html.DisplayFor

I'm discovering .Net Core Tag Helpers and I was just curious to know if there are any tag helpers that replicate the #Html.DisplayFor. I think that the label tag helper replicates #Html.DisplayNameFor since it shows the property name on a model passed to the page, but is there an equivalent for #Html.DisplayFor for displaying a property value?
I'm assuming there isn't because in the microsoft .net core tutorials, razor pages that need to display the property value rather than the property name use the HTML helpers.
First, the tag helper is actually the "label asp-for". You can create a new tag helper that is a "label asp-text" helper.
Another option is to use another tag such as span and create a custom "span asp-for" tag helper.
Here is a simple span implementation:
[HtmlTargetElement("span", Attributes = FOR_ATTRIBUTE_NAME, TagStructure = TagStructure.NormalOrSelfClosing)]
public class CustomSpanTagHelper : InputTagHelper
{
private const string FOR_ATTRIBUTE_NAME = "asp-for";
public CustomSpanTagHelper(IHtmlGenerator generator) : base(generator)
{
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
var metadata = base.For.Metadata;
if (metadata == null)
{
throw new InvalidOperationException(string.Format("No provided metadata " + FOR_ATTRIBUTE_NAME));
}
if (!string.IsNullOrWhiteSpace(metadata.Description))
{
output.Content.Append(metadata.Description);
}
if (metadata.IsEnum)
{
var description = (this.For.Model as Enum).GetDescription();
output.Content.Append(description);
}
base.Process(context, output);
}
}
You will need to register your custom tag helper in your _ViewImports.cshtml like this: (don't forget to rebuild)
#namespace MyProject.Web.Pages
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#addTagHelper MyProject.Web.TagHelpers.CustomSpanTagHelper, MyProject.Web <-- custom import

How to properly save self reference with ES6 classes?

Honestly, I'm not sure of what is the cause for the behavior: systemjs, babel or my own fault. I'm using class for custom control controller and saving class reference in self variable. Apparently that gets overriden by any subsequent controller instances.
I created a simple repository to demonstrate:
clone, install, run live-server or your preferred server. You will see 2 buttons, each is a custom control. Clicking on a button only affects one control.
https://github.com/alexkolt/selfIsThis
How can I get this working with ES6 class?
I should have posted the code, sorry.
The reason you'd want to save reference to self is for example in callbacks calling this might result in a different reference.
I was trying to do this:
var self;
class Test {
constructor(dependency) {
self = this;
self.dependency = dependency;
}
method() {
self.dependency().then(value => self.property = value);
}
}
Like it was mentioned before the self becomes shared when declared outside of the module. I didn't realize that would happen as files would be wrapped in a closure. Joe Clay answer is correct, but to do what I was trying to do self needs to be declared in every method that needs it.
class Test {
constructor(dependency) {
this.dependency = dependency;
}
method() {
var self = this;
this.dependency().then(value => self.property = value);
}
}
You're not really using ES6 classes right. You don't need to save a reference to this - just access it directly in class methods. The way you have it at the minute, all your instances of CustomControlController are sharing a single self variable.
class CustomControlController {
constructor() {
this.value = 0;
}
click() {
var newValue = this.value * 2;
this.value = newValue;
}
}
export default CustomControlController;

Custom accessors Eloquent Model

I have a Eloquent Model and I want to create a customized toArray method...
class Posts extends Model {
public function scopeActives($query)
{
return $query->where('status', '=', '1');
}
public function toCustomJS()
{
$array = parent::ToArray();
$array['location'] = someFunction($this->attributes->location);
return $array;
}
}
//In my controller:
Posts::actives()->get()->toArray(); //this is working
Posts::actives()->get()->toCustomJS(); //Call to undefined method Illuminate\Database\Eloquent\Collection::toCustomJS()
How can I override the toArray method or create another "export" method?
get() actually returns a Collection object which contains 0, 1, or many models which you can iterate through so it's no wonder why adding these functions to your model are not working. What you will need to do to get this working is to create your custom Collection class, override the toArray() function, and also override the function in your model responsible for building that collection so it can return the custom Collection object.
CustomCollection class
class CustomCollection extends Illuminate\Database\Eloquent\Collection {
protected $location;
public function __construct(array $models = Array(), $location)
{
parent::__construct($models);
$this->location = $location;
}
// Override the toArray method
public function toArray($location = null)
{
$original_array = parent::toArray();
if(!is_null($location)) {
$original_array['location'] = someFunction($this->location);
}
return $original_array;
}
}
Overriding the newCollection method on your models
And for the models you wish to return CustomCollection
class YourModel extends Eloquent {
// Override the newCollection method
public function newCollection(array $models = Array())
{
return new \CustomCollection($models, $this->attributes['location']);
}
}
Please note this may not be what you are intending. Because a Collection is really just an array of models, it's not good to depend on the location attribute of a single model. Depending on your use-case, it's something that can change from model to model.
It might also be a good idea to drop this method into a trait and then just use that trait in each model you wish to implement this feature in.
Edit:
If you don't want to go through creating a custom Collection class, you can always just do it manually each time...
$some_array = Posts::actives()->get()->toArray();
$some_array['location'] = someFunction(Posts::first()->location);
return Response::json($some_array);

Extending Backbone Collections to add logic, with custom methods, is a bad practice?

Usually I find my self needing to write an object with a specific functionality that it is a set of models.
Finally I extend a collection and add more functions that works with its model.
I think is better show you an example:
My app has a set of permissions, related with the user and/or the version of the platform.
var Permissions = Backbone.Collection.extend({
model: Permission,
hasAccess: function (moduleCode) {
....
},
allowAccess: function (moduleCode) {
....
},
...
With that methods I change the format of a property of a permission (the model). (My permissions are a concatenation of code with an string that identify the type of permission.)
A workmate tells me that it is wrong. In .NET he creates a class and he adds a private list and makes the changes to it. He does not inherit the list and changes it.
He would make a model and inside it he would add a collection property
this.set("permissionsCollection", new Backbone.Collection.extend({model: Permission}))
[Comment: I don't understand why he creates properties of everything, I think in his case it is not needed.] -> But this is another question
I think in a different way. I know the Collection has internally that list. I have a great potencial in Backbone.Collections, why do I have to use a model that it is not necessary? If I don't need that encapsulation... I think that it is not necessary, he is overprogramming in my opinnion.
Am I wrong? Did I not know how to use BackboneJS Collections?
Thank you in advance.
At the beginning I had something called helper with similar methods:
findAttr: function (model, name) {
var attrs = model.get('app_attrs');
if (attrs !== undefined) {
return this.findByAttrName(attrs, name);
}
},
findByAttrName: function (array, name) {
return _.find(array, function(a) {
if (a.attrName === name) {
return a;
}
});
}
The view code was more awkward:
render: function () {
var attr = helper.findAttr(this.model, 'user');
...
return this;
}
The only logical solution was to move these methods into the model (this.model in the above case). After refactoring I've got:
render: function () {
var attr = this.model.findAttr('user');
...
return this;
}
which is of course more readable than the previous solution.

How can I create a fluent interface for defining Dialog Boxes?

I am looking for examples and experience of using fluent interface to define simple Dialog Boxes (and other UI elements).
(I may need to add support for custom Dialog Boxes to an in-house programming language and I think a fluent interface may be the best way of doing it)
The UI system will be build on Winforms OR WPF if that effects your answers.
What if the interface is not fluent and I changed the question to just a “a simple to use (and read) API..” that does not depend on the use of a “drag and drop” UI designer.
I think the result will be fluent to some extend, e.g
Textbox(“name”). Labelled(“Person
Name”). Column(1)
Textbox(“notes”). Labelled(“Notes”).
Multiline(4). Column(1).ToColumn(3)
However the interface does not have to be a single line
This "How to make Databinding type safe and support refactoring"
gives a good starting point for a fluent interface for databinding.
I built a fluent interface for my dialog boxes, something along the lines of:
var result = Dialog
.Buttons(buttons.Ok, buttons.Cancel)
.Title("")
.Text("")
.Show();
if ( result == DialogResult.Ok) {
//...
}
I also had one for taking in an enum something like this:
var result = Dialog(of EnumName)
.Text("")
.Title("")
.Show();
if ( result == EnumName.Value1 ) {
//...
}
Which generated the buttons from the enum, and returned the selected buttons enum value.
Edit: Added from comments:
The form it shows has its width calculated to fit all the buttons in one row.
It has an method for adding extra controls.
The layout is made from flow layout panels (one horizontal for buttons. one vertical for text and other controls)
The general layout is of a standard messagebox.
It has another option for Auto Accelerating the buttons.
Summary of Methods:
.Buttons(paramarray of DialogResult)
.FromEnum<T>(enum)
.Title(text)
.Text(text)
.Control(control)
.AutoAccelerate
.Icon(image)
.Show() as T
The examples given so far do nothing to reduce the complexity of the task; they only trade one syntax for another (almost equally verbose) one. If you invest the time to create a fluent interface, leverage it to actually improve the expressiveness of your API instead of just jiggling syntactic sugar. Raise the level of abstraction from the default primitives (buttons, modalities,...) to templates, visual inheritance chains and behaviors.
I haven't totally thought this through yet, but something along the lines of:
Dialog
.WithStandardColors()
.WithTitleOf("ChooseSomething")
.WithButtonSet<OkCancel>()
.Show();
or
Dialog
.UseErrorFormatting
.SetTitleTo("Uh Oh")
.Show()
This question has been driving me crazy for a few days. I think a question you might need to ask is "why should I make a fluent API for dialog boxes?"
When you look at popular fluent APIs you'll notice something that's common with them in that it aids a user to be able to fluently read a line of code. Almost like a sentence. Observe:
From Ninject:
Bind(typeof(IWeapon)).To(typeof(Sword));
From Moq:
mock.Setup(foo => foo.Execute("ping"))
.Returns(() => calls)
.Callback(() => calls++);
From the mother of all fluent APIs, Linq:
var query = Products
.Where(p => p.Name.Contains("foo")
.OrderBy(p => p.Name);
These are good APIs that provide almost a sentence structure to their use.
As another example, how is this:
Dialog.Buttons(buttons.Ok, buttons.Cancel).Title("").Text("")
More readable and more useful than
new Dialog()
{
Buttons = Buttons.OkCancel,
Title = "",
Text = ""
};
And this is just a simple example. I noticed you are asking how to stuff things like layout, etc all in one line of code. My goodness your lines are going to be long.
I think you need to decide if you really think a fluent API is gaining you anything here. All I see are methods that set properties on a dialog box and don't provide any readability or value.
LINQ example of a fluent interface:
var customerTurnover = allOrders
.Where (o.CustomerID == CustomerID)
.Sum (o => o.Amount);
Basically, it is a way to design interfaces to minimize verbosity and provide a natural and well readable way to combine operations in order to accomplish much with little code.
An imaginary example for the dialog boxes domain:
DialogBoxAPI
.ModalDialogBox ()
.RoundCornersStyle ()
.BackgroundColor (RGB (200, 200, 200))
.TextColor (0, 0, 0)
.MessageText ("What shall we decide?")
.OKButton ()
.CancelButton ();
Which would generate a dialog box with the supplied characteristics. Is that what you are looking for?
I have good experience with extension methods and single "context" of fluent calling in combination with anonymous methods.
I hope example will be more clear:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TcKs.FluentSample {
class FluentSample {
Form CreateDialogBox() {
var frm = new Form();
frm.AddTextField( "Simple text field:" )
.AddTextField( "Advanced text field:", null, txt => txt.BackColor = Color.Red )
.AddTextField( "Complex text field:", lbl => {
lbl.Click += ( _sender, _e ) => MessageBox.Show( lbl, "Some informative text.", "Help" );
lbl.Font = new Font( lbl.Font, FontStyle.Underline );
lbl.Cursor = Cursors.Hand;
},
txt => {
txt.TextChanged += ( _sender, _e ) => txt.BackColor = txt.TextLength > 0 ? SystemColors.Window : Color.Red;
txt.DoubleClick += ( _sender, _e ) => { /* TODO: show lookup dialog */ };
txt.AddErrorProvider();
} )
.AddButton( btn => btn.Click += ( _sender, _e ) => frm.Close() );
return frm;
}
}
// contains standard extension methods for fluent creation of control
static class StandardControlFluentExtensionMethods {
// this extension method create button and add them to parent
public static T AddButton<T>( this T parent ) where T : Control {
return AddButton<T>( parent, (Action<Button>)null );
}
// this extension method create button and add them to parent, then call initMethod
public static T AddButton<T>( this T parent, Action<Button> initButton ) where T : Control {
var button = new Button();
parent.Controls.Add( button );
if ( null != initButton ) { initButton( button ); }
return parent;
}
}
// contains specialized extension methods for fluent creation of control
static class SpecializedControlFluentExtensionMethods {
public static T AddCloseButton<T>( this T parent, Action<Button> initButton ) where T : Control {
return parent.AddButton( btn => {
var frm = btn.FindForm();
if ( null != frm ) { frm.Close(); }
if ( null != initButton ) { initButton( btn ); }
} );
}
}
// contains data-driven extension methods for fluent creation of control
static class DataDrivenControlFluentExtensionMethods {
public static TParent AddTextField<TParent>( this TParent parent, string title ) where TParent : Control {
return AddTextField<TParent>( parent, title, (Action<Label>)null, (Action<TextBox>)null );
}
public static TParent AddTextField<TParent>( this TParent parent, string title, Action<Label> initTitle, Action<TextBox> initEditor ) where TParent : Control {
Label lblTitle = new Label();
// lblTitle .....
if ( null != initTitle ) { initTitle( lblTitle ); }
TextBox txtEditor = new TextBox();
// txtEditor ....
if ( null != initEditor ) { initEditor( txtEditor ); }
return parent;
}
public static TParent AddErrorProvider<TParent>( this TParent parent ) where TParent : Control {
return AddErrorProvider( parent, (Action<ErrorProvider>)null );
}
public static TParent AddErrorProvider<TParent>( this TParent parent, Action<ErrorProvider> initErrorProvider ) where TParent : Control {
// create and/or initilaize error provider
return parent;
}
}
}

Resources