Make a form field selection values dependent on another field value - graph

I am editing the AP301000 screen, Bills and Adjustments, in a customization project.
I added two new fields to the form, which are both in the APRegisterExt class.
1. PONbr
2. ReceiptNbr
When a user selects a PO number, I want the ReceiptNbr selection values to be restricted to only the receipt records which have the same PO number.
I tried using a PXSelector attribute on ReceiptNbr, but because the PONumber is in an extension class, I cannot use Current<> to access this field.
Any ideas?

On your second CustomField's Selector attribute definition use Current<> statement for filtering, see below:
#region UsrCustomField1
[PXDBInt]
[PXUIField(DisplayName="CustomField1")]
[PXSelector(typeof(Search<DAC.Field>),
typeof(DAC.Field),
typeof(DAC.Field),
SubstituteKey= typeof(DAC.Field))]
public virtual int? UsrCustomField1 { get; set; }
public abstract class usrCustomField1 : IBqlField { }
#endregion
#region UsrCustomField2Dependent
[PXDBInt]
[PXUIField(DisplayName="CustomField2Dependent")]
[PXSelector(typeof(Search<DAC.Field, Where<DAC.Field, Equal<Current<UsrCustomField1>>>>),
typeof(DAC.Field),
typeof(DAC.Field),
SubstituteKey= typeof(DAC.Field))]
public virtual int? UsrCustomField2Dependent { get; set; }
public abstract class usrCustomField2Dependent : IBqlField { }
#endregion
Then on your ASPX file make sure you have added CommitChanges=True and AutoRefresh=true properties, see below:
<px:PXSelector runat="server" ID="CstPXSelector2" DataField="UsrCustomField1" CommitChanges="True" AutoRefresh="True" />
<px:PXSelector runat="server" ID="CstPXSelector1" DataField="UsrCustomField2Dependent" CommitChanges="True" AutoRefresh="True" />

Related

Sitefinity - AutoGenerated Fields - Not persisting values

I'm exploring the use of the autogenerated fields in SiteFinity widget designers.
The fields are generated as expected. However, the selected values aer not persisted to the model. I.e. the FAQs property remains null after selecting in the widget designer.
What steps have I missed?
Do I need to implement my own angularJS controller?
Here's my model:
public class CustomWidgetModel: CustomDynamicContentModelBase, IDynamicContentBase
{
[Content(Type = "Telerik.Sitefinity.DynamicTypes.Model.FAQs.Faq", AllowMultipleItemsSelection =true)]
public MixedContentContext FAQs { get; set; }
[DefaultValue(WidgetDisplay.AllPublished)]
public WidgetDisplay WidgetDisplay { get; set; }
[Browsable(false)]
public override string ContentTypeFullName => "Telerik.Sitefinity.DynamicTypes.Model.FAQs.Faq";
}
https://knowledgebase.progress.com/articles/Knowledge/linkmodel-is-not-persisted-if-it-is-in-the-model
It's a known bug, the property needs to be on the controller itself.

When to use BindAttribute?

I'm learning asp.net mvc and wonder when we need to use BindAttribute.
The first case (using Bind):
Model:
public class Book
{
public string Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
}
Controller:
public IActionResult Create([Bind(nameof(Book.Name), nameof(Book.Author))] Book model)
{
return Ok();
}
The book Id would be generated on server side. So, client side has nothing to do with it, every actions try to change/make the id is prevented.
The second case (not using Bind):
Model:
public class BookViewModel
{
public string Name { get; set; }
public string Author { get; set; }
}
Controller:
public IActionResult Create(BookViewModel model)
{
return Ok();
}
Because the second model doesn't contain Id property, we don't need to prevent from creating or changing.
I prefer the second. It's easy to manage model.
Is there a case we must use Bind attribute?
We use bind when we want that some properties of complex property are ignored when received on server. It could be for safety or other reasons.
When this action is executed the MVC model binder will use the request parameters to populate the user parameter's properties, as you may already know. However, the Bind attribute tells the model binder to only populate properties with names specified.
So in this case only the Username, FullName and Email properties will be populated. All others will be ignored.
See here for more details: http://ittecture.wordpress.com/2009/05/01/tip-of-the-day-199-asp-net-mvc-defining-model-binding-explicitly/
If you have situation when you only have to ignore one parametar from binding you could use Exclude property:
[Exclude]
public Entity Name {get; set;}
Bind is used to increase security and unauthorized data to be posted on server . In your model class , suppose you have content property also. if the content property is not needed in the future. Then it would be difficult for you to remove all the occurrences of that property. Here you can use bind property like this
[Bind(exclude="content")]
or you can bind only selected properties to be posted on server by including the properties like this
public ActionResult create([Bind(Include = "Name,Author")] Modelclass modelclass)
{
//Do something here
}
You can learn more about it here
Second approach is more suitable instead writing all the properties and bind them but there are some situations where you must bind user like you have a roles property or IsAdmin property in your model then you might not want that user somehow posts the IsAdmin or roles properties to the server . That's where you can use Bind attribute

How to use a class to create the SQLite table and ignore the fact that it is a List<ChildrenObjectModel>?

I'm using a class to generate an SQLite table, but I also want to use it as ItemSource for a two levels ListView (A listview with sub items).
This works for the ListView:
public class ParentModel:List<ChildrenModel>
{
[PrimaryKey]
public string uid { get; set; }
public string name { get; set; }
[Ignore]
public string attributeA { get; set; }
public ParentModel() {
}
}
But when I do mySQLiteConnection.CreateTable<ParentModel>(); it throws an Exception because the Object is a List<>.
I can [Ignore] attributes, but is there a way to ignore the fact that the the class is a List<>?
I can also create a List variable inside the model and [Ignore] it, but this wouldn't work for the ListView.
The only solution I can think is creating two classes with the same attributes, one being a List<> and the other one not.
But I really don't like this idea.
Not sure why you want to inherit from List<ChildrenModel>. You should make the ChildrenModel class a class that can create a table, and then that table would have all of the ChildrenModel items. Then in ParentModel you could have a public property of type List<ChildrenModel> which you can load from the ChildrenModel table. You would want to ignore that property as SQLite can not store a List. You can then access your populated List through the public property for the List<ChildrenModel> in the ParentModel class. That's what I would do anyway.

Description(and many attributes) for User Control are not displaying info

I want to show some description information of my User Control in the Propereties toolbox.
After writting some attributes for the control:
public partial class WebUserControl1 : System.Web.UI.UserControl
{
int id;
[Description("Get or Set the main name of the css class to apply")]
public string CssClass { get; set; }
[Description("Get the number of nodes")]
public int NodesCount
{
get
{
return id;
}
}
[Browsable(true),
Category("Behavior"),
DefaultValue(""),
Description("The Uri to find the Xml file"),
Editor(typeof(System.Web.UI.Design.XmlUrlEditor), typeof(UITypeEditor))]
public string XmlPath { get; set; }
There are no answer from the toolbox
Any Ideas?
I have confirmed this yet, but I have read that you if you create the WebUserControl in a separate project and add the .dll reference, you will then get the design time support you are looking for.

Binding IList<IMyInterfaceType> doesn't display members of Interfaces that IMyInterface inherits

I'm binding IList to a GridView. IMyInterface looks like
public interface IMyInterface: IHasTotalHours, IHasLines
{
DateTime GoalStartDate { get; set; }
DateTime GoalEndDate { get; set; }
}
I bind an instance to a Grid like this:
IList<IMyInterface> instance= GetMyData();
myGrid.DataSource = instance;
myGrid.DataBind();
When bind this to the grid, the only members that show up in the grid are the direct members of IMyInterface: GoalStartDate and GoalEndDate.
Why is that? How do I get the grid to display the members of the other interfaces it inherits?
Update
The inherited interfaces define simple data properties like
public interface IHasTotalHours
{
string Description { get; set; }
int Hours{ get; set; }
}
public interface IHasLines
{
double TotalLines { get; set; }
double LinesPerHour { get; set; }
}
There is a class that implements IMyInterface:
public class MyClass : IMyInterface
{
public string Description { get; set; }
public int Hours { get; set; }
public double TotalLines { get; set; }
public double LinesPerHour { get; set; }
public DateTime GoalStartDate { get; set; }
public DateTime GoalEndDate { get; set; }
}
These are cast as IMyInterface, and returned in the list that I'm binding to the GridView.
Data bound controls do not use reflection but a TypeDescriptor to get the properties from a data source. In the TypeDescriptor.GetProperties method, you can read the following:
The properties for a component can
differ from the properties of a class,
because the site can add or remove
properties if the component is sited.
Apparently the default implementation will only return direct properties from an Interface and not the inherited ones.
Luckily this mechanism is extensible, and you can write a TypeConverter class with custom property information implementation. Please refer to the remarks in the TypeConverter documentation for implementing property logic.
The GetProperties implementation of your custom TypeConverter class can call TypeDescriptor.GetProperties(Type) on your interface and all it's inherited interfaces. But maybe you could even write a generic TypeConverter that would find all inherited properties by using reflection.
Then you attach this custom TypeConverter to your interface with the TypeConverterAttribute attribute.
And then, like magic, the data source will find all properties. ;-)
It's because an interface is a contract, and that's the only way to interact with an object is through that specific contract. The other interfaces cannot be assumed and can't be utilized until a cast is made.
So when you bind a List of T to something, the datagrid doesn't know about those other interfaces. And the datagrid isn't going to use reflection to figure out what other classes or interfaces might be inherited. The only object properties that are going to be available to the datagrid are the properties exposed by the T interface.
You need to bind List if you want the datagrid to have access to all the properties.

Resources