I have a TabControl tied to a list. (Two data items in the list) TabControl has a DataTemplate that contains two TextBox controls bound to two row properties in my data class.
If I type text on Textbox1 in the first tab and then on Tab2, the update will not be made to the data source and the change will be lost.
This is due to the fact that LostFocus does not actually start for TextBox1 (it is in TextBox2, because switching to Tab 2 automatically focuses TextBox1), and I believe that this is due to the fact that each tab uses the same text fields from template and just changes the DataContext tab tabs.
Two events can help here: PreviewLostKeyboardFocus and DataContextChanged. Both users have typed text in an accessible text field.
There is also an old problem with the Save toolbar button that does not receive focus.
It seems to me that perhaps the Binding class should listen to PreviousLostKeyboardFocus, not LostFocus, which seems to work in both of the above scenarios.
How do you solve these problems?
Aos, what are the ways to use the PreviewLostKeyboardFocus event to update the source? (I think something like a top-level container is watching this event, checking if there is a binding to SourceSource using LostFocus UpdateSourceTrigger and tricks / forced binding to update the source, but I'm new to Wpf and there may be other considerations about which I did not think)
Here is an example application ...
<Window x:Class="BindingFocusTabIssue.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="398" Width="731" > <Grid> <TabControl Height="267" HorizontalAlignment="Left" Margin="31,36,0,0" Name="tabControl1" VerticalAlignment="Top" Width="472" ItemsSource="{Binding}"> <TabControl.ContentTemplate> <DataTemplate> <StackPanel> <TextBox Margin="3" Name="TextBox1" Text="{Binding Text1}" GotFocus="TextBox_GotFocus" LostFocus="TextBox_LostFocus" PreviewLostKeyboardFocus="TextBox_PreviewLostKeyboardFocus" DataContextChanged="TextBox_DataContextChanged"/> <TextBox Margin="3" Name="TextBox2" Text="{Binding Text2}" GotFocus="TextBox_GotFocus" LostFocus="TextBox_LostFocus" PreviewLostKeyboardFocus="TextBox_PreviewLostKeyboardFocus" DataContextChanged="TextBox_DataContextChanged"/> </StackPanel> </DataTemplate> </TabControl.ContentTemplate> </TabControl> <GroupBox Header="List item 1" Height="115" HorizontalAlignment="Left" Margin="509,50,0,0" Name="groupBox1" VerticalAlignment="Top" Width="188"> <Grid > <TextBox Height="23" HorizontalAlignment="Left" Margin="28,21,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=[0].Text1}" /> <TextBox Height="23" HorizontalAlignment="Left" Margin="28,50,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Text="{Binding Path=[0].Text2}"/> </Grid> </GroupBox> <GroupBox Header="List item 2" Height="115" HorizontalAlignment="Left" Margin="509,184,0,0" Name="groupBox2" VerticalAlignment="Top" Width="188"> <Grid> <TextBox Height="23" HorizontalAlignment="Left" Margin="28,21,0,0" Name="textBox3" VerticalAlignment="Top" Width="120" Text="{Binding Path=[1].Text1}" /> <TextBox Height="23" HorizontalAlignment="Left" Margin="28,50,0,0" Name="textBox4" VerticalAlignment="Top" Width="120" Text="{Binding Path=[1].Text2}"/> </Grid> </GroupBox> <ToolBar Height="26" HorizontalAlignment="Left" Margin="54,3,0,0" Name="toolBar1" VerticalAlignment="Top" Width="200"> <Button>Save</Button> </ToolBar> </Grid>
and his code
using System;
using System.Collections.Generic; using System.Diagnostics; using System.Windows; using System.Windows.Controls; using System.Windows.Input;
namespace BindingFocusTabIssue {public partial class MainWindow: Window {public MainWindow () {InitializeComponent ();
DataContext = new List<DataClass> { new DataClass { Name="One"}, new DataClass { Name="Two"}, }; } private void TextBox_GotFocus(object sender, RoutedEventArgs e) { var textBox = (TextBox) e.Source; Debug.WriteLine(textBox.Name + "_GotFocus and Text='" + textBox.Text + "'"); } private void TextBox_LostFocus(object sender, RoutedEventArgs e) { var textBox = (TextBox) e.Source; Debug.WriteLine(textBox.Name + "_LostFocus and Text='" + textBox.Text + "'"); } private void TextBox_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { var textBox = (TextBox) e.Source; Debug.WriteLine(textBox.Name + "_PreviewLostKeyboardFocus and Text='" + textBox.Text + "'"); } private void TextBox_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { var textBox = (TextBox) sender; Debug.WriteLine(textBox.Name + "_DataContextChanged and Text='" + textBox.Text + "'"); } } public class DataClass { public string Name { get; set; } public string Text1 { get; set; } public string Text2 { get; set; } public override string ToString() { return Name; } }
}