TabItem基于ViewModel类型

时间:2014-03-16 21:45:46

标签: c# .net wpf xaml mvvm

1 - 我有TabControl。它的项目来源是Tabs的集合   不同种类。我需要为每种类型使用不同的XAML。如何形成TabItem标题和内容取决于ViewModel类型?
2 - 为每种类型的ViewModel封装XAML的最佳解决方案是什么?我应该为每种类型配备一个UserControl还是有更好的解决方案?

HumanTabViewModel和InvaderTabViewModel是BaseViewModel类的子类。

<TabControl ItemsSource="{Binding Tabs}">
</TabControl>

class PanelViewModel : BaseViewModel
{
    private readonly ObservableCollection<BaseViewModel> _tabs = new ObservableCollection<BaseViewModel>();

    public ObservableCollection<BaseViewModel> Tabs
    {
        get { return _tabs; }
    }

    private void InitTabs()
    {
        // Fill Tabs collection with some logic

        var tab1 = new HumanTabViewModel ();
        _tabs.Add(tab1);

        var tab2 = new InvaderTabViewModel ();
        _tabs.Add(tab2);
    }
}

1 个答案:

答案 0 :(得分:1)

使用DataTemplates,您可以为您的类型定义不同的外观:

DataTemplate用于为逻辑实体(.cs)提供可视化表示,一旦您将逻辑对象(在您的案例中为invader / human vm&#39; s)作为内容分配,框架将遍历逻辑树为您的类型寻找DataTemplate。

如果找不到,它只会显示&#34; ToString()&#34;你的类型。

在您的情况下,您有2个内容TabItem.Content和Header,可以通过HeaderTemplate为其分配DataTemplate。

HumanView和InvaderView是UserControls。

CS:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
        Items.Add(new HumanViewModel());
        Items.Add(new InvaderViewModel());
    }

    private ObservableCollection<BaseViewModel> items;
    public ObservableCollection<BaseViewModel> Items
    {
        get
        {
            if (items == null)
                items = new ObservableCollection<BaseViewModel>();
            return items;
        }
    }
}

public class BaseViewModel : INotifyPropertyChanged
{
    public virtual string Header
    {
        get { return "BaseViewModel"; }
    }


    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

public class HumanViewModel : BaseViewModel
{

    public override string Header
    {
        get
        {
            return "HumanViewModel";
        }
    }
}

public class InvaderViewModel : BaseViewModel
{

    public override string Header
    {
        get
        {
            return "InvaderViewModel";
        }
    }
}

XAML:

<Window>
   <Window.Resources>
      <DataTemplate DataType="{x:Type local:HumanViewModel}">
          <local:HumanView />
      </DataTemplate>
      <DataTemplate DataType="{x:Type local:InvaderViewModel}">
          <local:InvaderView />
      </DataTemplate>

       <Style TargetType="TabItem">
          <Setter Property="HeaderTemplate">
              <Setter.Value>
                  <DataTemplate>
                      <TextBlock Text="{Binding Header,Mode=OneWay}" FontSize="18" FontWeight="Bold" Foreground="DarkBlue" Width="Auto"/>
                  </DataTemplate>
              </Setter.Value>
          </Setter>
      </Style>

  </Window.Resources>


  <Grid>
      <TabControl ItemsSource="{Binding Items, Mode=OneWay}" />    
  </Grid>

</Window>