In my wpf program i would like to have tabs that would be generated from array or list. I would like to edit files with each tab. Each tab would have corresponding folder with same name, so all tabs should look same (this is why I used DataTemplates), since files in all directories are all generated with same names but their content is different. I have code that generates tabs from array and adds names to tabs.
public class MainWindowViewModel
{
public ObservableCollection<TabViewModel> Tabs { get; set; }
public MainWindowViewModel()
{
this.Tabs = new ObservableCollection<TabViewModel>();
var location = System.AppDomain.CurrentDomain.BaseDirectory.ToString();
string[] folderList = new string[] { "Folder1", "Folder2" };
foreach (string folder in folderList)
{
this.Tabs.Add(new TabViewModel(folder));
string newLocation = location + folder + "\\";//i would like to point tab to this directory
}
}
}
public class TabViewModel
{
public string Name { get; set; }
public TabViewModel(string name)
{
this.Name = name;
}
}
<TabControl ItemsSource="{Binding Tabs}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate >
<TextBox x:Name="fileTextBox"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
But I have 2 problems:
you're experiencing this behavior because, when binding by ItemsSource
, all TabControl items are 'optimized' by sharing a panel to render the content (see this question)
I suggest you use the INotifyPropertyChanged interface in your view model and add the file data in the TabViewModel (I added the Location property but you can also add a Content property)
public class MainWindowViewModel
{
public ObservableCollection<TabViewModel> Tabs { get; set; }
public MainWindowViewModel()
{
this.Tabs = new ObservableCollection<TabViewModel>();
var location = System.AppDomain.CurrentDomain.BaseDirectory.ToString();
string[] folderList = new string[] { "Folder1", "Folder2" };
foreach (string folder in folderList)
{
string newLocation = location + folder + "\\";//i would like to point tab to this directory
this.Tabs.Add(new TabViewModel(folder, newLocation));
}
}
public class TabViewModel : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
return;
_name = value;
OnPropertyChanged();
}
}
private string _location;
public string Location
{
get { return _location; }
set
{
if (_location == value)
return;
_location = value;
OnPropertyChanged();
}
}
public TabViewModel(string name, string location)
{
this.Name = name;
this.Location = location;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
notice the use of UpdateSourceTrigger
to update the viewModel when the textbox content changes
<TabControl ItemsSource="{Binding Tabs}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate >
<TextBox x:Name="fileTextBox" Text="{Binding Location, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</TabControl.ContentTemplate>