I have a view with an image that has a tap gesture bound to a command:
VIEW:
var clickableImage = new Image(...);
var imageTap = new TapGestureRecognizer();
clickableImage.GestureRecognizers.Add(imageTap);
imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandProperty, _ => _.MyCommand);
The command is in the view model like this:
VIEW MODEL
public ICommand MyCommand
{
get
{
return new Command((parameters) =>
{
// Can I access imageTap element here?
});
}
}
Is there any way to access the imageTap element from within the command that it's bound to?
Yes, you can make use of command parameter.
You can refer this answer/post from one our engineers on Forms team.
https://stackoverflow.com/a/25914911/85606
imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandProperty, _ => _.MyCommand);
//Command parameter
imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandParameterProperty, _ => imageTap);
The CommandParameter is another bindable property on the TapGestureRecognizer, you can set it on another line.
To explain a little bit more thoroughly, when you're using the CommandParameter, the object you bind to gets passed in as the parameter for your Command's Action when it is run. You then have to cast the parameter to the desired type to be able to use it or modify it.
For instance, if you wanted to get a reference to the Image element from within your Command you would set up you Control like so:
var clickableImage = new Image (...);
var imageTap = new TapGestureRecognizer();
clickableImage.GestureRecognizers.Add(imageTap);
imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandProperty, _ => _.MyCommand);
imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandParameterProperty, _ => clickableImage); // clickableImage will be passed to MyCommand when it is run
Then in your MyViewModel class, you would set up your Command like so:
public ICommand MyCommand
{
get
{
return new Command((parameter) => // the bound parameter (the Image element in this case) is passed in as an object
{
var clickableImage = (Image)parameter; // cast the parameter object to an Image.
// Use the element for whatever you need
...
});
}
}
Related
I have this fiddle
let m = new Mine();
this.setState(m, () => {
console.log('1:', m instanceof Mine, m.x, m.meth);
// => 1: true 123 function meth() {}
console.log('2:', this.state instanceof Mine, this.state.x, this.state.meth);
// => 2: false 123 undefined
});
As you can see I create an instance of the Mine class and then set state in a react component with that instance.
I would expect this.state to contain exactly that instance but while the instance properties that are set in the constructor are available I can't access any of the class methods on that instance.
The test in the fiddle shows that this.state is not an instance of the class Mine.
Does anybody understand what is going on or is this unintended behavior?
After more investigation I found out the reason why that happens.
The function _processPendingState from react uses Object.assign to set the new state, so since the target object is a new object (different than what is passed to setState) the new state loses the quality of being an instance of the "Mine" class.
And because Object.assign only copies own enumerable properties from the sources to the target the new state also won't have the class methods.
If in the fiddle we replace the line...
let m = new Mine();
with...
let m = {x: 123};
Object.defineProperty(m, 'meth', {
enumerable: false,
get() { return function() {}; }
});
we still don't have the "meth" property on the resulting state. Even if "m" owns the "meth" property it is not enumerable.
The best solution is to surface the method as an arrow function:
class Blah {
constructor() {
// no definition here for surfacedMethod!
}
surfacedMethod = () => {
// do something here
}
}
Then you can set instances of this class in setState and use their methods as if they were attributes set on the instance.
// other component innards
this.setState(state => ({blah: new Blah()}))
// later
this.state.blah.surfacedMethod(); // this will now work
In such case use replaceState, it should work.
Restangular offers a feature, extendModel, which lets you add functionality onto objects returned from the server. Is there any way to get these methods added to an empty / new model, that hasn't yet been saved to the server?
I wanted to do the same thing but didn't find an example. Here's how I ended up doing it:
models.factory('User', function(Restangular) {
var route = 'users';
var init = {a:1, b:2}; // custom User properties
Restangular.extendModel(route, function(model) {
// User functions
model.myfunc = function() {...}
return model;
});
var User = Restangular.all(route);
User.create = function(obj) {
// init provides default values which will be overridden by obj
return Restangular.restangularizeElement(null, _.merge({}, init, obj), route);
}
return User;
}
Some things to be aware of:
Use a function like _.merge() instead of angular.extend() because it clones the init variable rather than simply assigning its properties.
There is a known issue with Restangular 1.x that causes the Element's bound data to not be updated when you modify its properties (see #367 and related). The workaround is to call restangularizeElement() again before calling save(). However this call will always set fromServer to false which causes a POST to be sent so I wrote a wrapper function that checks if id is non-null and sets fromServer to true.
I just have the following scenario
i want to return string from method but the method should be based on variable type which is (Type CType)
i need to make the render class like this
public string render(TextBox ctype){
return "its text box";
}
public string render(DropDown ctype){
return "its drop down";
}
you know TextBox is a Type thats why i can declare the Type variable like this
var CType = typeof(TextBox)
and i need to call the render method like this
render(Ctype);
so if the Ctype is type of TextBox it should call the render(TextBox ctype)
and so on
How can i make it ?
you should use a template function
public customRender<T>(T ctype)
{
if(ctype is TextBox){
//render textbox
}
else if(ctype is DropDown){
//render dropdown
}
}
hope it will help
First of all, even if you don't see an if or a switch, there will still be one somewhere hidden inside some functions. Distinguishing types at runtime that are not known at compile-time simply will not be possible without any such kind of branching of the control flow.
You can use one of the collection classes to build a map at runtime that maps Type instances to Func<T, TResult> methods. For example, you can use the Dictionary type to create such a map:
var rendererFuncs = new Dictionary<Type, Func<object, string>>();
You could then add some entries to that dictionary like this:
rendererFuncs[typeof(TextBox)] = ctype => "its text box";
rendererFuncs[typeof(DropDown)] = ctype => "its drop down";
Later on, you can call the appropriate function like this:
string renderedValue = rendererFuncs[Ctype.GetType()](Ctype);
Or, if you want to be on the safe side (in case there are Ctype values that have no appropriate renderer):
string renderedValue;
Func<object, string> renderer;
if (rendererFuncs.TryGetValue(Ctype.GetType(), out renderer)) {
renderedValue = renderer(Ctype);
} else {
renderedValue = "(no renderer found)";
}
Note that this will only work for as long as Ctype is of the exact type used as a key in the dictionary; if you want any subtypes to be correctly recognized as well, drop the dictionary and build your own map that traverses the inheritance hierarchy of the type being searched (by using the Type.BaseType property).
I am trying to achieve attribute introduction like here but my attributes have property arguments like: [Foo(Bar = "Baz")]
How do I correctly pass the arguments? I'm not copying the attributes from something else, so I don't think I can use CustomAttributeData?
You can set properties of your custom attributes by using ObjectConstruction.NamedArguments dictionary.
For example:
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
Type targetType = (Type) targetElement;
var objectConstruction =
new ObjectConstruction(typeof (MyCustomAttribute).GetConstructor(Type.EmptyTypes));
objectConstruction.NamedArguments["Bar"] = "Baz";
var introduceAttributeAspect = new CustomAttributeIntroductionAspect(objectConstruction);
yield return new AspectInstance(targetType, introduceAttributeAspect);
}
I'm using ReactiveUI and the provided ReactiveCollection<> class.
In a ViewModel I have a collection of objects, and I wish to create an observable that watches those items for their IsValid property.
This is the scenario I'm trying to solve. In my ViewModel's constructor.
this.Items = new ReactiveCollection<object>();
IObservable<bool> someObservable = // ... how do I watch Items so when
// any items IsValid property changes,
// this observable changes. There
// is an IValidItem interface.
this.TheCommand = new ReactiveCommand(someObservable);
...
interface IValidItem { bool IsValid { get; } }
EDIT Ana's answer got me most of the way there. The solution is the following.
this.Items = new ReactiveCollection<object>();
this.Items.ChangeTrackingEnabled = true;
var someObservable = this.Items.Changed
.Select(_ => this.Items.All(i => i.IsValid));
It depends on what you want to do with the results of IsValid. Here's how I would do it, though it's not entirely intuitive:
// Create a derived collection which are all the IsValid properties. We don't
// really care which ones are valid, rather that they're *all* valid
var isValidList = allOfTheItems.CreateDerivedCollection(x => x.IsValid);
// Whenever the collection changes in any way, check the array to see if all of
// the items are valid. We could probably do this more efficiently but it gets
// Tricky™
IObservable<bool> areAllItemsValid = isValidList.Changed.Select(_ => isValidList.All());
theCommand = new ReactiveCommand(areAllItemsValid);
Since you are using ReactiveUI, you have a few options. If your objects are ReactiveValidatedObjects you can actually use the ValidationObservable:
var someObservable = this.Items
.Select(o => o.ValidationObservable
.Select(chg => chg.GetValue()) //grab just the current bool from the change
.StartsWith(o.IsValid)) //prime all observables with current value
.CombineLatest(values => values.All());
If they aren't ReactiveValidatedObjects, but implement INotifyPropertyChanged, you would just replace the first line and use the handy ObservableForProperty extension method in ReactiveUI for those objects. Instead of o.ValidationObservable you would use o.ObservableForProperty(x => x.IsValid). The rest should be the same.
This is a pretty common use case and I've wrapped it in an extension method for IEnumerable<ReactiveValidatedObject>
I'm sure Paul Betts will come along with something more elegant, but this is what I do.