MVVM Silverlight - can not assign existing control to a property of collection of custom elements in XAML - xaml

I have a class
public class Item
{
public string A { get; set; }
public Control B { get; set; }
}
I'm using MVVM with Silverlight. I have a custom view that is inherited from a standard view. Custom view has public property public ICollection MyItems { get; set; } which should store items described above.
In xaml of my view I have
xxxx.MyItems>
Item A="someText" B="_existingButton" />
Item A="someText2" B="_existingButton2" />
/xxxx.MyItems>
Initialize() method of View fails when trying to assign value for B.
How can I assign a reference to existing element for a custom collection item?

I don't exactly understand what you are trying to achieve, but to help you arrive at a solution, I recommend that you attempt your task in the code behind file first (i.e. in the .xaml.cs) file.
By doing this, you will be given much more informative help from the compiler and intellisense.
Once you've achieved what you wanted in the code behind, then try and implement it in the xaml file.

Related

Adding warehouse selector to the custom field in acumatica

I created a custom field and trying to add the warehouse selector to it.I try to read from the customization guide and tried it but,the selector does not show up in the custom field.
This is the code I tried.
#region UsrCustomSite
[PXDBInt]
[PXUIField(DisplayName="Warehouse", Visibility = PXUIVisibility.SelectorVisible)]
[PXSelector(typeof(Search<IN.INSite.siteCD>),typeof(IN.INSite.descr),DescriptionField =(typeof(IN.INSite.siteCD)),SubstituteKey =(typeof(IN.INSite.siteCD)),DirtyRead =true)]
public virtual int? UsrCustomSite { get; set; }
public abstract class usrCustomSite : PX.Data.BQL.BqlInt.Field { }
#endregion
Am I missing something here?
I would try changing
[PXSelector(typeof(Search<IN.INSite.siteCD>)
to
[PXSelector(typeof(Search<IN.INSite.siteID>)
You are storing an int so you want the id, the substitute Key setting will make it so that the UI will show the CD.

Instantiating ModelExpression directly

Let's say I have the following input tag which utilizes the built-in tag helper:
#model ProductViewModel
<label asp-for="Product.Id"></label>
In my case, this expands into the following:
<label for="Product_Id">Id</label>
I see that asp-for is expecting a ModelExpression:
In tag helper implementations, I often see a property like the following:
public ModelExpression For { get; set; }
It appears that this is automatically populated when the tag helper is used.
Is there a way to instantiate a ModelExpression directly in C#?
I.e. something like this:
var exp = new ModelExpression("Product.Id",...)
I'd like to be able to generate "Product_Id" and "Id" from Product.Id as the input tag helper did.
As far as I know, you can specify that your property is to be set to the name of some property on the View's Model object by declaring your property with the ModelExpression type. This will enable any developer using your property to get IntelliSense support for entering a property name from the Model object. More importantly, your code will be passed the value of that property through the ModelExpression's Model property.
Sample code as below:
[HtmlTargetElement("employee-details")]
public class EmployeeDetailTagHelper : TagHelper
{
[HtmlAttributeName("for-name")]
public ModelExpression EmployeeName { get; set; }
[HtmlAttributeName("for-designation")]
public ModelExpression Designation { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "EmployeeDetails";
output.TagMode = TagMode.StartTagAndEndTag;
var sb = new StringBuilder();
sb.AppendFormat("<span>Name: {0}</span> <br/>", this.EmployeeName.Model);
sb.AppendFormat("<span>Designation: {0}</span>", this.Designation.Model);
output.PreContent.SetHtmlContent(sb.ToString());
}
}
Code in the View page:
#model WebApplication7.Models.EmployeeViewModel
<div class="row">
<employee-details for-name="Name" for-designation="Designation"></employee-details>
</div>
Code in the Model
public class EmployeeViewModel
{
public string Name { get; set; }
public string Designation { get; set; }
}
From above code, you can see that we could custom the attribute name. More detail information about using the ModelExpression, check the following links:
Creating Custom Tag Helpers With ASP.NET Core MVC
Expression names
I'd like to be able to generate "Product_Id" and "Id" from Product.Id
as the input tag helper did.
Besides, do you mean you want to change the Product. Id to Product_Id, in my opinion, I'm not suggesting you change it, because generally we can use "_" as a separator in the property name. So, if we are using Product.Id, it means the Product's Id property, and the Product_Id means there have a Product_Id property.
To answer the question:
Is there a way to instantiate a ModelExpression directly in C#"
Yes you can, through IModelExpressionProvider and its CreateModelExpression method. You can get an instance of this interface through DI.
Now, if you're already in your view and working with tag helpers, Zhi Lv's answer is all you need, as the functionality is built-in and much easier to use. You only need IModelExpressionProvider for when you're in your Razor Page, Controller, or perhaps some custom middleware. Personally, I find this functionality useful for my Ajax handlers that need to return one of my ViewComponents that has a ModelExpression argument (so that I can easily call it from my Pages/Views too.)
To call CreateModelExpression, you'll need a strongly-typed instance of ViewData. In Razor Pages, this is as easy as casting the ViewData property to the strongly-typed instance of your PageModel's type (presuming you don't have a page model hierarchy):
var viewData = (ViewDataDictionary<IndexModel>)ViewData;
If you're using MVC and you're in the controller, that won't exist yet. Best you can do is make your own instance.
var viewData = new ViewDataDictionary<ErrorViewModel>(new EmptyModelMetadataProvider(),
new ModelStateDictionary());
Once you get your strongly-typed ViewData instance, you can obtain your desired ModelExpression like this, just like using a lambda expression in your views:
var myPropertyEx = _modelExpressionProvider.CreateModelExpression(viewData,
m => m.MyProperty);

MVC 4 Validation Attribute is not working for dynamically added fields

Here are my Product and ProductItem classes/models:
public class Product
{
public int ProductId { get; set; }
[Required(ErrorMessage="Enter Name")]
public string Name { get; set; }
public List<ProductItem> productitems { get; set; }
[Required(ErrorMessage="Enter Price")]
public decimal Price { get; set; }
}
public class ProductItem
{
[Required(ErrorMessage="Select Raw Material")]
public int RawMaterial { get; set; }
[Required(ErrorMessage="Enter Quantity")]
public decimal Qty { get; set; }
}
For ProductItem I am adding its fields dynamically with jQuery, as you can see here:
$("#btnAddProductItem").click(function () {
$.getJSON("/rawmaterial/GetRawMaterials", null, function (data) {
var productItem = $("<tr class='productItem' id='productItem-0'><td><select id='rmlist-0' name='productitems[0].RawMaterial'></select><span class='field-validation-valid' data-valmsg-for='productitems[0].RawMaterial' data-valmsg-replace='true'></span></td><td><input type='text' id='rmqty-0' name='productitems[0].Qty'/><span class='field-validation-valid' data-valmsg-for='productitems[0].Qty' data-valmsg-replace='true'></span></td></tr>");
$("#productItem").append(productItem);
$("#rmlist-0").addItems(data);
});
});
Now the validation attributes applied on Name and Price are working fine but not on the fields added dynamically (i.e. "RawMaterial" and "Qty").
Please give me the suggestions how this validation will work ?
Note: For testing purpose I have just added the first object of the List indexed with 0.
There are several ways to accomplish this -
PARTIAL VIEW: Since you are using Server Side data annotation as I see from the class definitions, then it is not a good idea to load dynamically with js. Because you will miss out all the validation that MVC 4 could have created automatically. So, the best solution I would suggest is taking the code that you are adding dynamically to a partial view file and then get the html with ajax call and then populating the HTML.
JS VALIDATION: But, if it is a must that you should use JS, then you have to add all the validation items yourself. To do that you have to do some extra works -
First, inspect the HTML with any developer tools, you will notice that there is a <span> attribute appended after each item to show the error which has a target mentioned. You have to append similar attributes to your elements
With MVC 4 unobtrusive validation, all the validation attributes and rules are added with the target element with data attributes. Each one is based one the validation they stands for. You have you create attributes similar to that.
Finally, after adding all the validation items in JS, reset the form so that it parses the new validations added and work accordingly. The code to parse the validations are here -
var form = $("form") //use more specific selector if you like
form.removeData("validator").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse(form);
But I would prefer the partial view solution, since it will require least amount of re-work and also gives you option to keep all your validation in one place. You don't have to worry about new validations to be ported to js in future.

Pattern for passing common data to _layout.cshtml in MVC4.5

I am trying to come up with the best pattern for passing data to my _layout.cshtml page.
I am toying with creating a common base class from which all view specific models derive. This base class would be recognized by my _layout.cshtml and used to fill in details about the user and load proper images in the header, etc. For example, here is a snippet of it.
public abstract class ViewModelBase
{
public string Username { get; set; }
public string Version { get; set; }
}
At the top of my _layout.cshtml I have...
#model MyProject.Web.Controllers.ViewModelBase
I need a common area to hydrate the information required by the model, and am planning to use the following pattern...
Each action method creates and hydrates a model derived from
ViewModelBase.
The action completes.
I create a ActionFilterAttribute and override OnActionExecuted to cast the
current Result to ViewModelBase.
If the conversion is successful, then I populate the ViewModelBase details with the relevant data.
Here are my questions...
Is the use of a ActionFilterAttribute (OnActionExecuted) a good pattern for what I am trying to do?
I am not able to see how to get the Result created in the action from the HttpActionExecutedContext. How is this done?
I follow the same approach and use a base ViewModel class which all my other viewModels inherit from.
Then, I have a base controller that all controller inherit from. In there, I have one method that takes care of initializing the view model:
protected T CreateViewModel<T>() where T : ViewModel.BaseViewModel, new()
{
var viewModelT = new T {
HeaderTitle = "Welcome to my domain",
VisitorUsername = this.VisitorUsername,
IsCurrentVisitorAuthenticated = this.IsCurrentVisitorAuthenticated,
//...
};
return viewModelT;
}
Then on each controller, when I want to create the view model, I simply call the base controller's method:
var vm = base.CreateViewModel<MyPageCustomViewModel>();

How to disable selection a single item in a GridView

How do you disable the selection single item from a GridView?
I have a GridView with it's ItemsSource bound to an IEnumerable<SampleDataItem>. I'd like to be able to programmatically not allow the selection of some items in the list while allowing selection of the others.
While I haven't done this, you should be able to use an ItemContainerStyleSelector on the GridView, the method gives you the container (GridViewItem) and the item you're binding to. From there you can set the IsEnabled property on the GridViewItem to false which makes it unselectable.
You'll also probably need to select a custom style as well since the default GridViewItem style will customise how a disabled item will look.
Update DataTemplateSelector Solution
public class IssueGridTemplateSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var selectorItem = container as SelectorItem;
if (item is Issue)
return IssueTemplate;
selectorItem.IsEnabled = false;
selectorItem.Style = RepositoryItemStyle;
return RepositoryTemplate;
}
public DataTemplate IssueTemplate
{
get;
set;
}
public DataTemplate RepositoryTemplate
{
get;
set;
}
public Style RepositoryItemStyle
{
get;
set;
}
}
Nigel's answer is great. I just added some attached properties to the WinRT XAML Toolkit that should make it simpler to do if you are populating your GridView using the ItemsSource property binding.
For me the usual way to modify the GridViewItem properties then was using GridView.ItemContainerStyle property. Using that method you would need to specify the IsEnabled property using a style and style setters don't support bindings in WinRT. Using the ItemContainerStyleSelector might be one way, but it requires defining a custom class.
I have created a GridViewItemExtensions class with an IsEnabled property that you can set on any control in your GridView.ItemTemplate like this:
xmlns:xyzc="using:Xyzzer.WinRT.Controls"
xyzc:GridViewItemExtensions.IsEnabled="{Binding IsEnabled}"
The property has a behavior of finding the GridViewItem in its ancestors visual tree and keeping its IsEnabled value synchronized to the GridViewItemExtensions.IsEnabled value set on its descendant.
Then as Nigel said - you still need to extract the template from a GridViewItem and modify it so the disabled items don't look out of place.