Silverlight Expander.Header with additional button - data-binding

When the Complete Survey button on the Expander.Header is clicked, I would like to Navigate to another page and pass along some information from the viewmodel. I have the expander working so that when its selected it expands, and the selecteditem property is properly bound and filled. However if I just click right to the button, the selecteditem does not change and is not even populated if its the first action. How can I trigger the selected item if the button control is pressed before the expander is selected? I would prefer an MVVM solution if possible. Thanks
<ListBox x:Name="SearchList"
Grid.Row="1"
Margin="5,0,5,0"
Grid.Column="0"
Background="Transparent"
BorderThickness="0"
BorderBrush="Transparent"
ItemsSource="{Binding Path=SearchResults}"
SelectedItem="{Binding Path=SelectedResult,Mode=TwoWay,Converter={StaticResource DebugConverter}}"
HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:Expander>
<sb:BindingHelper.Binding>
<sb:RelativeSourceBinding TargetProperty="IsExpanded"
Path="IsSelected"
RelativeMode="FindAncestor"
AncestorType="ListBoxItem" BindingMode="TwoWay" />
</sb:BindingHelper.Binding>
<toolkit:Expander.Header>
<Grid Width="525">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="25" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0"
Grid.Row="0"
Text="{Binding Path=PatientName}" />
<Button Grid.Column="2"
Grid.Row="0"
Content="Complete Survey">
<sb:BindingHelper.Binding>
<sb:RelativeSourceBinding Path="OpenSurveyCommand"
TargetProperty="Command"
RelativeMode="ParentDataContext" />
</sb:BindingHelper.Binding>
</Button>
</Grid>
</toolkit:Expander.Header>
<StackPanel>
<TextBlock Text="{Binding MRN,Converter={StaticResource StringLabelConverter},ConverterParameter=MRN}" />
<TextBlock Text="{Binding OriginalVisitNumber,Converter={StaticResource StringLabelConverter},ConverterParameter='Original Visit Number'}" />
<TextBlock Text="{Binding OriginalAdmitDate,Converter={StaticResource StringLabelConverter},ConverterParameter='Original Admit Date'}" />
<TextBlock Text="{Binding OriginalReason,Converter={StaticResource StringLabelConverter},ConverterParameter='Original Reason'}" />
<TextBlock Text="{Binding ReAdmitVisitNumber,Converter={StaticResource StringLabelConverter},ConverterParameter='ReAdmit Visit Number'}" />
<TextBlock Text="{Binding ReAdmitDate,Converter={StaticResource StringLabelConverter},ConverterParameter='Readmit Date'}" />
<TextBlock Text="{Binding ReAdmitReason,Converter={StaticResource StringLabelConverter},ConverterParameter='ReAdmit Reason'}" />
</StackPanel>
</toolkit:Expander>
</DataTemplate>
</ListBox.ItemTemplate>

I'm not familiar with the BindingHelper class you're using but if it's using the standard commanding in the background then I'd bind the command parameter to the "item".
That way you have access to the bound item in the commands executed event.

Using a collection of viewmodels with the button in the viewmodel solved this. No special magic other than the ObservableCollectionVM

Related

Need direction for best way to minimize data template code in Xamarin form

In MVC ASP.net Core, I used partials to re-use blocks of a page. In Xamarin, we have DataTemplates & ControlTemplates but I'm not sure how to best use them.
In one of my pages I have the following for the content:
<StackLayout>
<Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
<Label Text="Welcome to data template selector" HorizontalTextAlignment="Center" TextColor="White" FontSize="36"/>
</Frame>
<CollectionView ItemsSource="{Binding MainPageView.Fields}"
EmptyView="No fields for this screen."
ItemTemplate="{StaticResource templateSelector}"
SelectionChanged="CollectionView_SelectionChanged">
</CollectionView>
<StackLayout Margin="10,0,10,5" Orientation="Vertical">
<Button Command="{Binding MainPageView.SubmitCommand}" Text="Submit" />
<validator:ErrorSummaryView
IsVisible="{Binding MainPageView.ShowValidationSummary, Mode=OneWay}"
ErrorStateManager="{Binding MainPageView.ErrorStateManager, Mode=OneWay}"
Margin="0,0,0,5"/>
</StackLayout>
</StackLayout>
The template selector is (there will be more choices later):
<tempcel:FieldDataTemplateSelector
x:Key="templateSelector"
RadioTemplate="{StaticResource RadioTemplate}"
DropListTemplate="{StaticResource DropListTemplate}">
</tempcel:FieldDataTemplateSelector>
Where I could use some direction is right now 80% of what is in RadioTemplate and DropListTemplate are the same and I'd like to pull the shared code out so if I want to change the base layout, I only need to change one place. Here are the two DataTemplates:
<DataTemplate x:Key="DropListTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout
Orientation="Horizontal"
Grid.Row="0">
<Label
Text="{Binding Name}"
Style="{StaticResource LabelStyle}">
</Label>
<ImageButton HorizontalOptions="Center"
CornerRadius="6"
VerticalOptions="Center"
Clicked="HelpButton_Clicked"
HeightRequest="12"
WidthRequest="12"
BorderColor="Black"
BackgroundColor="Black"
BorderWidth="1"
IsVisible="{Binding ShowHelpButton}">
<ImageButton.Source>
<FontImageSource FontFamily="FAFreeSolid"
Color="White"
Glyph="{x:Static fa:FontAwesomeIcons.Question}"/>
</ImageButton.Source>
</ImageButton>
</StackLayout>
<Label
Grid.Row="1"
Style="{StaticResource HelpStyle}"
Text="{Binding HelpTopic.Text}"
IsVisible="{Binding HelpTopic.IsVisible, Mode=TwoWay}">
</Label>
<Picker
Grid.Row="2"
IsEnabled="{Binding IsEnabled}"
Margin="10,2,10,0"
ItemsSource="{Binding Choices.Choices}"
SelectedItem="{Binding SelectedChoice}"
ItemDisplayBinding="{Binding Label}"
SelectedIndexChanged="Picker_SelectedIndexChanged">
</Picker>
<validator:ErrorView ErrorState="{Binding ErrorStatemanager[Input]}" Grid.Row="3" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="RadioTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout
Orientation="Horizontal"
Grid.Row="0">
<Label
Text="{Binding Name}"
Style="{StaticResource LabelStyle}">
</Label>
<ImageButton HorizontalOptions="Center"
CornerRadius="6"
VerticalOptions="Center"
Clicked="HelpButton_Clicked"
HeightRequest="12"
WidthRequest="12"
BorderColor="Black"
BackgroundColor="Black"
BorderWidth="1"
IsVisible="{Binding ShowHelpButton}">
<ImageButton.Source>
<FontImageSource FontFamily="FAFreeSolid"
Color="White"
Glyph="{x:Static fa:FontAwesomeIcons.Question}"/>
</ImageButton.Source>
</ImageButton>
</StackLayout>
<Label
Grid.Row="1"
Style="{StaticResource HelpStyle}"
Text="{Binding HelpTopic.Text}"
IsVisible="{Binding HelpTopic.IsVisible, Mode=TwoWay}">
</Label>
<StackLayout
Grid.Row="2"
RadioButtonGroup.GroupName="{Binding Choices.Code}"
RadioButtonGroup.SelectedValue="{Binding Value}"
BindableLayout.ItemsSource="{Binding Choices.Choices}"
BindableLayout.EmptyView="No choices available"
Orientation="Horizontal"
Spacing="50"
Margin="10,2,0,0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<RadioButton Value="{Binding Value}"
Content="{Binding Label}"
IsChecked="{Binding IsSelected}"
CheckedChanged="OnRadioChanged">
</RadioButton>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<validator:ErrorView ErrorState="{Binding ErrorStatemanager[Input]}" Grid.Row="3" />
</Grid>
</DataTemplate>
I haven't figured out enough about Xamarin to know if I need to change where I have the CollectionView to put something there that has the common layout information with a way to put the different editors in. Or, if there is a way to modify the DataTemplates to get their base layout from something else. I tried looking at ContentPresenter but couldn't figure out how it would fit in.
Thanks
I found there is very little difference between DropListTemplate and RadioTemplate. So you can also achieve this without DropListTemplate and RadioTemplate .
You can display and hide the two views (Picker and BindableLayout) based on the item data of the CollectionView 's ItemsSource.
The following are the difference in the two Templates:
<Picker
Grid.Row="2"
IsEnabled="{Binding IsEnabled}"
Margin="10,2,10,0"
ItemsSource="{Binding Choices.Choices}"
SelectedItem="{Binding SelectedChoice}"
ItemDisplayBinding="{Binding Label}"
SelectedIndexChanged="Picker_SelectedIndexChanged">
</Picker>
and
<StackLayout
Grid.Row="2"
RadioButtonGroup.GroupName="{Binding Choices.Code}"
RadioButtonGroup.SelectedValue="{Binding Value}"
BindableLayout.ItemsSource="{Binding Choices.Choices}"
BindableLayout.EmptyView="No choices available"
Orientation="Horizontal"
Spacing="50"
Margin="10,2,0,0">
<BindableLayout.ItemTemplate>
<DataTemplate>
<RadioButton Value="{Binding Value}"
Content="{Binding Label}"
IsChecked="{Binding IsSelected}"
CheckedChanged="OnRadioChanged">
</RadioButton>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>

Binding to a property in ControlTemplate does not work

I have a mobile app with Xamarin.Forms and FreshMvvm. Every page uses a control template defined in App.xaml:
<ControlTemplate x:Key="MainPageTemplate">
<Grid BindingContext="{Binding Source={RelativeSource TemplatedParent}}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="9*" />
</Grid.RowDefinitions>
<Image Source="{local:ImageResource MyApp.Images.My_logo.jpg}" Margin="0, 0, 0, 5" Grid.Row="0" />
<Label Text="{Binding ScreenName}" FontSize="Subtitle" TextColor="Black" FontAttributes="Bold" HorizontalOptions="Center" Grid.Row="1" />
<Label Text="{Binding ErrorMessage}" TextColor="Red" Grid.Row="2" />
<ContentPresenter Margin="10, 0, 10, 10" Grid.Row="3" />
</Grid>
</ControlTemplate>
The ScreenName property is defined in the PageModel like this:
protected string _screenName;
public string ScreenName => _screenName;
For some reason, the ScreenName is not showing up on the page that uses the control template. It does if I replace the Binding with a hard-coded text:
<Label Text="Something" ...
When setting your BindingContext to your {RelativeSource TemplatedParent}, your binding context is the page.
To access your ViewModel, you must change your xaml to access your property through the "BindingContext" of your page.
<Label Text="{Binding BindingContext.ScreenName}" FontSize="Subtitle" TextColor="Black" FontAttributes="Bold" HorizontalOptions="Center" Grid.Row="1" />

Xamarin.Forms stepper is showing only minus button on android

This only shows minus option on the stepper. Why the plus option is not visible? The stepper works just fine on iOS.
<Entry Text="{Binding Path=Quantity, Mode=TwoWay}" Grid.Column="1" Grid.Row="1"></Entry>
<Stepper Value="{Binding Path=Quantity, Mode=TwoWay}"
Grid.Column="2"
Grid.Row="1"
MinimumWidthRequest="200"></Stepper>
I have tried shared code in my Grid , it works .
<Grid VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="400" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Entry Text="{Binding Path=Quantity, Mode=TwoWay}"
Grid.Column="0"
Grid.Row="0"></Entry>
<Stepper Value="{Binding Path=Quantity, Mode=TwoWay}"
Grid.Column="1"
Grid.Row="0"
MinimumWidthRequest="200"></Stepper>
<BoxView Grid.Row="1"
Grid.Column="0"
BackgroundColor="Red" />
<Button Grid.Row="2"
Grid.Column="0"
BackgroundColor="Yellow"
Clicked="Button_Clicked" />
</Grid>
The effects :
If you have a doubt about MinimumWidthRequest , it can be affected by Layout . If using it in StackLayout , then it will work , however in Grid can not .
<StackLayout Orientation="Horizontal" VerticalOptions="Start">
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<Entry Text="{Binding Path=Quantity, Mode=TwoWay}" Placeholder="123456789" MinimumWidthRequest="5"
></Entry>
<Stepper Value="{Binding Path=Quantity, Mode=TwoWay}"
MinimumWidthRequest="1"></Stepper>
</StackLayout>
The effects :
In addition , from Remarks of MinimumWidthRequest :
This causes overflow handling to shrink this element to its minimum width before elements who do not have a minimum size set.
I think it just be used to shrink the element , if the element not be supported the limit size , then it will not work .Here Stepper is not recommended for using MinimumWidthRequest. If works, it will cause it to appear asymmetric.

issue with Xamarin form grid inside Stacklayout

I am working on Xamarin forms Where i need to display grid. I am using StackLayout to create form. Everything is working until I add Grid inside StackLayout ., then I am getting error that Timeout exceeded getting exception details
Here is my code :
<ContentPage.Content>
<StackLayout VerticalOptions="StartAndExpand" BackgroundColor="White">
<StackLayout Padding="20,40,20,0" HorizontalOptions="CenterAndExpand">
<Image Source="logo.png" Aspect="AspectFit" HorizontalOptions="Center"></Image>
</StackLayout>
<StackLayout Padding="15,20,15,0" VerticalOptions="Center">
<local:ImageEntry TextColor="#98a4b4"
PlaceholderColor="#98a4b4" FontFamily="ProximaNova"
Image="LoginEmailIcon"
Placeholder="Email"
HorizontalOptions="FillAndExpand"
ImageWidth="25"
ImageHeight="20"
LineColor="#98a4b4"/>
<local:ImageEntry TextColor="#98a4b4"
PlaceholderColor="#98a4b4" FontFamily="ProximaNova"
Image="LoginPasswordIcon"
Placeholder="Password"
HorizontalOptions="FillAndExpand"
ImageWidth="23"
ImageHeight="25"
LineColor="#98a4b4" IsPassword="True"/>
<Label Text=" Forgot your password?"
HorizontalOptions="StartAndExpand" FontFamily="ProximaNova"
TextColor="#bcbcbc"/>
<StackLayout Orientation="Horizontal">
<Button x:Name="ButtonSignin" BackgroundColor="#29abdf" TextColor="White" HorizontalOptions="FillAndExpand" FontFamily="ProximaNova" Text="Sign in" FontAttributes="Bold"/>
</StackLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="CenterAndExpand">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25px" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Image Source="loginsideicon.png" Grid.Row="0" Grid.Column="0"></Image>
<Label Text="OR" Grid.Row="0" Grid.Column="1" FontFamily="ProximaNova" TextColor="#bcbcbc"></Label>
<Image Source="loginsideicon.png" Grid.Row="0" Grid.Column="2"></Image>
</Grid>
</StackLayout>
</StackLayout>
</StackLayout>
</ContentPage.Content>
Now When I run this code I am getting exception:
Unhandled Exception:
System.FormatException: <Timeout exceeded getting exception details> occurred
But when i comment Grid code everything is working
I noticed a few issues with your xaml :
-Use a capital letter for Auto
<ColumnDefinition Width="Auto" />
-We do not use 25px with xaml
<RowDefinition Height="25" />

WP7 Using binding how can I manage data relevant on prior items

When I am binding to a collection with a listbox, is there any way I can manage the output based upon the prior items that were displayed in the collection.
For example in the following binding
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="AgendaListbox"
ItemsSource="{Binding AgendaItems2}"
ItemTemplate="{StaticResource EventDisplay3}"/>
</Grid>
Where the Template is as follows
<DataTemplate x:Key="EventDisplay3">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="10"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding DateTimeDayString}" Style="{StaticResource PhoneTextSmallStyle}"
Grid.Row="0" Grid.Column="0"/>
<TextBlock Text="{Binding DisplayTimeString}" Foreground="{Binding DisplayColor}"
Grid.Row="1" Grid.Column="0" Style="{StaticResource PhoneTextLargeStyle}"/>
<TextBlock Text="{Binding Details}" TextWrapping="Wrap" Style="{StaticResource PhoneTextNormalStyle}"
Grid.Row="0" FontSize="30" Grid.Column="2" Grid.RowSpan="3"
VerticalAlignment="Center" />
<TextBlock Text="{Binding Location}" Style="{StaticResource PhoneTextSmallStyle}"
Grid.Row="3" Grid.Column="0"/>
</Grid>
</DataTemplate>
If I want to alter the display based upon they previous item that was displayed (e.g say I want to drop the DateTimeString Binding if its identical to the previous one) is there a way that I can do it without having to make specific allowance for it when I build up the collecton.
Because so much happens automatically as it were with the listbox being bound to that collection I cannot see any other way without me handling this as the collection is being built... because after that I have little control.
Thanks
Is there any way I can manage the output based upon the prior items that were displayed in the collection?
No.
You have to do such changes when you build the collection. Consider if using a DataTemplateSelector can be of any help.

Resources