i'm trying to get location, when I tap on bing map control. I know how to get it, but I want to make it in ViewModel. For Tap event I use interactions.
<map:Map CopyrightVisibility="Collapsed" LogoVisibility="Collapsed">
<map:MapTileLayer>
<map:MapTileLayer.TileSources>
<customMap:OpenStreetTile />
</map:MapTileLayer.TileSources>
</map:MapTileLayer>
<map:MapLayer>
<map:Pushpin Location="{Binding Location}" />
</map:MapLayer>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<cmd:EventToCommand Command="{Binding AddPushpinCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</map:Map>
I can get position from eventarguments with GetPosition function. But this function need UIElement parameter.I made it so:
var source = (e.OriginalSource as MapLayer).ParentMap;
var point = e.GetPosition(source);
Location = source.ViewportPointToLocation(point);
But Im not sure if it is good solution. Do you have any idea how to do it?
Thanks
Well, your approach certainly works and sometimes, good enough is good enough. ;) If you want to be 100% clean with your MVVM implementation, you should avoid references to the view (and thus the MapLayer class) however.
Joost van Schaik wrote a blog post that shows how to achieve this using behaviors (it's for Windows Phone 8, but I'm sure it applies to Windows Phone 7 as well): http://dotnetbyexample.blogspot.nl/2013/03/simple-reverse-geocoding-with-windows.html
Related
I'm currently trying to implement a ImageViewer with the possibility to move and zoom with touch inputs.
I already implemented these functionalities in a recent project in the Code Behind, but I'm struggling to do so in a View Model in MVVM.
Problem is that for my code to work I have to know how many touch inputs are recognized at the same time.
In my Code-Behind I used:
canvas.TouchesCaptured.Count()
The ViewModel shouldn't not know any Controls of the View, so passing the Canvas as a Command Parameter is not the way to go.
Beside the canvas I need the TouchEventArgs of the triggered TouchEvent to determine the position of the TouchEvent on the canvas.
Using Prism I was able to get the TouchEventArgs into the ViewModel.
<i:Interaction.Triggers>
<i:EventTrigger EventName="TouchDown">
<prism:InvokeCommandAction Command="{Binding TouchDownCommand}"
</i:EventTrigger>
</i:Interaction.Triggers>
prism:InvokeCommandAction automatically sets the EventArgs as the CommandParameter for clarification.
To determine the position of the TouchEvent on the Canvas I need the canvas and the TouchEvent.
In my Code-Behind it looked like that:
startingPoint = e.GetTouchPoint(canvas);
Anyone has a idea how I can solve this problem without violating the MVVM Pattern?
You could try writing a Blend behavior that encapsulates the Canvas event handling and exposes commands (e.g. ManipulationDelta in particular). You could even add a property to the behavior that exposes the TouchesCaptured values (during the ManipulationDelta event).
e.g.
<Canvas>
<i:Interaction.Behaviors>
<bhv:CanvasBehavior ManipulationDeltaCommand="{Binding MyViewModelCommand}" TouchPointCount="{Binding MyViewModelTouchPointCount}" />
</i:Interaction.Behaviors>
</Canvas>
Mouse gestures can be bound to commands using the MouseBinding InputBinding,
for example:
<Grid.InputBindings>
<MouseBinding Command="{Binding MyCommand}" Gesture="LeftClick"/>
</Grid.InputBindings>
In that example, the LeftClick gesture is used. What is the full list of gesture strings? I'm looking for a left mouse button down gesture, if it exists.
That is a MouseAction value. You can see possible values in the documentation. Mouse down is not a built-in gesture. Only various clicks and double clicks are in the enumeration.
It is possible to make your own input bindings by creating classes that extend InputBinding and InputGesture. You can reference the implementation of MouseBinding for an example. Alternatively, you can find a different way to accomplish whatever it is you are trying to do.
I'm looking for a left mouse button down gesture, if it exists.
That would be the LeftClick mouse action that you are currently using.
If you want to invoke a command when the MouseLeftButtonDown event occurs, you could do this using an interaction trigger:
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown" >
<i:InvokeCommandAction Command="{Binding MyCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Please refer to the following blog post for more information about this.
Handling events in an MVVM WPF application: https://blog.magnusmontin.net/2013/06/30/handling-events-in-an-mvvm-wpf-application/
The EventTrigger class is included in th Expression Blend SDK which you can download from here: http://www.microsoft.com/en-us/download/details.aspx?id=10801.
I'm developing an application in which the user needs to enter a username and password to login.
I'm using the MVVM light framework to separate my view from my viewmodels.
For now I have a button on my view which tapped event is caught on the corresponding viewmodel.
I would also would like to have the possibility if the user presses the enter button they can also login. In WPF you had the ability to set a button as IsDefault, but it seems not possible in WinRT.
How can I do this?
I think you can put this code into your viewmodel and check if the enter key is pressed, then when it is pressed just launch the same method you would launch if your button was pressed
Windows.UI.Xaml.Window.Current.CoreWindow.KeyDown += (sender, arg) =>
{
if (arg.VirtualKey == Windows.System.VirtualKey.Enter)
{
//Your login method
}
};
As per my comment I don't recommend using UI code in the view model. Use a trigger to bind to a command for a keypress in the textbox.
<TextBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommandCommand="{Binding MyCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
be sure to incluide the following in your xaml declarations:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="http://www.galasoft.ch/mvvmlight"
Hope this helps
There's a virtual method on the Page called OnKeyDown() you can override. This is safer than subscribing to events and fits MVVM better. I prefer to cast DataContext to my view model type and call whatever I want.
It is possible to achieve this with behaviors:
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="KeyDown">
<core:CallMethodAction TargetObject="{Binding}" MethodName="Load" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
You'll have to reference:
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
However, it only works for all keys. I didn't see any possibility to filter for a certain key.
There are:
xmlns:i="using:WinRtBehaviors"
xmlns:b="using:Win8nl.Behaviors"
<i:Interaction.Behaviors>
<b:EventToCommandBehavior Event="Loaded" Command="LoadedCommand"/>
</i:Interaction.Behaviors>
from Nuget.
basically I have a pivot control in my WP7 app that contains 3 views. On each view I'm calling 1 of my 3 different web services that I run. What I'm trying to do is call the service only when they navigate to that particular view.
It's pretty simple using the code behind because all you do is use selected index with a switch statement and you can fire certain methods accordingly. Any idea on how to accomplish this from a view model?
NOTE: I'm using MVVM Light.
UPDATE: Here's my code that I would normally use:
private void PivotItem_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int currentPivot = ResultsPivot.SelectedIndex;
switch (currentPivot)
{
case 0:
//Fire Method 1
break;
case 1:
//Fire Method 2
break;
case 2:
//Fire Method 3
break;
default:
//Fire default method
break;
}
}
The standard approach with MVVMLight is the split your view-model into data and commands. Most things you use databinding related, properties, etc. but commands actually do something.
In this case what you are calling "Fire Method 1" is an ordinary method that to conform to the pattern you have to convert to a command. If you already have commands you know what I am talking about.
The glue for events like SelectionChanged that you would have wired up with code-behind in MVVMLight is EventToCommand which is a XAML fragment that you put in the XAML with the pivot item instead of in the event hander.
So this is the pattern: EventToCommand is your key to hooking up XAML events to view-model commands without any code-behind. The best thing to do is use the MVVMLight samples to see how EventToCommand works because there are lots of ways to use it.
But here is the bare-bones version:
<controls:PivotItem Name="pivotItem">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SelectServiceCommand}"
CommandParameter="{Binding SelectedIndex, ElementName=pivotItem}"/>
</i:EventTrigger>
<!-- other stuff -->
</i:Interaction.Triggers>
</controls:PivotItem>
and to make this work the SelectServiceCommand has to actually exist in the view-model and it has to take a parameter and do the right thing for 0, 1, 2, 3, etc.
This can be solved in the following way
<controls:Pivot x:Name="PivotControl" FontSize="18" >
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="SelectionChanged">
<GalaSoft_MvvmLight_Command:EventToCommand x:Name="VideoPivotClicked"
Command="{Binding VideoPivotClicked, Mode=OneWay}" PassEventArgsToCommand="True" />
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
Then in your viewmodel you add this
public RelayCommand<SelectionChangedEventArgs> VideoPivotClicked
{
get;
private set;
}
VideoPivotClicked = new RelayCommand<SelectionChangedEventArgs>(arg =>
{
PivotItem pivotItem = arg.AddedItems[0] as PivotItem;
Pivot pivot = pivotItem.Parent as Pivot;
Debug.WriteLine(pivot.SelectedIndex);
}
);
You will not get the PivotItem that you are going to! and not the one you are leaving.
I haven't used MVVM Light directly, but you should be able to bind the selected index / item to a property on the view model. When that property is changed you could do your switch.
I like to keep things simple in situations like these where the View needs to notify the ViewModel that something that is so trivial changed (for example: A trivial combobox selection change that really has nothing to do with the view state (i.e ViewModel)).
For your specific case, in your switch statement, just call a public method in your ViewModel.
How to get the viewmodel reference? You can obtain that by the view's DataContext. So now your views can call public methods (and properties) within your viewModel.
For significant things stick with DataBinding. otherwise, just call directly. Saves so much time and hassle.
I get the index for the pivotItem that I'm leaving, not the PivotItem that I'm going to! .
Using this:
<controls:Pivot x:Name="pivMain" Title="{Binding AppName}" >
<Custom:Interaction.Triggers>
<Custom:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SelectServiceCommand}"
CommandParameter="{Binding ElementName=pivMain, Path=SelectedIndex}"/>
</Custom:EventTrigger>
</Custom:Interaction.Triggers>
Is it possible to create a command behavior using Prism's CommandBehaviorBase class for Silverlight's grid? I know that it is only intended for actual controls, so I was wondering if anyone might know if a workaround. I would like to create an attachable mouse over behavior for a grid, that executes a specific command, and ideally would like to use Prism for this approach, just can't seem to use CommandBehaviorBase for a Grid.
Thanks.
The arguably easier way to achieve this is to use Triggers. Doesn't require you to write any code, all you have to do is this:
<Grid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<si:InvokeDataCommand Command="{Binding DoSomethingCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
...
</Grid>
Here the DoSomethingCommand (defined in a ViewModel) will trigger when MouseEnter event is fired on the Grid.