Xamarin AutoSuggestBox Selected Item as Command Parameter - c#

My panelists ask me if I can put an auto-suggestion in my application. After some research, I've decided to use this AutoSugggestionBox and followed this tutorial. However, I am having a hard time displaying the selected suggestion since I am converting it into an MVVM. In timestamp 16:12, he uses the dotMorten.Xamarin.Forms.AutoSuggestBoxQuerySubmittedEventArgs parameter to get the ChoseSuggestion.
My question is, what will I put in the CommandParameter if I use xct:XamarinCommunityTools EventToCommandBehavior
<control:AutoSuggestBox PlaceholderText="Enter"
x:Name="AutoSuggestBox">
<control:AutoSuggestBox.Behaviors>
<xct:EventToCommandBehavior EventName="QuerySubmitted"
Command="{Binding quesrySubmitComm}"
CommandParameter=""
</control:AutoSuggestBox.Behaviors>
</control:AutoSuggestBox>
Or is there a more simplified way to MVVMify an AutoSuggestBox?
Thank you in advance for your answers.

Based on João's suggestions to use SuggestionChosen, I managed to get a work around with the MVVM
This is in my view
<control:AutoSuggestBox x:Name="box">
<control:AutoSuggestBox.Behaviors>
<xct:EventToCommandBehavior EventName="TextChanged"
.../>
<xct:EventToCommandBehavior EventName="SuggestionChosen"
Command="{Binding showComm}"
CommandParameter="{x:Reference box}"/>
</control:AutoSuggestBox.Behaviors>
</control:AutoSuggestBox>
And this is in my ViewModel
public ICommand showComm { get; }
private async Task show(object sender)
{
AutoSuggestBox input = (AutoSuggestBox)sender;
await App.Current.MainPage.DisplayAlert("", input.Text, "OK");
}

Use SuggestionChosen for this!
You don't need this command.
Try this.
<control:AutoSuggestBox PlaceholderText="Enter"
x:Name="AutoSuggestBox"
SuggestionChosen="SuggestionChosen"/>
Create the method and get the chosen.

Related

Getting a value from a child WPF window that has a seperate viewmodel using the MVVM pattern

I have made quite a bit of progress on my first MVVM WPF application, the issue I am now having is I have a Window that has a viewmodel. This window has a button which opens another window that has another viewmodel.
Imagine a textbox on the first window. Once the second is opened the user will select a value and click save, this window will close and update the first window with its value.
When pushing save I have an ICommand on the childwindows Viewmodel that calls the SaveMethod. I have the selected value stored in a property on the Child windows viewmodel. But how do I update the Main Windows textbox with this value? I imagine I bind a property on the main windows view model, but unsure on how to continue.
Please advise, I can provide code examples if needed, but I think I may have explained it well enough, oh and thanks to everyone at StackOverflow for the help on my questions I have learnt a lot.
This is pretty straightforward using the MVVM Light framework. For the purposes of demonstration I'm going to use a string as the value you're passing, but it's easy to construct a different message type for whatever you need to pass.
In the constructor of your first Window's ViewModel you register to receive NotificationMessages. NotificationMessages are used to send string messages:
public MyFirstViewModel()
{
Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}
In the SaveMethod in your second Window's ViewModel you send a message with the value you want to pass. I'm using MyStringValue as the name of the property that stores the value chosen by the user in your second Window:
private void SaveMethod()
{
MessengerInstance.Send(new NotificationMessage(MyStringValue));
}
When that message is received by the ViewModel of the first Window the NoitificationMessageReceived method is called. I'm going to put that value in a string property on the first ViewModel called MySavedValue:
private void NotificationMessageReceived(NotificationMessage msg)
{
MySavedValue = msg.Notification;
}
In your View for the first Window you have a TextBox with its Text property bound to MySavedValue. This updates whenever MySavedValue is updated.
In the parent viewmodel, you'll need a reference to the child viewmodel. When the child window is closed, you'll want to get the value of the secondviewmodel's property and set it to a appropriate property of the first parent viewmodel.
One of the posible (and simple) solutions is to keep one ViewModel for both windows
<Grid>
<StackPanel>
<TextBox Text="{Binding TheText}" />
<Button Command="{Binding ShowOptionsCommand}" Content="..."/>
</StackPanel>
<Popup IsOpen="{Binding IsShowingOptions}">
<StackPanel>
<ListBox ItemsSource="{Binding Options}"
SelectedItem="{Binding SelectedOption,Mode=TwoWay}"/>
<Button Command="{Binding SaveOption}">Save</Button>
</StackPanel>
</Popup>
</Grid>
//ShowOptionsCommand handler
void ShowOptions()
{
IsShowingOptions = true;
}
//SaveOptionCommand handler
void SaveOption()
{
TheText = SelectedOption;
IsShowingOptions = false;
}
I'm using the Popup to simplify the example.
Personally I'd go with the mvvm light framework already mentioned, but another option is to leverage IOC, also included with the above framework.
With this pattern view models have interfaces and are bound as properties from a view model locator data source. Within that, the child view model can be injected to the parent view model. Because IOC can create singleton instances of objects, the same instance gets given to the parent as is bound to the child window. That way you get a reference to the view model but through an interface thus preserving the separation.
Just offering this as an alternative technical solution beyond those already offered.

Metro style windows 7 WPF app -toggleSwitch-

I'm currently fiddling around with the look of one of my older wpf apps using MahApps metro library. I'm stuck with Controls:ToggleSwitch where I can bind almost everything but commands.
When I try to bind a command as below,
<Controls:ToggleSwitch Header="Start Playing" OnLabel="Stop" OffLabel="Play"
IsChecked="{Binding ToggleRecordCommand}"
CommandParameter="{Binding}" />
I get an error like;
Error 62 A TwoWay or OneWayToSource binding cannot work on the read-only property 'ToggleRecordCommand' of type 'RecorderApp.View.MainWindowViewModel'.
Also it tells me there is no CommandParameter. How am I going to bind actions to this?
First of all, as Brendan said, IsChecked property has to be binded with a general Property which has INotifyPropertyChanged, NOT an ICommand type.
In order to bind with Command, the easiest workaround is to use Click(or Checked) event with xaml.cs Code-behind works.
In XAML, as below.
<ToggleButton x:Name="recordButton"
Checked="OnRecordButton_Checked"
IsChecked={Binding IsRecording} />
In Code-behind, as below.
private void OnRecordButton_Checked(object sender, RoutedEventArgs e)
{
if (recordButton.IsChecked.GetValueOrDefault())
{
// Do your own logic to execute command. with-or-without command parameter.
viewModel.ToggleRecordCommand.Execute(null);
}
}
And, In ViewModel (assumption), as below.
// Property for toggle button GUI update
public bool IsRecording{
get{ return _isRecording;}
set{
_isRecording = value;
NotifyPropertyChanged("IsRecording");
}
}
public ICommand ToggleRecordCommand{
// Your command logic.
}
IsChecked is a bool? property and will likely not work if you pass it an ICommand. Source code
If you'd like to see this supported, please raise an issue on the project site and we can discuss it further.

Any built in way to format WPF bindings?

Scenario
I can't seem to find a way to format bindings in WPF using an IFormatProvider. Currently I've a property on my data source:
public int PersonNumber { get; set; }
This property is bound to a Label in XAML:
<Label Content="{Binding Path=PersonNumber}" />
As you can see it's a number, but should be formatted like 0000.00.000. Currently we use a separate IFormatProvider for such things in our old WinForms application.
Questions
Is formatting like this possible in WPF?
If yes, our preferred way is to still use an IFormatProvider, also possible?
If no, what is a good alternative?
Thanks in advance!
You're looking for the ContentStringFormat property, which is on all ContentControl descendants including Label.
<Label Content="{Binding PersonNumber}" ContentStringFormat="000" />
I'm not sure whether WPF's formatting can make use of an IFormatProvider, though.
And to be complete, you could just add a String property to your ViewModel to get full control in C#:
public int PersonNumber { get; set; }
public string PersonNumberText { get { return ... } }
You can use the property StringFormat of Binding
Nice example: http://blogs.msdn.com/b/mikehillberg/archive/2008/05/29/trying-out-binding-stringformat.aspx
In addition to the posted answers, there's always available the converter way.

How to detect Pivot View using MVVM in WP7?

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>

WPF: Binding to commands in code behind

I have a WPF Microsoft Surface Application and I'm using MVVM-Pattern.
I have some buttons that are created in code behind and I would like to bind commands to them, but I only know how that works in the XAML
like this:
<Custom:SurfaceButton Command="{Binding SaveReservationCommandBinding, Mode=OneWay}"/>
But I cannot do it like this because my buttons do not exist in the XAML, only in the code behind.
So how would a command binding like that works in code behind?
The accepted answer will work great if the Button has access to the Command. However, in MVVM these are usually kept separate (the Button in the View and the Command in the View-Model). In XAML you'd normally use a data binding to hook it up (like the example in the question).
My program gave me an error when my dynamic Button couldn't find the Command (because it was in a totally different namespace). This is how I ended up solving this:
SurfaceButton.SetBinding (Button.CommandProperty, new Binding("SaveReservationCommand"));
Assuming that you have a named your SurfaceButton to "SurfaceButton1" and you have access to an instance of the command, you can use the following code:
SurfaceButton1.Command = SaveReservationCommand;
I took the code from the link posted by Anvaka as template. I use RadMenuItem of Telerik, but surely you can use any other component that expose Command property.
item = new RadMenuItem();
item.Header = "Hide Column";
DependencyProperty commProp = RadMenuItem.CommandProperty;
if (!BindingOperations.IsDataBound(item, commProp)) {
Binding binding = new Binding("HideColumnCommand");
BindingOperations.SetBinding(item, commProp, binding);
}
//this is optional, i found easier to pass the direct ref of the parameter instead of another binding (it would be a binding to ElementName).
item.CommandParameter = headerlCell.Column;
menu.Items.Add(item);
Hope it helps ... and if something is not clear, sorry, it's my first post :)
This works
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}, Path=SaveReservationCommand}"

Categories