uwp twoway binding not updating UI - xaml

I have the following XAML code, where I have a TextBox for user input (phone number) and GridView for user contacts.
<GridView x:Name="ContactsCollection" Grid.Row="1" Style="{StaticResource DefaultGridView}" IsItemClickEnabled="True" ItemsSource="{Binding UserContacts}" ItemTemplate="{StaticResource HorizontalGridViewDataTemplate}" ItemContainerStyle="{StaticResource DefaultGridViewItemContainer}">
<i:Interaction.Behaviors>
<c:EventTriggerBehavior EventName="SelectionChanged">
<c:InvokeCommandAction Command="{Binding SelectContactCommand}" CommandParameter="{Binding SelectedItem, ElementName=ContactsCollection}"/>
</c:EventTriggerBehavior>
</i:Interaction.Behaviors>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
And my TextBox that is binded to the Recipient in the ViewModel.
<TextBox x:Uid="Recipient" Text="{Binding Recipient, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" PreventKeyboardDisplayOnProgrammaticFocus="True" toolkitControls:TextBoxMask.Mask="7(999)999-99-99" toolkitControls:TextBoxMask.PlaceHolder="X" InputScope="NumericPin" HeaderTemplate="{StaticResource UiControlHeaderDataTemplate}" Style="{StaticResource DefaultTextBoxStyle}"/>
Here goes code from the ViewModel.
public string Recipient
{
get { return _recipient; }
set
{
if (value != _recipient)
{
_recipient = value;
RaisePropertyChanged(nameof(Recipient));
ContinueTransferCommand.RaiseCanExecuteChanged();
}
}
}
Now, when I click any contact from the GridView the following functions is called, that assign contact's phone number to the Recipient property.
private void SelectContactCommandAction(object contact)
{
Contact c = contact as Contact;
if (c.Phones?.Count > 0)
Recipient = FormatDataHelper.FormatPhoneNumber(c.Phones.FirstOrDefault().Number);
}
When I click any contact for the FIRST time, the Recipient property is updated, and the UI is updated too. But, if I select other contact, in the debug mode I can see, that Recipient property is updated and saved new value, but the UI (TextBox) is not updated at all. The only way it works, I have to delete any character from the TextBox and select a contact again, in that case UI value will be updated again.
Can somebody please explain this?

Related

TargetNullValue not working in ListView in Xamarin app

I'm trying to display some text -- or an image -- if there's no data for my ListView to display in my Xamarin Forms 5 app but I can't get it to work.
Here's what my ListView looks like:
<ListView
x:Name="CustomersList"
ItemsSource="{Binding Customers, TargetNullValue='No customers!'}"
BackgroundColor="Transparent">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell
Text="{Binding FullName}"
TextColor="{StaticResource PrimaryDark}"
Command="{Binding Source={x:Reference Name=CustomersList}, Path=BindingContext.CustomerSelectedCommand}"
CommandParameter="{Binding .}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The source for the ListView is set as follows in my ViewModel
ObservableRangeCollection<CustomerModel> customers;
public ObservableRangeCollection<CustomerModel> Customers
{
get => customers;
set
{
if (customers == value)
return;
customers = value;
OnPropertyChanged();
}
}
If my API call returns nothing, I do a Customers = null;
When I use TargetNullValue as shown above, I acutally get errors where I bind the TextCell to FullName. It shows:
'FullName' property not found on 'N', target property:
'Xamarin.Forms.TextCell.Text'
It then repeats this error message for every character in No Customers!.
I then tried using FallbackValue. This time I don't get an error but it simply doesn't show the "No Customers!" message.
How do I handle a ListView having no data to show? At the very least, I'd like to show some simple text message but it would be even better to show something nicer, maybe an image.
If you are ok to switch from ListView to CollectionView, you can use the built-in CollectionView.EmptyView:
<CollectionView ItemsSource="{Binding Customers}"
EmptyView="No customers!" ... />
With the same EmptyView you can define whatever view:
<CollectionView>
<CollectionView.EmptyView>
<ContentView>
<image ... />
</ContentView>
</CollectionView.EmptyView>
</CollectionView>
Docs: CollectionView EmptyView

How to add autocomplete functionality for Listpicker in windows phone 8?

Hi I'm developing wp8 application .
I'm using List picker for bind city names.Below it's my code for list Picker
XAML
<toolkit:ListPicker x:Name="Lpcity" Foreground="White" BorderThickness="0" VerticalAlignment="Top" Margin="400,10,0,0" Height="80" Width="50" Visibility="Visible" SelectionChanged="Lpcity_SelectionChanged">
<toolkit:ListPicker.Background>
<ImageBrush ImageSource="/Assets/Images/search.png"/>
</toolkit:ListPicker.Background>
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding cityname}" Visibility="Collapsed" Foreground="Red"/>
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
<toolkit:ListPicker.FullModeItemTemplate>
<DataTemplate>
<TextBlock FontSize="30">
<Run Text="{Binding cityname}"/>
</TextBlock>
</DataTemplate>
</toolkit:ListPicker.FullModeItemTemplate>
</toolkit:ListPicker>
C#
public void Citybind()
{
string city_nameurl = "http://xxxx.yyyyy";
WebClient city_namewc = new WebClient();
city_namewc.DownloadStringAsync(new Uri(city_nameurl), UriKind.Relative);
city_namewc.DownloadStringCompleted += city_namewc_DownloadStringCompleted;
}
void city_namewc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
var city_name = e.Result;
city_namedata add = new city_namedata();
add.id = "-1";
add.cityname = "Select any one city";
add.id = "0";
add.cityname = "Remove city based search";
var city_nameval = JsonConvert.DeserializeObject<List<city_namedata>>(city_name);
city_nameval.Insert(0, add);
Lpcity.ItemsSource = city_nameval;
}
OutPut:
Now nearly 200 and more city name is bind in List picker. If user wan to select city name start with z. now he need to scroll to the bottom of the screen.
So i need to add the auto complete functionality . If user type z all z related name should show to user.
I searched in web and find out autocomplete box functionality.I try with following code for autocomplete box
XAML
<toolkit:AutoCompleteBox HorizontalAlignment="Left"
Width="450"
Grid.Row="0"
Name="autoCompleteBox1"
VerticalAlignment="Top"
InputScope="Digits"
ItemsSource="{StaticResource AutoCompletions}"
/>
Now i need to know it's possible to add both list picker and autocomplete box?
Other wise any other option available for my requirement?
Thank you

Windows Store App binding of CheckBox does not work (occassionally)

I have the following piece of XAML:
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Background="#286C9A" Width="336" Height="22">
<TextBlock Text="{Binding Checked}" Foreground="Black" HorizontalAlignment="Left"/>
<CheckBox IsChecked="{Binding Checked}" HorizontalAlignment="Right" />
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
It's a template in a ListView. Checked is a bool property, and the problem is that the initial value of the property is transferred correctly to the view (both TextBlock and CheckBox). But following changes to the property is only reflected on the TextBlock, the Checkbox does not react.
Can someone tell me what happens?
EDIT:
The relevant part (I believe) of the ViewModel is this :
public class MenuGroup : ObservableCollection<MenuItem>
{
bool #checked;
public bool Checked
{
get { return #checked; }
set
{
if (#checked == value) return;
#checked = value;
OnPropertyChanged(new PropertyChangedEventArgs("Checked"));
}
}
}
EDIT: It is apparent that the binding stops working the first time I have clicked on the checkbox and thus manually changed it's state. And it works all the way if it's TwoWay binding. But why that is, I don't know.

How to attach EventTrigger in code behind in Silverlight 4

My question is the following:
I have a grid and I attached the SelectedIndexChanged event the following way in the xaml file:
"<cc:DetailViewGrid AutoGenerateColumns="False" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="dgAcitivityList" VerticalAlignment="Stretch" ItemsSource="{Binding EntityList}" SelectionMode="Single" IsReadOnly="False">
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="SelectionChanged">
<interactivity:InvokeCommandAction Command="{Binding SelectedItemChangeCommand}" CommandParameter="{Binding SelectedItem, ElementName=dgAcitivityList}"/>
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>"
But I want to attach this event in code behind. I ctreated an own grid that is inherited from windows grid, and I put this code to own control.
public override void OnApplyTemplate()
{
//base.OnApplyTemplate();
System.Windows.Interactivity.EventTrigger selectedItemChangedTrigger = new System.Windows.Interactivity.EventTrigger("SelectionChanged");
System.Windows.Interactivity.InvokeCommandAction action = new System.Windows.Interactivity.InvokeCommandAction();
action.CommandName = "{Binding SelectedItemChangeCommand}";
action.CommandParameter = string.Format("{{Binding SelectedItem, ElementName={0}}}", this.Name);
selectedItemChangedTrigger.Actions.Add(action);
System.Windows.Interactivity.Interaction.GetTriggers(this).Add(selectedItemChangedTrigger);
base.OnApplyTemplate();
}
Is this solution proper? It's not working but I'm not sure that I should put this code in the OnApplyTemplate() method.

Why can't get validation error display in validationSummary?

I have a form with some validations set in entity metadata class. and then binding entity instance to UI by VM. Something as below:
Xaml like:
<Grid x:Name="LayoutRoot">
<StackPanel VerticalAlignment="Top">
<input:ValidationSummary />
</StackPanel>
<TextBox Text="{Binding Name, Mode=TwoWay}" />
<ComboBox x:Name="xTest" ItemsSource="{Binding MyList}"
SelectedItem="{Binding MyItem,Mode=TwoWay,
DisplayMemberPath="MyName"
ValidatesOnDataErrors=True,
ValidatesOnNotifyDataErrors=True,
ValidatesOnExceptions=True,
NotifyOnValidationError=True,UpdateSourceTrigger=Explicit}" />
</Grid>
Code-behind like:
public MyForm()
{
InitializeComponent();
this.xTest.BindingValidationError +=new EventHandler<ValidationErrorEventArgs>((s,e)=>{
BindingExpression be = this.xTest.GetBindingExpression(ComboBox.SelectedItemProperty);
be.UpdateSource();
if (e.Action == ValidationErrorEventAction.Added)
((ComboBox)s).Foreground = new SolidColorBrush(Colors.Red);
});
}
Metadata like:
[Required]
public string Name { get; set; }
[RequiredAttribute]
public int MyItemID { get; set; }
But when running the app, I got nothing display in valudationSummary.
For CombBox, even there is error, looks like BindingValidationError event is never fired.
How to resolve it?
Why are you using an Explicit UpdateSourceTrigger?
Silverlight validation happens inside the binding framework, when the binding is updating the source object. The way you have this, there won't be a binding validation error because you never tell the binding to update the source object. Well, actually you do, but it happens inside the validation error event handler. You've written chicken-and-egg code.
Remove your UpdateSourceTrigger on your binding or set it to Default.
Remove the explicit call to BindingExpression.UpdateSource.
Remove setting the ComboBox foreground to red - you are using NotifyOnValidationError=True, which eliminates any need to manually color the control.
Remove the DisplayMemberPath from the binding
So your XAML:
<Grid x:Name="LayoutRoot">
<StackPanel VerticalAlignment="Top">
<input:ValidationSummary />
<ComboBox x:Name="xTest" ItemsSource="{Binding MyList}"
SelectedItem="{Binding MyItem,
Mode=TwoWay,
ValidatesOnDataErrors=True,
ValidatesOnNotifyDataErrors=True,
ValidatesOnExceptions=True,
NotifyOnValidationError=True}" />
</StackPanel>
</Grid>
And your code:
public MyForm()
{
InitializeComponent();
// you don't need anything here to have the validations work
}