0

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); }
        }
    }
}
jim
  • 1,153
  • 1
  • 7
  • 9
  • You need to find TextBox in your ItemTemplate, after adding a new element and focus it. Look this answer to find your control in template:[Find Control in ItemTenplate](http://stackoverflow.com/questions/21234459/collapse-opened-expanders-in-datatemplate-when-we-open-new-one/21236051#21236051) – Valera Scherbakov Jan 21 '14 at 10:35

1 Answers1

0

ItemsControl is not that friendly according to your needs as there are no properties to get a perticular selected item. Try using a Listbox Instead, as it exposes the properties like SelectedItem, SelectedIndex etc, Using these properties you can get the child control at any index value.

PS: I could elaborate my answer if you are looking to use alistbox and get the child elements.

A.K.
  • 3,321
  • 1
  • 15
  • 27
  • Thanks for the reply, but I don't see how using a listbox will help me losing the focus. – jim Jan 21 '14 at 15:47