PropertyAcess : Define condition values for label in PropertyAcess - gwt

I have a model called Field which has id and label.
I have defined PropertyAcess as below and it works. I would like to change it in such a way that I can show label based on condition ie if field.getLabel() is null, use field.getId() as label. How can I acheieve that
interface FieldProperties extends PropertyAccess<Field> {
ModelKeyProvider<Field> id();
LabelProvider<Field> label();
#Path("label")
ValueProvider<Field, String> labelProp();
}
Thanks

The PropertyAccess tool is meant to make it easy to quickly build ValueProvider, ModelKeyProvider, and LabelProvider instances that are based on a specific getter/setter on a bean-like object. If you don't want just access to a single property, then implement the interface directly.
In your case, since you want a LabelProvider that returns getLabel() unless it is null, then getId(), you might do something like this:
public LabelOrIdLabelProvider implements LabelProvider<Field> {
#Override
public String getLabel(Object item) {
return item.getLabel() == null ? item.getId() : item.getLabel();
}
}
If you want custom behavior, build it out yourself to do exactly what you need. If you just want the simple behavior of reading a single getter, the PropertyAccess is there to help save you a few lines of code.

Related

PostSharp C# - How to Implement All Fields Required

PostSharp contracts make it easy to label individual fields as Required. But I want a class attribute that makes all of the class fields required. I'm guessing I would have to implement a custom aspect to support this.
It seems like it would be a common need for anyone passing around data containers. Can anyone direct me to some code that implements a custom "AllFieldsRequired" aspect in PostSharp?
You can implement PostSharp.Aspects.IAspectProvider:
public class AllFieldsRequiredAttribute : TypeLevelAspect, IAspectProvider
{
IEnumerable<AspectInstance> IAspectProvider.ProvideAspects(object targetElement)
{
Type type = (Type)targetElement;
return type.GetFields().Select(
m => new AspectInstance(m, new ObjectConstruction(typeof(RequiredAttribute))));
}
}
[AllFieldsRequired]
public class Foo
{
public string Bar;
public object Baz;
}

use GwtCreateResource to provide text programatically

I would like my uiBinder to use a ClientBundle which will provide some runtime customized labels. Kind of a TextResource but not from a text file !
I tried with GwtCreateResource but from the DevGuide it seems like it's not possible. Am I right ? (create() and name() are the only methods available)
What I would like to achieve is something like this:
client bundle:
public interface MyWidgetResources extends ClientBundle {
GwtCreateResource<WidgetLabels> labels();
#Source("lol.css")
CssResource style();
}
labels class:
public final class MyWidgetLabels {
public String title() {
return load("mywidget-title");
}
public String banner() {
return load("mywidget-banner");
}
private String load(String key) {
// load from external..
}
}
uiBinder:
<ui:with type="com.package.MyWidgetResources" field="res"/>
<gwt:SimplePanel>
<gwt:Label text="{res.labels.title}"></gwt:Label>
<gwt:Label text="{res.labels.banner}"></gwt:Label>
</gwt:SimplePanel>
My code looks like this already but res.label.title does not work because GwtCreateResource can only serve as class instantiator (res.labels.create().title()).
Is there a solution for me ? Maybe with a custom ResourceGenerator ?
As long as MyWidgetLabels can be created by GWT.create, you can put anything you want into that type, and you can make it behave however you'd like. You will need the create reference in your uibinder as you suggested at the end of the post to actually build the object, so your lines will look about like this:
<gwt:Label text="{res.labels.create.title}"></gwt:Label>
Each . separated piece (except the first, which is a ui:field/#UiField) is a no-arg method to be called - you declared labels() in MyWidgetResources, create() already existed in GwtCreateResource, and you created title() in your own MyWidgetLabels type.
Since that first piece is a ui:field/#UiField, you could have another that references res.labels.create as something like labels so that later you could instead say:
<gwt:Label text="{labels.title}"></gwt:Label>
Finally, yes, you could build your own ResourceGenerator which would enable you to do whatever you wanted to emit the type in question, as long as you extended the ResourcePrototype type and had a getName() method.

How to store a unique value into a Panel (GWT)?

This is simple question but there's No answer found on the Internet.
Ok, some widgets such as CheckBox have a method called myCHeckBox.setFormValue(text); so I take advantage of this method to store the unique ID into a CheckBox so that later on I just myCHeckBox.getFormValue(); to retrieve back the unique value.
However, there's no setFormValue on GWT Panel?
So if we want to store a unique value into a Panel (for example, FlowPanel, VerticalPanel)?
Then Which method can i use to do that?
The way I see it what you are really trying is to extend the purpose of the Panel. I cannot see why you would want a unique identifier, as the object of the Panel is as unique as it guess but that's not the point here.
Since you want to extend the Panel do just that. Extend the corresponding class and give it a unique value, implement the corresponding getters and setters and then you are set. It is as simple as that
class AbsolutePanelUnq extends AbsolutePanel
{
private int uniqueId;
public getUniqueId(){
return uniqueId;
}
public setUniqueId(int uniqueId)
{
this.uniqueId = uniqueId;
}
}
Then create the object and do whatever you need.
Best way I can suggest:
Public class myPanel extends Panel {
private myUniqueValue;
//Getter setter for myUniqueValue
}

Should a method be 'fired' from within a property?

My application uses the MVVM pattern. My TextBox is bound to a property of my ViewModel (type string).
When ever the content of the TextBox changed via the user typing, I want to perform some validation.
So, currently, my code is
<TextBox Text="{Binding XmlContentAsString, UpdateSourceTrigger=PropertyChanged}" />
and my ViewModel has this property and field:
private string _xmlContentAsString;
public string XmlContentAsString
{
get { return _xmlContentAsString; }
set
{
if (_xmlContentAsString == value)
return;
_xmlContentAsString = value;
PerformValidiationLogic(value);//This is where I am unsure
}
}
Now, this works but, and I don't know why, I don't like this! It some how feels 'hacked' to include the method in the property.
Can some one please tell me if this is the correct approach when using the MVVM pattern?
There's different type of validations.
For simplistic validating string lengths or allowed characters etc you can use DataAnnotations and put the validation in attributes on your properties. You'll need to include
using System.ComponentModel.DataAnnotations;
then for example to keep string to 9 characters:
[StringLength(9)]
public string StringValue
{
get
{
return stringValue;
}
set
{
this.stringValue = value;
}
}
Then there is validation that is a bit more complex and is effectively enforcing your business logic.
There seem to be many views on how to do this. Ideally it should belong on the model, so that the validation can be reused, but obviously called via the viewmodel.
Personally I will put method calls in the property setters occasionally, to me thats the whole reason for having the ability to create setters and getters - otherwise there's very little point in having anything other than auto properties.
But if it's complex or asynchronous then you can hit issues.
I'd be very careful doing it with UpdateSourceTrigger=PropertyChanged, as that means you'll be firing it every character.
In your example, you perform validation logic on the value, but what would be the result of the validation if it fails? Typically you would want to notify the user of a validation failure. If that is the case, then I suggest IDataErrorInfo (examples can be found here:
http://codeblitz.wordpress.com/2009/05/08/wpf-validation-made-easy-with-idataerrorinfo/).
If you plan on overriding the value without notifying the user, then validating in the setter is acceptable (though still not a fan for more personal reasons).
In my opinion thats the correct approach. I would write a base class for your ViewModel that contains a method that sets the property, call PropertyChanged and validate if some validation rule is attached to that property.
For example:
public abstract class ValidableViewModel
{
private List<ValidationRule> _validationRules;
public ValidableViewModel()
{
_validationRules = new List<ValidationRule>();
}
protected virtual void SetValue<T, T2>(Expression<Func<T>> expression,
ref T2 backend, T2 value)
{
if (EqualityComparer<T2>.Default.Equals(backend, value))
return;
backend = value;
OnPropertyChanged(expression);
Validate(expression.Name, value);
}
protected void Validate(string propertyName, object value)
{
foreach(var validationRule in _validationRules)
{
if(validationRule.PropertyName == propertyName)
validationRule.Execute(value);
}
}
}
The code is not complete, there is missing a lot. But it could be a start ;-)
I personally don't advise putting so much logic in your property. I would use a command bound to an event, ie the lostfocus event of the textbox, and perform your validation there.
I would use something like this:
<TextBox Text="{Binding XmlContentAsString, UpdateSourceTrigger=PropertyChanged}">
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="LostFocus">
<interactivity:InvokeCommandAction Command="{Binding LostFocusCommand, Mode=OneWay}"/>
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
</TextBox>
then have a command in your view model that is LostFocusCommand wiht your validation logic.
I use mvvm-light and can give a more detailed example for that. (you will need to include the blend interactivity declaration at the top of your xaml)

Handling MVC2 variables with hyphens in their name

I'm working with some third-party software that creates querystring parameters with hyphens in their names. I was taking a look at this SO question and it seems like their solution is very close to what I need but I'm too ignorant to the underlying MVC stuff to figure out how to adapt this to do what I need. Ideally, I'd like to simply replace hyphens with underscores and that would be a good enough solution. If there's a better one, then I'm interested in hearing it.
An example of a URL I want to handle is this:
http://localhost/app/Person/List?First-Name=Bob&My-Age=3
with this Controller:
public ActionResult List(string First_Name, int My_Age)
{
{...}
}
To repeat, I cannot change the querystring being generated so I need to support it with my controller somehow. But how?
For reference, below is the custom RouteHandler that is being used to handle underscores in controller names and action names from the SO question I referenced above that we might be able to modify to accomplish what I want:
public class HyphenatedRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.RouteData.Values["controller"] = requestContext.RouteData.Values["controller"].ToString().Replace("-", "_");
requestContext.RouteData.Values["action"] = requestContext.RouteData.Values["action"].ToString().Replace("-", "_");
return base.GetHttpHandler(requestContext);
}
}
Have you tried [Bind(Prefix="First-name")]? It might work...
One way would be with a custom model binder. Another way would be with an action filter. Use the model binder if you want to do this on a specific type. Use the action filter if you want to do this on a specific action or controller. So for the latter method you could do something like:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var keys = filterContext.HttpContext.Request.QueryString.AllKeys.Where(k => k.Contains('-'));
foreach(var k in keys)
{
filterContext.ActionParameters.Add(
new KeyValuePair<string, object>(
k.Replace('-', '_'), filterContext.HttpContext.Request.QueryString[k]));
}
base.OnActionExecuting(filterContext);
}
I had the same problem. In the end rather than doing something too complex I just get the query string parameters using
string First_Name = Request["First-Name"];
You may want to check for NUlls incase the parameter is not there, but this sorted it out for me. You can also include an optional parameter for the ActionResult for test purposes etc..