I have a TabControl that is data bound to a list. (Two data items in the list) The TabControl has a DataTemplate which contains two TextBox controls bound to two string properties on my data class.
If I type some text on Textbox1 on the first tab and then click onto Tab2, no update is made to the data source and the change is lost.
This is because LostFocus is not actually fired for TextBox1 (it is on TextBox2 because moving to Tab 2 automatically focuses TextBox1) and I believe this is due to each tab sharing the same TextBoxes from the template and just changing the DataContext on tab switches.
Two events may help here: PreviewLostKeyboardFocus and DataContextChanged Both still have the typed text on the TextBox available.
There is also the age-old problem of a toolbar Save button which doesn't get focus.
It seems to me that maybe the Binding class should be listening to PreviousLostKeyboardFocus rather than LostFocus which seems to fire in both the above scenarios.
How do you guys solve these issues?
Aos, what ways are available to harness the PreviewLostKeyboardFocus event to Update Source? (I'm thinking something along the lines of a top level container watches this event, checks if there is a Binding on the OriginalSource with a LostFocus UpdateSourceTrigger and tricks/forces the binding to update the source - but I'm new to Wpf and there might be other considerations I haven't thought about)
Here is a sample app...
<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 its codebehind
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;
}
}
}