I display a list of fullname of Member and when I select a member, it will go to the detail page. I edit info directly in the textbox and then click Save in application bar but the info is not changed as I edited...it still remains the old value
Plz help me!
I have the List name of member like this
<ListBox x:Name="Listmember" Height="500" SelectionChanged="Listmember_SelectionChanged" ItemsSource="{Binding Data}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="466" Margin="0, 0, 0, 12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0"></Grid>
<StackPanel Grid.Column="1" >
<TextBlock FontSize="40" Text="{Binding FullName}" Foreground="#FFEA0909" FontWeight="Normal" FontStyle="Normal" Style="{StaticResource PhoneTextTitle3Style}" TextWrapping="Wrap"/>
</StackPanel>
<Grid Grid.Column="2">
<Button x:Name="Deletebutton" Height="60" Width="60" Click="deleteButton_Click" BorderBrush="{StaticResource TransparentBrush}">
<Image Source="/Assets/delete.dark.png" Visibility="{StaticResource PhoneDarkThemeVisibility}" Margin="-24"/>
</Button>
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and the SelectionChanged is:
private void Listmember_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If no customer is selected, just return
if (Listmember.SelectedItem == null) return;
// Get the parent application that contains the customer being edited
App thisApp = Application.Current as App;
// Set this to the selected customer
thisApp.SelectedMember = Listmember.SelectedItem as Member;
// Navigate to the detail page
NavigationService.Navigate(new Uri("/View/MemberDetail.xaml", UriKind.RelativeOrAbsolute));
}
In the MemberDetails.xaml which is navigated to:
<Grid Name="ListDetails" Grid.Row="0">
<TextBlock Grid.Row="0" Name="fn" Text="FullName" FontSize="30" VerticalAlignment="Bottom"/>
<TextBox Grid.Row="1" Name="fullnameTextBox" Text="{Binding FullName, Mode=TwoWay}" TextWrapping="Wrap"/>
<TextBlock Grid.Row="2" Name="ad" Text="Address" FontSize="30" VerticalAlignment="Bottom"/>
<TextBox Grid.Row="3" Name="addressTextBox" Text="{Binding Address, Mode=TwoWay}" TextWrapping="Wrap" />
</Grid>
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
<shell:ApplicationBarIconButton
IconUri="/Images/save.png"
Text="Save"
x:Name="SaveButton"
Click="Save_Click"/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
and the code behind
public MemberDetail()
{
InitializeComponent();
this.DataContext = App.MainViewModel;
}
ViewDetails view = new ViewDetails();
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Get the parent application that contains the active custom
App thisApp = Application.Current as App;
// Load the active customer into the viewmodel
view.LoadDetails(thisApp.SelectedMember);
// Set the data context to the viewmodel
ListDetails.DataContext = view;
}
private void Save_Click(object sender, EventArgs e)
{
App thisApp = Application.Current as App;
view.UpdateDetails(thisApp.SelectedMember);
// Go back to the previous page
NavigationService.GoBack();
}
and class ViewDetails in ViewModel:
public class ViewDetails : INotifyPropertyChanged
{
private string _fullname;
public string FullName
{
get
{
return _fullname;
}
set
{
_fullname = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Fullname"));
}
}
}
private string _address;
public string Address
{
get
{
return _address;
}
set
{
_address = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Address"));
}
}
}
public void UpdateDetails(Member abc)
{
abc.FullName = FullName;
abc.Address = Address;
}
public void LoadDetails(Member abc)
{
FullName = abc.FullName;
Address = abc.Address;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
// Used to notify the app that a property has changed.
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
TextBox in Binding Mode Twoway will not update the source until lost focus happens.
If you try to press button, you will find that pressing a button will trigger LostFocus event of text box so the The data will be updated and will be in the correct state before you execute the code in your button.
And if you try to press ApplicationBarIconButton you will find that LostFocus didn't fire. So the data will not be updated and will be in old state.
Now how can we overcome this?
Simple you can do one of the following solutions which update source each time text changes
Using Explicit Binding Combined with OnTextChanged from this question
Explicit: Updates the binding source only when you call the UpdateSource method. It saves you one extra binding set when the user leaves the TextBox.
in xaml
<TextBox TextChanged="OnTextBoxTextChanged" Text="{Binding MyText, Mode=TwoWay, UpdateSourceTrigger=Explicit}" />
in C#
private void OnTextBoxTextChanged( object sender, TextChangedEventArgs e )
{
TextBox textBox = sender as TextBox;
// Update the binding source
BindingExpression bindingExpr = textBox.GetBindingExpression( TextBox.TextProperty );
bindingExpr.UpdateSource();
}
You can use behavior like the one from this link which listens to TextChanged event and updates the source. I prefer this solution as it is easy to add to your textbox without adding more lines to code behind. All you need to do is to add this lines to your textbox.
<TextBox x:Name="tbx" Text="{Binding Name, Mode=TwoWay}">
<i:Interaction.Behaviors>
<local:UpdateSourceOnTextChangedBehavior />
</i:Interaction.Behaviors>
</TextBox>
Don't forget to reference System.Windows.Interactivity also add these namespaces to your page namespace definitions
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="name space of the behavior"