Xamarin: Binding grouped RadioButton isChecked property with a viewModel - xamarin

Just to be clear I'm talking here about the RadioButton released with Xamarin 4.6 in 2006.
My aim here is to create one binding which will work with multiple RadioButtons in the same group. Ultimately so I can leave my screen and come back to it and set the last selected RadioButton item.
So I know you can set a true of false property binding to the IsChecked property. However, this single item has no context of which item it is.
I know you can also set a binding context to a page or a control... so I guess I could set a context to a StackLayout for all the items inside it... but this still won't help.
This is something like what I want to achieve... yes I won't acctually have 10, I'm just making a point that I don't want to have to use lots of different bindings..
<RadioButton GroupName="Numbers" Text="One"
IsChecked="{Binding IsCheckedNumbersgroup}" />
<RadioButton GroupName="Numbers" Text="Two"
IsChecked="{Binding IsCheckedNumbersgroup}" />
....
<RadioButton GroupName="Numbers" Text="Ten"
IsChecked="{Binding IsCheckedNumbersgroup}" />

If we binding the same source with multi RadioButton , it will cause issue as when you click one of them , other RadioButton will also been effected .
So in your case if you do not want to define multi property , you could define a List and binding them with the item .
in Xaml
Command, which is executed when the RadioButton is selected.
<RadioButton GroupName="Numbers" Text="One" IsChecked="{Binding MySource[0]}" Command="{Binding ButtonCommand}" CommandParameter="0" />
<RadioButton GroupName="Numbers" Text="Two" IsChecked="{Binding MySource[1]}" Command="{Binding ButtonCommand}" CommandParameter="1" />
<RadioButton GroupName="Numbers" Text="Three" IsChecked="{Binding MySource[2]}" Command="{Binding ButtonCommand}" CommandParameter="2" />
in ViewModel
public ObservableCollection<bool> MySource { get; set; }
public xxxViewModel()
{
MySource = new ObservableCollection<bool>() {true,false,false };
ButtonCommand = new Command((org)=> {
var index = int.Parse(org.ToString());
App.Current.MainPage.DisplayAlert("Title","the status of RadioButton"+(index+1).ToString()+"is"+MySource[index].ToString() ,"OK");
});
}

Related

how to use radio buttons in xamarin forms

Creating a Registration page, I need to get the following data from user.
First Name
Last Name
Username
Email
Password
Date of Birth
Gender
User Role
For the last two parameters, I am unable to find how to use radio buttons in Xamarin.Forms. Following is my code for the Registration Page.
<StackLayout BackgroundColor="#30af91" Padding="60">
<Entry Text="{Binding FirstName}" Placeholder="First Name"/>
<Entry Text="{Binding LastName}" Placeholder="Last Name"/>
<Entry Text="{Binding UserName}" Placeholder="Last Name"/>
<Entry Text="{Binding Email}" Placeholder="Email" />
<Entry Text="{Binding Password}" Placeholder="Password" IsPassword="True"/>
<Entry Text="{Binding ConfirmPassword}" Placeholder="Confirm Password" IsPassword="True"/>
<DatePicker MinimumDate="1/1/1948" MaximumDate="12/31/2007"/>
<!--Radio buttons for Gender
1. Male 2.Female-->
<!--Radio Buttons for UserRole
1. Admin 2.Participant-->
<Button Command="{Binding RegisterCommand}" Text="Register"/>
<Label Text="{Binding Message}" />
</StackLayout>
Xamarin forms does not provide Radio Button.
You can either use
1)Switch
2)Picker
or any other component to fulfill your requirement
UPDATE
The xamarin forms update version 4.6 has introduced the Radio button control, Here is the official documentation
I think there is a simpler solution that is fairly easy and requires no libraries. Really a a radio group is just a fancy ListView. You would just need to create a viewModel for each radio button that has a IsSelected flag and switch between 2 images. I had a need to allow a user to select how long a token persisted:
XAML
<ListView
HasUnevenRows="True"
HorizontalOptions="FillAndExpand"
ItemsSource="{Binding Durations}"
ItemSelected="ListView_ItemSelected"
SelectedItem="{Binding SelectedDuration}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout
Orientation="Horizontal">
<Image
HeightRequest="18"
IsVisible="{Binding IsSelected}"
Source="radioButtonChecked.png"
WidthRequest="18"/>
<Image
HeightRequest="18"
IsVisible="{Binding IsUnselected}"
Source="radioButtonUnchecked.png"
WidthRequest="18"/>
<Label
Margin="8,0,0,0"
Text="{Binding Caption}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
We create a listview in our content page and listen for the ItemSelected event. Each list item is a horizontal stack panel where we flip between two images depending on the selected state
Code Behind
public partial class LoginPage : ContentPage
{
LoginPageViewModel LoginPageViewModel { get; }
public LoginTwoFactorFrequencyPage ()
{
BindingContext = LoginPageViewModel = new LoginPageViewModel();
InitializeComponent ();
}
private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
LoginPageViewModel.UpdateSelected(e.SelectedItem as PersistenceDuration);
}
}
The page's code behind instantiates a view model and calls an UpdateSelected method with the newly selected item on the page's view model*
RadioButton ViewModel
The view model for each radio button:
public class PersistenceDuration : ViewModelBase
{
bool isSelected;
public string Caption { get; set; }
public TwoFactorTokenPersistenceDuration Duration { get; set; }
public bool IsSelected
{
get => isSelected;
set
{
isSelected = value;
OnPropertyChanged();
OnPropertyChanged("IsUnselected");
}
}
public bool IsUnselected => !IsSelected;
public PersistenceDuration(string caption, TwoFactorTokenPersistenceDuration duration)
{
Caption = caption;
Duration = duration;
IsSelected = false;
}
}
The radio button view model holds selection info and the caption. We make sure to fire OnPropertyChanged whenever the selected state changes
Page ViewModel
public class LoginPageViewModel : ViewModelBase
{
PersistenceDuration duration;
PersistenceDuration selectedDuration;
public ObservableCollection<PersistenceDuration> Durations { get; }
public PersistenceDuration SelectedDuration
{
get => selectedDuration;
set
{
if (value != null)
{
duration = value;
UpdateSelected(duration);
}
OnPropertyChanged();
}
}
public LoginTwoFactorFrequencyViewModel()
{
Durations = new ObservableCollection<PersistenceDuration>(
new List<PersistenceDuration>()
{
new PersistenceDuration(AppResources.Save_code__forever, TwoFactorTokenPersistenceDuration.Forever),
new PersistenceDuration(AppResources.ChatRequireEvery30Days, TwoFactorTokenPersistenceDuration.ThirtyDays),
new PersistenceDuration(AppResources.ChatRequireEveryLogin, TwoFactorTokenPersistenceDuration.None),
});
}
public void UpdateSelected(PersistenceDuration persistenceDuration)
{
foreach (var item in Durations)
item.IsSelected = persistenceDuration == item;
}
}
In the page view model we create a list of radio button view models that the XAML binds to. When we UpdateSelected() all the IsSelected states are updated which trigger binding updates which flip the image.
You will still need to do something about the highlight when someone selects an item, but that is easy enough to find on the internet :)
You can use XLabs plugin from manage NuGets package. After installing you can use like this:
In Xaml:
controls:BindableRadioGroup x:Name="Radiobtn"
In C#:
string[] gender = {"MAlE","FEMALE"}
Radiobtn.Add(gender)
Refer Link
https://github.com/XLabs/Xamarin-Forms-Labs/tree/master/samples/XLabs.Samples/XLabs.Samples/Pages/Controls
You can get the radio button effect without a package. Use Labels with text unicode circle \u26AA or \u25CB. Attach a tab gesture recognizer to each label.
When tapped, change the text of the selected button to unicode circle bullet \u29BF and change the text of the other button(s) back to unicode circle \u26AA.
Test on your preferred platforms as each platform may display somewhat differently. You may need to adjust the font size as you change the text.
If you want real radiobuttons you can xlabs their package (https://github.com/XLabs/Xamarin-Forms-Labs/tree/master/src/Forms/XLabs.Forms/Controls/RadioButton)
Personally I'd just use a picker, Xlabs package hasn't been updated in a while so their might be some bugs in the radiobutton
You can use image as a radio button. When tou you click on it, it can change. It is not a good way to do it though.
This is xaml code:
<Image Scale="0.7" HorizontalOptions="Start" x:Name="radioButton" Source="unRadioBtn.png">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="radioButton_Clicked"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
And this is .cs:
private void radioButton_Clicked(object sender, EventArgs e)
{
radioButton.Source = "radioBtn.png";
}
Xamarin.Forms 4.6 introduced a new RadioButton control. You can find the documentation here: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/radiobutton
You can use the switch component. Also you can see the implementation for a checkbox component from the XLabs project which is now discontinued, get the code and modify it as you need.
Hint: You're gonna need the custom renderers per platform for it to work .
You need to use Picker
https://developer.xamarin.com/api/type/Xamarin.Forms.Picker/
Actually it is the best alternative to RadionButton On Xamarin.forms
XLabs RadioButton and BindableRadioGroup work well: XLabs RadioButton for Xamarin Forms
Here's a simple Yes/No radio using the BindableRadioGroup:
var answers = new List<string>();
answers.Add("Yes");
answers.Add("No");
var RadioGroup = new XLabs.Forms.Controls.BindableRadioGroup()
{
ItemsSource = answers,
Orientation = StackOrientation.Horizontal
};
Xamarin Forms now provides a Radio Button control.
See docs here:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/radiobutton
As of XF 4.8 this is still experimental and I've not yet used this feature so can't comment on its stability.

how to checkbox checked for all in listbox datasource in wp8?

while selecting all means renaming all the checkbox are checked. my code is below:
<ListBox Name="VillageList">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding isCheched}" Content="{Binding Villages}" IsChecked="False"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
so all checkbox are inside the listbox.how to checked is enable for all checkbox single selection.
public class villageinformation
{
public string Villages{get;set;}
public bool isChecked {get;set;}
}
page.cs{
list<villageinformation> mydataSource=new list<villageinformation>();
myDataSource.Add(new villageinformation(){Village="All",isChecked ="False"});
myDataSource.Add(new villageinformation(){Village="name1",isChecked ="False"});
myDataSource.Add(new villageinformation(){Village="name2",isChecked ="False"});
myDataSource.Add(new villageinformation(){Village="name3",isChecked ="False"});
VillageList.itemSource=myDataSource;
}
so while clicking manually "All" checkbox remaining name1,2,3 are selected how to do this?
If you are using the ObservableCollection for your villages list, which is used for the data binding to the ListBox, then you can set all values in the ObservalbeCollection in the codebehind which shoul update the UI (by checking all the Checkboxes)
you can do it something like this
foreach(var village in VillagesCollection)
{
village.isChecked = true;
}
If you are not able to understand the above, edit your question with how you are setting up the Village data in the code behind file (means .xaml.cs file)

Get selecteditem from listbox using MVVM

I'm using MVVM in this project, I have a listbox which bind to a collection of Customers. I want to create an event to navigate a detailsPage using id of the elementselected:
<ListBox ItemsSource="{Binding Customers}" x:Name="state_list" SelectionChanged="state_list_SelectionChanged">
<i:Interaction.Triggers>
<i:EventTrigger EventName="selectionchanged">
<cmd:EventToCommand Command="{Binding stateSelectedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding nom}" />
<!--TextBlock Text="{Binding LastName}" />
<TextBlock Text="{Binding Text, ElementName=tbCount}" /-->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I can't figure out how to get the selected item to add it to the uri and then use it to get data. An example or tutorial would be helpful. Thanks :)
I would create a "SelectedCustomer" property in the ViewModel (next to you Customers property) and bind it to the SelectedItem. Then, on the setter of that property you can navigate to your desired page. This way you eliminate the messy events and command.
<ListBox x:Name="state_list
ItemsSource="{Binding Customers}"
SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}">
...
public Customer SelectedCustomer
{
get
{
return _selectedCustomer;
}
set
{
if (value != null)
{
_selectedCustomer = value;
//Navigate to your page here, either with Navigator class or any other mechanism you have in place for changing content on screen
}
}
}
AlexDrenea gives you a good way of binding SelectedItem to a property on your viewmodel. If you are wanting to navigate based on this in an MVVM architecture, I would suggest using messaging to get it done.
I cover this in a blog post I did a while back, but the short summary of doing this within MVVMLight, is to create a Navigator class that sits at the application level.
public class Navigator
{
private PhoneApplicatoinFrame RootFrame;
public Navigator(PhoneApplicationFrame frame)
{
RootFrame = frame;
RegisterMessages();
}
private void RegisterMessages()
{
Messenger.Default.Register<ShowTrackerMessage>(this, ShowTracker);
}
private void ShowTracker(ShowTrackerMessage msg)
{
RootFrame.Navigate(new Uri("/Views/ItemLocationCompassView.xaml", UriKind.RelativeOrAbsolute));
}
}
Then, as part of your application start-up, create it and pass it a reference to your RootFrame:
private static Navigator _navigator;
public static Navigator Nav
{
get { return _navigator; }
}
...
_navigator = new Navigator(this.RootFrame);
Then, you have a couple choices on how you send the Navigation message.
Option 1: In your ViewModel, hook into the PropertyChanged event (part of INotifyPropertyChanged), and send the appropriate message when your SelectedItem property changes.
Option 2: Tie into the SelectionChanged event of your ListBox. I use the MVVMLight's EventToCommand to send that event to a RelayCommand in my ViewModel, then react appropriately to send the message to the Navigator object.
I cover this in more detail at: http://www.smartchitecture.com/?p=27

How do I add a behavior to ApplicationBarIconButton in C#?

I am attempting to add items to an application bar with behavoirs.
In xaml they look like:
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True"
IsMenuEnabled="True">
<shell:ApplicationBarIconButton x:Name="Save"
IconUri="/resources/icons/appbar.check.rest.png"
Text="Save" />
<shell:ApplicationBarIconButton x:Name="Cancel"
IconUri="/resources/icons/appbar.cancel.rest.png"
Text="Cancel" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
<i:Interaction.Behaviors>
<Behaviors:ApplicationBarIconButtonCommand TextKey="Save"
CommandBinding="{Binding SaveEventSetupCommand}" />
<Behaviors:ApplicationBarIconButtonCommand TextKey="Cancel"
CommandBinding="{Binding CancelEventSetupCommand}" />
</i:Interaction.Behaviors>
For multi language support I need to add something like:
Text="{Binding Path=Localizedresources.lblCourse, Source={StaticResource LocalizedStrings}}"
to each button. It would appear that this cannot be done in xaml, hence the use of code.
The button is added in this code:
ApplicationBarIconButton appBarSaveButton = new ApplicationBarIconButton(
new Uri("/resources/icons/appbar.check.rest.png", UriKind.Relative))
{ Text = "Test" };
ApplicationBar.Buttons.Add(appBarSaveButton);
I just can't figure how to add the behavior. This is my start point:
WP7Contrib.View.Controls.Behaviors.ApplicationBarIconButtonCommand
ibc = new WP7Contrib.View.Controls.Behaviors.ApplicationBarIconButtonCommand
{ TextKey = "Test" };
Basically I am looking for a working sample if anyone can oblige.
Thanks
Based on Matt's answer this is my solution:
Add this at the top of the xaml page:
xmlns:Preview="clr-namespace:Phone7.Fx.Preview;assembly=Phone7.Fx.Preview"
and this inside the Grid at the bottom:
<Preview:BindableApplicationBar x:Name="AppBar" BarOpacity="1.0" IsVisible="{Binding IsBarVisible}" >
<Preview:BindableApplicationBarIconButton
Command="{Binding SaveCommand}"
Text="{Binding Path=Localizedresources.lblSave, Source={StaticResource LocalizedStrings}}"
IconUri="/resources/icons/appbar.check.rest.png" />
<Preview:BindableApplicationBarIconButton
Command="{Binding CancelCommand}"
Text="{Binding Path=Localizedresources.lblCancel, Source={StaticResource LocalizedStrings}}"
IconUri="/resources/icons/appbar.cancel.rest.png" />
</Preview:BindableApplicationBar>
References:
http://blog.humann.info/post/2010/08/27/How-to-have-binding-on-the-ApplicationBar.aspx
http://www.codeproject.com/KB/windows-phone-7/CommandToAppBarWP7.aspx?display=Mobile
You cannot specify the Text property of an ApplicationBarIconButton to a resource in XAML, which you've already worked out. To create a behavior and attached it in code you use code similar to the following (modified from an app I'm working on right now):
((ApplicationBarIconButton)this.ApplicationBar.Buttons[0].Text = Strings.NewContact;
var newBehavior = new ApplicationBarButtonNavigation
{
ButtonText = Strings.NewContact,
NavigateTo = new Uri("/views/ContactView.xaml", UriKind.RelativeOrAbsolute),
};
Interaction.GetBehaviors(this).Add(newBehavior);
The principal is the same for your scenario: create the behavior, and then use Interaction.GetBehaviors(this).Add(yourBehavior);
NOTE: In the above examples this refers to the code-behind for the view and is not in the view model.
You can definitely make the ApplicationBar bindable by using the wrapper from http://blog.humann.info/post/2010/08/27/How-to-have-binding-on-the-ApplicationBar.aspx
Not sure about adding commands but this shoudl be possible with the same technique.

Validating data entered on the form page : WPF

I have around 20 controls which are binded to different properties of a class along with validation rules like following. For sake of understanding i am writing the code for one control as other are same.
<TextBox Style="{StaticResource errorStyle}" Grid.Column="0" Grid.Row="2" Grid.RowSpan="1" HorizontalAlignment="Left" Margin="110,100,0,0" Name="balesText" VerticalAlignment="Top" Width="170" >
<TextBox.Text>
<Binding Source="{StaticResource insertTransaction}" UpdateSourceTrigger="Explicit" Path="Bales">
<Binding.ValidationRules>
<ExceptionValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Right now i am checking for the input errors in code-behind in the following manner
BindingExpression balesBe = balesText.GetBindingExpression(TextBox.TextProperty);
balesBe.UpdateSource();
.
.
if (balesBe.HasError)
{
MessageBox.Show("Please correct Errors", "Insert Aborted");
}
else
{
Binding insertTransactionBinding = BindingOperations.GetBinding(balesText, TextBox.TextProperty);
InsertTransaction insertTransaction = insertTransactionBinding.Source as InsertTransaction;
insertMessage = insertTransaction.Add();
MessageBox.Show(insertMessage, "Transaction");
this.NavigationService.Refresh();
}
Now, the Question is : Is there any way i can validate these 20 controls in one go or i need to manually define their BindingExpression and check for validation error??
Make your own UserControl "OwnTextBox". Inherit it from TextBox (OwnTextBox: TextBox) and define there DependencyProperty Validate. Then you only have to remember, that TextBox is part of logical tree and make search from it.

Resources