I have an MvvmCross PCL and a related MonoDroid UI project (pattern copied from following Stuart Lodge's excellent N+1 video series). I want to bind the click of an Action Bar menu item to an ICommand in my ViewModel. I've seen this post but an IMenuItem doesn't appear to have a suitable property to bind to. I'm aware of the SetOnMenuItemClickListener method but (and this is no doubt my lack of understanding) don't know how to leverage this to bind a System.Windows.Input.ICommand to it.
Also, if this is possible, can it be done in the OnCreateOptionsMenu method of the MvxView as this provides a handle to the Action Bar menu itself?
I don't think you can bind it, as the ActionBar is something that is loaded outside of the XML view. Also it does not expose any C# type of events for clicks on items as they are populated from a menu xml file. However you could in your SetOnMenuItemClickListener execute commands when a MenuItem is clicked. You can simply execute a command like this:
ViewModel.MyAwesomeCommand.Execute();
Related
I've got a page where a DataTemplate is being used to bind to the model for that content, e.g.:
<DataTemplate x:DataType="models:MyDataType">
... content ...
</DataTemplate>
In that content, I need to be able to bind a Click event. I need that click event to exist in the view model that is set as the page's DataContext:
<Page.DataContext>
<vm:MyViewModel x:Name="ViewModel">
</Page.DataContext>
but I'm really struggling with getting it to compile. Every approach I try results in the compilation error "Object reference not set to an instance of an object".
I know I can't use x:Bind because that will bind to the DataTemplate's DataContext, so I've been trying to use Binding and, based on other SO answers I've read, it seems like the answer should be:
Click="{Binding DataContext.Button_Click, ElementName=Page}"
where Page is defined as the x:Name for the Page. I've tried removing DataContext. I've tried adding ViewModel.
What am I misunderstanding? Is it not possible to do what I want to do? I've tried using code-behind instead but I'm using Template 10 and that pushes almost everything onto the view model, which makes it harder for me to access things like the navigation service from code-behind.
tl;dr; use Messaging.
#justinXL is right, 'ElementName' can work. But is it best?
The problem you are trying to solve has already been solved with messaging. Most MVVM implementations include a messaging solution. Prism uses PubSubEvents; MVVM Light has its own messenger. There are others, too.
The idea is that an outside class, typically described as a message aggregator, is responsible for statelessly receiving and multicasting messages. This means you need to have a reference to the aggregator but not a reference to the sender. It’s beautiful.
For example
A common use case might be a mail client and how the data template of a message in the list would include a trash/delete button. When you click that button, what should be called? With messaging, you handle the button_press in the model and send/publish a message (one that passes the item).
The hosting view-model has subscribed to the aggregator and is listening for a specific message, the Delete message that we just sent. Upon receipt, it removes it from the list and begins the process to delete it from cache/database, or whatever – including prompting the user with “Are you sure?”
This means all your data binding in your data template is local, and does NOT extend outside its local scope. Why does this matter? Because if you use Element Binding to reach the hosting page, it means you cannot 1) move this template to a resource dictionary or 2) reuse this template.
There are two other reasons.
you cannot use compiled x:Bind to do this because it already limits use of this painful binding approach – this matters because a data template is typically in a list, and performance should always be prioritized, and
It adds considerable complexity.
Complexity?
I am a big fan of sophisticated solutions. I think they are rare and are the trademark of truly smart developers. I love looking at such code/solutions. Complex is not the same as sophisticated. When it comes to complexity, I am not a fan. Data binding is already difficult to wrap your head around; multi-sourcing your data binding across scope boundaries is pure complexity.
That’s what I think.
Your binding expression is correct, except it won't work with a Button_Click event handler. You will need an ICommand defined in your page's ViewModel.
Since you are using Template10, you should be able to create a DelegateCommand called ClickCommand like this
private DelegateCommand<MyDataType> _clickCommand;
public DelegateCommand<MyDataType> ClickCommand
{
get
{
_clickCommand = _clickCommand ?? new DelegateCommand<<MyDataType>>((model) =>
{
// put your logic here.
});
return _clickCommand;
}
}
And the binding will be updated to
<Button Command="{Binding DataContext.ClickCommand, ElementName=Page}" CommandParameter="{x:Bind}" />
Note I have also added a CommandParameter binding to the button as you might want to know which MyDataType instance is associated with the clicked button.
I wish to bind a filter dynamically in the controller of a xml view to a control in the view. I know how to do this but I don't find a proper way to do this initially.
E.g. I defined a ComboBox on the view and gave a binding path to the oData model (in the view). Then in the controller I wish to set a fiter on the items of the ComboBox. I tried in onInit of the view but there the binding is not yet set in the ComboBox object.
I solved it by doing a lazy loading and set the filter in the "loadItems" event. Is there any way to do this by not using lazy loading? Did not find a proper event or standard hook.
Thanks.
So the binding is not available in oninit()... Where exactly do you create the binding then the very first time??? Where ever you create the binding the first time you can also apply the initial filters.
For example, in the controller inside onInit you call this.byId("myComboBox") to get the control. Then you call oComboBox.bindItems({...}) and also pass the initial filters. So bindItems(...) also accepts filters. If the filters change you can simply call oComboBox.getBinding("items").filter(...) to update the filters. Check the worklist app tutorial for some details...
By the way, you could also directly specify the binding including filters in the XMLView directly. See my answer here for details.
I have an NgComponent in Angular Dart which instantiates a search box and according to the query strings it populates another div in my html template with the ng-repeat directive.
More precisely,
Query string update: there is a binding to the input text value with a field in my components' controller.
Results population: In the attach() method I added a watcher for the local field which acts as a model to the input box, and whenever it changes I add to a local list some items which then acts as a model to the ng-repeat directive in another div.
So far everything works fine. But now I want to add some event listeners inside my component, like keystroke listeners or if possible to add listeners on specific elements in my html template. I have used CSS for hover and focus events and also ng-focus and ng-blur for easy functions. But I do not think that this can be used for keystroke listeners.
The reason I want the keystroke listener is to enable results traversing using the arrow keys. While the cursor is inside the input text box I would like to move to the first result, which is in another div, with the press of Down arrow, and then continue to the other results.
Thank you
OK, It seems that I have finally found the solution.
The solution is to implement the NgShadowRootAware interface with my component and then inside the void onShadowRoot(ShadowRoot shadowRoot) method I have full access to the DOM created inside the shadow dom template.
When you wish to create a new application and click on MDI, Delphi creates a basic MDI application for you with the basic menu items and graphics. You can run the program and create children windows and using the Window menu item place the children in cascade, tile, etc. arrangements.
My question is: where is the code to perform these operations?
I am stumped. You open the pas file editor and basically nothing is there. How does it do it?
Each menu item is linked to different types descendants of TWindowsAction=class(TAction). For example WindowsCascadeItem menu item is linked to WindowsCascade1:TWindowsCascade(=class(TWindowAction)) action. So code is hidden in this class implementation in VCL\STDActns.PAS.
I'm developing a Firefox extension. There is a menu X which I need to show in both Tools menu and Context menu. Tools menu item and Context menu item are defined in same file but menu X in another file.
As I'm reusing menu X by id only last use of it is effective. How can I reuse it multiple time in same file without redundancy?
It can be done using XBL.
I haven't found a good solution either. The approach is rather to define the menu in the overlay only once and then clone it in your "load" event handler. You can then insert the clone at the second location. You have to be careful because ID attributes have to stay unique - so if your menu uses ID attributes you will have to additionally rewrite them. Ugly, I know.
IDs are, per definitionem, unique. That means you can't share the menuitem but you can share the code that gets executed when the action is invoked. One way to achieve this is to use commands.