Juste au moment où je pensais que j'allais mieux, TabControl me pose maintenant des problèmes. J'ai lu des articles pertinents ici sur StackOverflow, mais je n'ai pas réussi à faire fonctionner ma simple application de démonstration comme je le voulais.Liaison de données correcte dans WPF à l'aide de TabControl et de MVVM
Pour garder les choses au point, je vais commencer par une seule question à propos de quelque chose que je ne comprends pas.
J'ai un TabControl dont les TabItems hébergent chacun le même UserControl. Lorsque je définis le DataTemplate de TabControl.ContentTemplate sur mon UserControl, un rendu de ce contrôle apparaît, mais il semble que ce soit le même contrôle pour chaque onglet. Ou peut-être que ce n'est lié à aucun des onglets.
MainWindow.xaml
<Window x:Class="TabControlMvvm.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:localviews="clr-namespace:TabControlMvvm.Views"
Title="MainWindow" Height="350" Width="525">
<TabControl ItemsSource="{Binding Tabs}" SelectedIndex="{Binding Selected}">
<TabControl.ContentTemplate>
<DataTemplate>
<localviews:PersonMainPanel />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Window>
code-behind met juste le ViewModel comme DataContext:
namespace TabControlMvvm {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow()
{
InitializeComponent();
DataContext = new TabControlMvvm.ViewModels.MainViewModel();
}
}
}
Contenu du TabItem devrait être un autre UserControl, PersonMainPanel.xaml:
<UserControl x:Class="TabControlMvvm.Views.PersonMainPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:localviews="clr-namespace:TabControlMvvm.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Border BorderBrush="Red" BorderThickness="2">
<TabControl TabStripPlacement="Bottom">
<TabItem Header="Tab 1">
<localviews:MyTabItem />
</TabItem>
<TabItem Header="Tab 2">
<TextBlock Text="This was left blank intentionally" />
</TabItem>
<TabItem Header="Tab 3">
<TextBlock Text="This was also left blank intentionally" />
</TabItem>
</TabControl>
</Border>
</UserControl>
Code-behind:
namespace TabControlMvvm.Views {
/// <summary>
/// Interaction logic for PersonMainPanel.xaml
/// </summary>
public partial class PersonMainPanel : UserControl {
public PersonMainPanel()
{
InitializeComponent();
}
}
}
Et le MainViewModel:
namespace TabControlMvvm.ViewModels {
public class MainViewModel : ViewModelBase {
public ICollectionView Tabs { get; set; }
public int Selected { get; set; }
public class Person
{
public string Name { get; set; }
}
public class DummyController {
public List<Person> Persons { get; private set; }
public DummyController()
{
Persons = new List<Person> {
new Person { Name = "Larry" },
new Person { Name = "Darryl" },
new Person { Name = "Other brother Darryl" }
};
}
}
public DummyController Controller { get; private set; }
public RelayCommand HelloCommand { get; set; }
public MainViewModel()
{
Controller = new DummyController();
/*
IEnumerable<TabItem> tabs = Enumerable.Range(1, _controller.Persons.Count())
.Select(x => new TabItem { Header = String.Format("Person {0}", x),
Content = new PersonMainPanel() });
*/
IEnumerable<TabItem> tabs = Enumerable.Range(1, Controller.Persons.Count())
.Select(x => new TabItem { Header = String.Format("Person {0}", x)});
Tabs = CollectionViewSource.GetDefaultView(tabs.ToList());
Tabs.MoveCurrentToFirst();
InitializeCommands();
}
private void InitializeCommands()
{
HelloCommand = new RelayCommand(() => { MessageBox.Show(String.Format("Hello, Person {0} named {1}!",
Selected, Controller.Persons[Selected].Name)); });
}
}
}
PersonMainPanel accueille un autre TabControl, où le contenu de l'onglet 1 est MyTabItem.xaml:
<UserControl x:Class="TabControlMvvm.Views.MyTabItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:" />
<TextBox Text="{Binding Name}" Width="100" />
</StackPanel>
<Button Command="{Binding HelloCommand}" Content="Say Hello" />
</StackPanel>
</UserControl>
code-behind:
namespace TabControlMvvm.Views {
/// <summary>
/// Interaction logic for MyTabItem.xaml
/// </summary>
public partial class MyTabItem : UserControl {
public MyTabItem()
{
InitializeComponent();
}
}
}
qui ressemble comme ceci à l'exécution:
questions que j'ai jusqu'à présent:
- Quand je rentre Nom de la personne 1 puis cliquez sur la personne 2 onglet, Nom de la personne 1 est encore visible, d'où mon hypothèse que les contrôles ne sont pas DataBound correctement . Je comprends que ItemsControls ne transmet pas leur DataContext à leurs enfants, mais je ne suis pas sûr de savoir comment résoudre ce problème sans associer la vue dans le code-behind.
- Je m'attendais à obtenir des erreurs de liaison de données dans la fenêtre de sortie en raison du DataContext manquant, mais je ne reçois aucune erreur. Je suppose que DataContext est null, mais cela ne se traduirait-il pas toujours par une erreur de liaison?
- Comment puis-je utiliser Snoop efficacement pour déboguer des problèmes comme celui-ci?
est ici la solution échantillon: http://www.filedropper.com/tabcontrolmvvm
Peut-être utile: https://stackoverflow.com/a/1870658/1136211 – Clemens
Comment votre MainViewModel regarder? – sTrenat
Oups, j'ai oublié l'évidence! Édité. En outre, @Clemens un emporter de votre poste lié est que la collection de sauvegarde ne devrait pas de TabItems, il devrait probablement être un ViewModel pour MyTabItem. Et le XAML qui spécifie le DataTemplate devrait être bon tel quel. Je vais essayer ça au cas où c'était mon problème tout le temps! – Dave