Reputation:
In my Application, there is a Picker and Button. I want two things.
Required to Select atleast one Item from Picker, else won't be able to click a Button. e.g. just like required Attribute in HTML
If the value is Provider 1, then Navigate to this Page, else if Provider 2, then navigate to this Page.
Code for Picker & Button in Views
<Picker x:Name="picker_provider"
Title="Select a Provider">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Provider 1</x:String>
<x:String>Provider 2</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
<Button
Text="Next"
Command="{Binding NextPageCommand}"/>
Code for Button Binding in ViewModel.cs
public async Task NextPage(RegisterViewModel nextpage) => await NavigationService.NavigateToAsync(nextpage, null, NavigationType.Modal);
#region Bindable Command
public ICommand NextPageCommand => new Command<RegisterViewModel>(async (nextpage) =>
{
await NextPage(nextpage);
});
#endregion
Upvotes: 3
Views: 898
Reputation: 15180
You can use a multi data trigger in your button to enable or disable it depending on the status of your picker selection properties.
Because you are binding to strings, you will need add a converter to test whether they are null or empty, for example:
namespace Osma.Mobile.App.Converters
{
public class StringNullOrEmptyValueBoolConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string str && !string.IsNullOrEmpty(str))
{
// String is not null or empty
return false;
}
// String is null or empty
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Add the required properties to your ViewModel
:
public class ProviderViewModel : ABaseViewModel
{
public ProviderViewModel(
IUserDialogs userDialogs,
INavigationService navigationService
) : base(
nameof(ProviderViewModel),
userDialogs,
navigationService)
{
}
public override async Task InitializeAsync(object navigationData)
{
await base.InitializeAsync(navigationData);
}
private string _selectedProvider;
public string SelectedProvider {
get { return _selectedProvider; }
set
{
this.RaiseAndSetIfChanged(ref _selectedProvider, value) }
}
}
private string _selectedCountry;
public string SelectedCountry {
get { return _selectedCountry; }
set
{
this.RaiseAndSetIfChanged(ref _selectedCountry, value) }
}
}
public async Task RegistrationPage(RegisterViewModel registration) => await NavigationService.NavigateToAsync(registration, null, NavigationType.Modal);
public ICommand RegistrationPageCommand => new Command<RegisterViewModel>(async (registration) =>
{
await RegistrationPage(registration);
}, (x) => false);
}
Add the converter namespace and resource to your page and implement the multitrigger and bindings:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converters="clr-namespace:Osma.Mobile.App.Converters"
x:Class="Osma.Mobile.App.Views.ProviderPage"
NavigationPage.HasNavigationBar="False"
BackgroundColor="#004B86">
<ContentPage.Resources>
<ResourceDictionary>
<converters:StringNullOrEmptyValueBoolConverter x:Key="stringNullOrEmptyValueBoolConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout
Spacing="30">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70" />
<RowDefinition Height="70" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Picker
x:Name="picker_country"
Title="Select a Country"
TextColor="Silver"
TitleColor="Silver"
HorizontalOptions="Start"
WidthRequest = "200"
VerticalOptions="Start"
Margin="130,0,0,0"
SelectedItem="{Binding SelectedCountry}">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Sweden</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
</Grid>
<Grid Grid.Row="1">
<Picker
x:Name="picker_provider"
Title="Select a Provider"
TextColor="Silver"
TitleColor="Silver"
HorizontalOptions="Start"
WidthRequest = "200"
VerticalOptions="Start"
Margin="130,0,0,0"
SelectedItem="{Binding SelectedProvider}">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Provider 1</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
</Grid>
</Grid>
<Button
BackgroundColor="#2194EF"
TextColor="White"
Text="Next"
HeightRequest="60"
MinimumHeightRequest="60"
IsEnabled="False"
Command="{Binding RegistrationPageCommand}">
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding SelectedCountry,
Converter={StaticResource stringNullOrEmptyValueBoolConverter }}" Value="false" />
<BindingCondition Binding="{Binding SelectedProvider,
Converter={StaticResource stringNullOrEmptyValueBoolConverter }}" Value="false" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiTrigger>
</Button.Triggers>
</Button>
</StackLayout>
</ContentPage.Content>
</ContentPage>
As you can see in the code the multrigger conditions are that both properties are not null or empty and when this is the case the button will be enabled.
Upvotes: 1
Reputation: 14475
Required to Select atleast one Item from Picker, else won't be able to click a Button. e.g. just like required Attribute in HTML
You could use DataTrigger
to determine when to set Button.Enable
.
<ContentPage.Resources>
<ResourceDictionary>
<local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Picker x:Name="picker_provider"
Title="Select a Provider" SelectedItem="{Binding xxx}">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Provider 1</x:String>
<x:String>Provider 2</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
<Button Text="Next" IsEnabled="False" Command="{}">
<Button.Triggers>
<DataTrigger
TargetType="Button"
Binding="{Binding Source={x:Reference picker_provider}, Path = SelectedIndex ,
Converter={StaticResource dataHasBeenEntered}}" Value="true">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
</Button.Triggers>
</Button>
</StackLayout>
public class MultiTriggerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if ((int)value >= 0) // length > 0 ?
return true; // some data has been entered
else
return false; // input is empty
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
If the value is Provider 1, then Navigate to this Page, else if Provider 2, then navigate to this Page
Create binding on Picker.SelectedItem
, and navigate to corresponding page according to the value .
public ICommand NextPageCommand => new Command<RegisterViewModel>(async (nextpage) =>
{
// here you could get the value of `Picker.SelectedItem`.
});
Upvotes: 0
Reputation: 15180
Add a flag in your view model such as:
private bool _canNavigate;
public bool CanNavigate
{
get { return _canNavigate; }
set { this.RaiseAndSetIfChanged(ref _canNavigate, value) }
}
Bind this property to the property "IsEnabled" of your button:
<Button
Text="Next"
IsEnabled="{Binding CanNavigate}"
Command="{Binding NextPageCommand}"/>
Then add a binding for the selected item as well and enabled the button when :
private string _selectedItem;
public string SelectedItem {
get { return _selectedItem; }
set
{
if (!string.IsNullOrWhiteSpace(value))
{
this.RaiseAndSetIfChanged(ref _selectedItem, value) }
}
}
}
And add the binding in your view:
<Picker x:Name="picker_provider"
Title="Select a Provider" SelectedItem="{Binding SelectedItem}">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Provider 1</x:String>
<x:String>Provider 2</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
There are other (perhaps) more elegant ways of doing this, for example using a MultiTrigger (see here) or a behavior to intercept the SelectedIndexChanged
event.
Upvotes: 0
Reputation: 11889
In your ViewModel have a property called IsNextButtonEnabled
that watches if an item has been selected. Also change your XAML, so that the button is enabled when IsNextButtonEnabled is true:
ViewModel:
public bool IsNextButtonEnabled => SelectedItem!=null;
public string SelectedItem
{
get=>_selectedItem;
set { _selectedItem = value; OnPropertyChanged("SelectedItem");}
}
private string _selectedItem;
Bear in mind the OnPropertyChanged function may be different depending on what (if any) libraries you use for your view models.
Xaml:
<Picker x:Name="picker_provider"
Title="Select a Provider"
SelectedItem="{Binding SelectedItem}>
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Provider 1</x:String>
<x:String>Provider 2</x:String>
</x:Array>
</Picker.ItemsSource>
public ICommand NextPageCommand => new Command<RegisterViewModel>(async (nextpage) =>
{
if(_selectedItem == "Provider 1") await ThisPage();
else await OtherPage();
});
Upvotes: 0