使用带有ICommand的父SelectedItem的主 - 细节TabControl绑定(1:n)

时间:2016-10-31 08:21:43

标签: c# wpf xaml

我有与XAML相关的问题,我试图徒劳地研究答案。我已经向XAML评论了相关问题。在我看来,由于我尝试安排事情的方式,这个问题更加复杂。

基本上我有一个在TabControl标题中使用的主视图模型,然后在内容区域中我将显示主视图模型中的项目列表。我只是不知道如何绑定。这是主要问题。但是,我怀疑我的下一步和最终目标可能会考虑如何考虑这个问题,所以我也添加了它们。其余的代码是为了完整。

<StackPanel>
    <TabControl x:Name="mainsTabControl"
             IsSynchronizedWithCurrentItem="True"
             IsEnabled="True"
             Visibility="Visible"
             ItemsSource="{Binding Path=Mains}">

        <!-- How to select a different background for the selected header? Note that the background color is "selected tab" if MainContentViewModel.IsActive is not TRUE.
             If it is, a different color is chosen. Here this fact is just emulated with IsEnabled property due to well, multi-binding to the rescue (and a converter)? -->

        <!-- Is there a clean way to use ICommand binding (RelayCommand) to check if it is OK to change the tab and if necessary, present a dialogue asking for the change? -->
        <TabControl.ItemContainerStyle>
            <Style TargetType="{x:Type TabItem}">
                <Setter Property="IsEnabled" Value="{Binding IsActive}"/>
            </Style>
        </TabControl.ItemContainerStyle>

        <!-- This binds to every item in the MainViewModel.Mains collection. Note the question about background color. -->
        <TabControl.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Name}" HorizontalAlignment="Center"/>
                </StackPanel>
            </DataTemplate>
        </TabControl.ItemTemplate>

        <TabControl.ContentTemplate>
            <DataTemplate>
                <!-- This binding gives reference to the selected MainContentViewModel. -->
                <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="10" DataContext="{Binding ElementName=mainsTabControl, Path=SelectedItem, Mode=OneWay}">
                    <ItemsControl  ItemsSource="{Binding Path=CustomItems}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Vertical"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}"/>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </StackPanel>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</StackPanel>

using GalaSoft.MvvmLight;
using System.Collections.ObjectModel;
using System.Linq;

namespace WpfDependencyInjection.ViewModel
{
public class MainContentViewModel: ViewModelBase
{
    private ObservableCollection<CustomItemViewModel> customItems;

    private mainContentDto MainContent { get; set; }

    public string Name { get; }


    public bool isActive;


    public MainContentViewModel(Engine engine, mainContentDto mainContent)
    {
        MainContent = mainContent;
        Name = MainContent.Name;
        IsActive = true;

        //The custom items belonging to this main content.
        var customItems = engine.CustomItemContents.Where(i => i.MainContentId == MainContent.Id).Select(i => new CustomItemViewModel(engine, i));
        CustomItems = new ObservableCollection<CustomItemViewModel>(customItems);
    }


    public ObservableCollection<CustomItemViewModel> CustomItems
    {
        get
        {
            return customItems;
        }
        set
        {
            customItems = value;
            RaisePropertyChanged(nameof(CustomItems));
        }
    }


    public bool IsActive
    {
        get
        {
            return isActive;
        }
        private set
        {
            isActive = value;
            RaisePropertyChanged(nameof(IsActive));
        }
    }
}
}

public class CustomItemViewModel: ViewModelBase
{
    private Engine Engine { get; }

    private ItemTypeDto  CustomItem { get; set; }

    public string Name { get; }        


    public CustomItemViewModel(Engine engine, ItemTypeDto customItem)
    {
        Engine = engine;
        CustomItem = customItem;
        Name = customItem.Name;
    }
}

namespace WpfDependencyInjection
{    
public class Engine
{
    public string Name { get; } = "EngineMan";

    public List<mainContentDto> MainContents { get; set; } = new List<mainContentDto>(new[]
    {
        new mainContentDto { Name = "Main One", Id = Guid.Parse("C51AC758-504B-4914-92DC-5EBE9A1F39E1"), Version = 1 },
        new mainContentDto { Name = "Main Two", Id = Guid.Parse("C51AC758-504B-4914-92DC-5EBE9A1F39E2"), Version = 1 }
    });


    public List<ItemTypeDto> CustomItemContents { get; set; } = new List<ItemTypeDto>(new ItemTypeDto[]
    {            
        new ItemType1Dto { MainContentId = Guid.Parse("C51AC758-504B-4914-92DC-5EBE9A1F39E1"), Name = "ItemType1Dto I", Id = Guid.NewGuid(), Version = 1 },
        new ItemType2Dto { MainContentId = Guid.Parse("C51AC758-504B-4914-92DC-5EBE9A1F39E1"), Name = "ItemType2Dto I", Id = Guid.NewGuid(), Version = 1 },

        new ItemType2Dto { MainContentId = Guid.Parse("C51AC758-504B-4914-92DC-5EBE9A1F39E2"), Name = "ItemType2Dto 2", Id = Guid.NewGuid(), Version = 1 }
    });


    public Engine()
    {
    }
}
}

&lt;编辑:绑定部分解决,但不是ICommand部分。

1 个答案:

答案 0 :(得分:1)

试试这个:

<TabControl x:Name="mainsTabControl"
            IsEnabled="True"
            IsSynchronizedWithCurrentItem="True"
            ItemsSource="{Binding Path=Mains}"
            SelectedItem="0"
            Visibility="Visible">
    <TabControl.ItemContainerStyle>
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="IsSelected" Value="{Binding IsSelected}" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Border Background="{TemplateBinding Background}">
                            <ContentPresenter ContentSource="Header" />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="HotPink" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TabControl.ItemContainerStyle>

    <TabControl.ItemTemplate>
        <DataTemplate DataType="{x:Type local:MainContentViewModel}">
            <Button Background="{x:Null}"
                    Command="{Binding SomeCommand}"
                    Content="{Binding Name}"
                    FocusVisualStyle="{x:Null}" />
        </DataTemplate>
    </TabControl.ItemTemplate>

    <TabControl.ContentTemplate>
        <DataTemplate DataType="{x:Type local:MainContentViewModel}">
            <ItemsControl Margin="10"
                          VerticalAlignment="Top"
                          ItemsSource="{Binding Path=CustomItems}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Vertical" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="{x:Type local:CustomItem}">
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

<强>命令:

可能有更简洁的方法,但在这里我们将IsSelected TabItem绑定到viewmodel的IsSelected属性。这使得有一个命令可以询问是否可以导航并将IsSelected设置为true(如果是)。

<强>背景

我们还重新设置了tabitem,以便背景按照我们的意愿工作。如果使用Snoop WPF进行检查,则在选择项目时会插入额外的边框。

旁注1:

不要将TabControl置于StackPanel之内。一个StackPanel大小的内容,将杀死滚动并在控件外绘制。它还附带一个成本,一个深的视觉树并不便宜。 ItemTemplate和其他地方相同。实际上StackPanel很少适合任何事情:)

旁注2:

如果在DataType中指定DataTemplate,则会获得智能感知和一些编译时检查。