I have an ItemsControl with ItemsSource bound to an IEnumerable<MyDataItem>.
The ItemTemplate consists of two textboxes. (Friendly name & name). This is how it looks like: https://i.stack.imgur.com/Rg1dC.png
As soon as the "Friendly name" field is filled in, I add an empty row. I use the LostKeyboardFocus event to check whether to add an empty "MyDataItem" and refresh the IEnumerable<MyDataItem> property.
The problem: I loose the focus when adding an item. So if I tab from friendly name to name and a new row is added, the focus is lost from name. How can I solve this?
EDIT: Underneath some code to show my problem. I want to be able to TAB from cell to cell. When both cells of a row are left empty, I want to remove that line. At the end I want to have an empty row (both cells empty). At this point the code works, but loses focus if you use tab. And working with a listbox makes that TAB doesn't work to go to the next item in list.
XAML:
<Window x:Class="Focus.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Focus"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MainViewModel, IsDesignTimeCreatable=True}"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="DataTemplate1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="5"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBox LostKeyboardFocus="TextBox_LostKeyboardFocus">
<TextBox.Text>
<Binding Path="FriendlyName" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
<TextBox Grid.Column="2" LostKeyboardFocus="TextBox_LostKeyboardFocus">
<TextBox.Text>
<Binding Path="Name" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox Margin="10" ItemsSource="{Binding OrderedItems}" ItemTemplate="{DynamicResource DataTemplate1}" HorizontalContentAlignment="Stretch">
</ListBox>
</Grid>
Code behind:
using System.Windows;
using System.Windows.Input;
namespace Focus
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
private void TextBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
MainViewModel vm = this.DataContext as MainViewModel;
vm.CheckToAddEmptyItem();
}
}
}
The ViewModel
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Focus
{
public class MainViewModel : INotifyPropertyChanged
{
private List<MyItem> _myItems = new List<MyItem>();
public IEnumerable<MyItem> OrderedItems
{
get { return _myItems.OrderBy(i => i.IsEmpty); }
}
internal void CheckToAddEmptyItem()
{
int count = _myItems.Count(i => i.IsEmpty);
if (count == 0)
{
_myItems.Add(new MyItem());
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs("OrderedItems"));
}
else if (count > 1)
{
var items = _myItems.Where(i => i.IsEmpty).Skip(1).ToArray();
foreach (MyItem item in items)
_myItems.Remove(item);
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs("OrderedItems"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public MainViewModel()
{
for(int i=1; i <= 5; ++i)
{
_myItems.Add(new MyItem() { FriendlyName = "Item #" + i, Name = "ITEM" + i });
}
if (null != PropertyChanged)
PropertyChanged(this, new PropertyChangedEventArgs("OrderedItems"));
CheckToAddEmptyItem();
}
}
}
The MyItem class:
using System.ComponentModel;
namespace Focus
{
public class MyItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _name = string.Empty;
public string Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
PropertyChanged(this, new PropertyChangedEventArgs("IsEmpty"));
}
}
}
}
private string _friendlyName = string.Empty;
public string FriendlyName
{
get { return _friendlyName; }
set
{
if (value != _friendlyName)
{
_friendlyName = value;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("FriendlyName"));
PropertyChanged(this, new PropertyChangedEventArgs("IsEmpty"));
}
}
}
}
public bool IsEmpty
{
get { return string.IsNullOrEmpty(Name) && string.IsNullOrEmpty(FriendlyName); }
}
}
}