Question

On a tabcontrol I have several tabpages, on one of the tabs there is a textbox in the content.

This textbox is content bound with a simple Path=PropertyName and UpdateSourceTrigger=LostFocus. The reason I am using LostFocus is I trap the Lost focus event of the Textbox and possibly reformat the text. This is a "time" textbox and if they enter "0900", I want to reformat to "09:00". This part works great when I press the tab key to move to the next control, but if I type "0900" then press one of the other tabs, I hit the lost focus and re-format the value in the textbox, BUT the bind never gets called to update my object. When I come back to the tab, the value is blanked out (or reset to the original value on the object)

Any ideas why textbox does not trigger the Binding update when changing tab page?

Note: this also happens with a regular textbox that does wire to the lost focus event. It seems to have something to do with click on the tab.

[[Added Code ]] More notes: 1. I am dynamically creating the tabs and controls on the tab (not sure if that has something to do with it or not) 2. I am using the Prism libraries

MainWindow Xaml

<Window.Resources>
    <DataTemplate DataType="{x:Type ctrls:myTextBoxDef}">
        <Grid Width="300">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" MinWidth="100" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="28" />
            </Grid.RowDefinitions>
            <TextBlock Grid.Column="0"
                   HorizontalAlignment="Stretch"
                   VerticalAlignment="Center"
                   Text="{Binding LabelText}" />

            <TextBox Grid.Column="1"
                 HorizontalAlignment="Stretch"
                 VerticalAlignment="Center"
                 Text="{Binding DocValue,
                                Mode=TwoWay,
                                ValidatesOnDataErrors=True,
                                UpdateSourceTrigger=LostFocus}"
                         />
        </Grid>
    </DataTemplate>
</Window.Resources>


<Grid>
    <TabControl HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                HorizontalContentAlignment="Stretch"
                VerticalContentAlignment="Stretch"
                IsTabStop="False"                 
                ItemsSource="{Binding Tabs, Mode=OneWay}"
                SelectedItem="{Binding SelectedTab,
                                Mode=TwoWay,
                                NotifyOnSourceUpdated=True}"
                >
        <TabControl.ItemTemplate>
            <DataTemplate>
                <Grid>  
                    <TextBlock Margin="18,14,22,0"                                       
                               Text="{Binding HeaderText}" />
                </Grid>
            </DataTemplate>
        </TabControl.ItemTemplate>
        <!--  Content  -->
        <TabControl.ContentTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>

                    <AdornerDecorator Grid.Column="0">
                        <ItemsControl Grid.Column="0"
                                          HorizontalAlignment="Stretch"
                                          VerticalAlignment="Stretch"
                                          IsTabStop="False"
                                          ItemsSource="{Binding Controls,
                                                                Mode=OneWay}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel Grid.Column="0"
                                                   Margin="10,5,0,0"
                                                   HorizontalAlignment="Stretch"
                                                   VerticalAlignment="Stretch"
                                                   Orientation="Vertical" />
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                        </ItemsControl>
                    </AdornerDecorator>
                    </Grid>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</Window>

Main Window Code Behind

public partial class MainWindow : Window
{
    private DataContextObject obj = new DataContextObject();
    public MainWindow()
    {
        InitializeComponent();

        myTextBoxDef txt1 = new myTextBoxDef(obj, "Textbox 1", "TAB1TextBox1");
        myTextBoxDef txt1b = new myTextBoxDef(obj, "Textbox 1 value", "TAB1TextBox1");

        myTextBoxDef txt2 = new myTextBoxDef(obj, "Textbox 2", "TAB1TextBox2");
        myTextBoxDef txt2b = new myTextBoxDef(obj, "Textbox 2 value", "TAB1TextBox2");

        obj.Tabs.Add(new myTabDef("Tab 1", new ObservableCollection<myTextBoxDef>() { txt1, txt2 }));
        obj.Tabs.Add(new myTabDef("Tab 2", new ObservableCollection<myTextBoxDef>() { txt1b, txt2b }));

        obj.SelectedTab = obj.Tabs[0];

        this.DataContext = obj;
    }
}

Supporting objects

public class DataContextObject : NotificationObject
{
    List<myTabDef> _tabs = new List<myTabDef>();
    public List<myTabDef> Tabs
    {
        get
        {
            return _tabs;
        }
    }

    private myTabDef _item;
    public myTabDef SelectedTab
    {
        get
        { return _item; }
        set
        {
            _item = value;
            this.RaisePropertyChanged("SelectedItem");
        }
    }

    private string _txt1 = "";
    public string TAB1TextBox1
    {
        get { return _txt1; }
        set
        {
            _txt1 = value;
            this.RaisePropertyChanged("TAB1TextBox1");
        }
    }

    private string _txt2 = "";
    public string TAB1TextBox2
    {
        get { return _txt2; }
        set
        {
            _txt2 = value;
            this.RaisePropertyChanged("TAB1TextBox2");
        }
    }

    private string _txt3 = "";
    public string TAB2TextBox1
    {
        get { return _txt3; }
        set
        {
            _txt3 = value;
            this.RaisePropertyChanged("TAB2TextBox1");
        }
    }
}

public class myTabDef
{
    public myTabDef(string tabText, ObservableCollection<myTextBoxDef> controls)
    {
        HeaderText = tabText;
        _left = controls;
    }

    public string HeaderText { get; set; }

    private ObservableCollection<myTextBoxDef> _left = new ObservableCollection<myTextBoxDef>();
    public ObservableCollection<myTextBoxDef> Controls
    {
        get
        {
            return _left;
        }
    }
}

public class myTextBoxDef : NotificationObject
{
    public myTextBoxDef(NotificationObject bound, string label, string bindingPath)
    {
        LabelText = label;
        Path = bindingPath;
        BoundObject = bound;

        BoundObject.PropertyChanged += BoundObject_PropertyChanged;
    }

    public string LabelText
    {
        get;
        set;
    }

    public NotificationObject BoundObject
    {
        get;
        set;
    }

    public string DocValue
    {
        get
        {
            return PropInfo.GetValue(BoundObject, null) as string;
        }
        set
        {
            PropInfo.SetValue(BoundObject, value, null);
        }
    }

    protected virtual void BoundObject_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName.Equals(Path))
        {
            this.RaisePropertyChanged("DocValue");
        }
    }

    public string Path
    {
        get;
        set;
    }

    private PropertyInfo pi = null;
    protected PropertyInfo PropInfo
    {
        get
        {
            if (pi == null && BoundObject != null && !string.IsNullOrEmpty(Path))
            {
                PropertyInfo[] properties = BoundObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

                pi = properties.Where((prop) => string.Compare(prop.Name, Path, true) == 0).FirstOrDefault();
            }

            return pi;
        }
    }
}
Was it helpful?

Solution

We have found a solution. I came cross this set of postings

https://groups.google.com/forum/#!topic/wpf-disciples/HKUU61A5l74

They talk about a control called TabControlEx. Towards the bottom (5th from the bottom) you will see a posting by Sacha Barber that has a zip file with an example.

It solved all our problems we were having.

here is also another link where the code for the Class is posted

http://updatecontrols.codeplex.com/discussions/214434

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top