使用父级SelectedItem和ICommand进行主细节TabControl绑定(1:n)

周数

我有与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()
    {
    }
}
}

<edit:绑定部分解决了,尽管不是ICommand部分。

约翰·拉森(Johan Larsson)

试试这个:

<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>

命令:

有可能是更清洁的方式,但在这里,我们结合IsSelectedTabItemIsSelected视图模型的财产。这样可以使用一个询问是否可以导航的命令,如果可以则设置IsSelected为true。

背景:

我们还重新设计了Tabitem,以便背景可以根据需要工作。如果您与Snoop进行检查,则WPF在选中该项目时会插入一个额外的边框。

旁注1:

不要把它TabControl变成StackPanel那样。StackPanel内容大小,将终止滚动并在控件之外绘制。同样,它也要付出代价,一棵深厚的视觉树并不便宜。ItemTemplate和其他地方也一样。实际上StackPanel,几乎没有什么合适的方法:)

旁注2:

如果在其中指定DataTypeDataTemplate则会得到智能感知和一些编译时检查。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

使用TabControl和MVVM在WPF中进行正确的数据绑定

使用.on()进行绑定时如何获取对父级的引用

使用ListView SelectedItem与TextCell命令进行绑定

如何使用数据绑定Android从Pojo访问父级和子级的值

使用TabControl和MVVM时绑定丢失

如何使用SQL查询在父级和子级之间对表记录进行排序

WPF主细节列表视图绑定

MVVM事件和ICommand绑定

使用ICommand的WPF绑定错误

在使用事件传播进行div选择和父级选择之后,将div子级从一个父级移动到另一个父级

使用后期静态绑定访问父级

在TabControl WPF问题中异步绑定到SelectedItem

使用父级和子级从表中获取值

使用EntityFramework向父级和子级升级

Aurelia中父级和子级自定义元素之间的双向绑定

使用find命令获取n级父级

如何使用 ionic 3 和拆分窗格组件实现主细节布局?

C# XAML 主细节绑定不起作用

使用JPA批注自动从父级删除子级和从子级删除父级

如何在mysql中进行查询以选择父级和子级而不重复父级行

使用fullPage.js回调更改活动元素的父级和父级父级的样式

EmberJS:主从细节,如何将细节的模型绑定到主数组模型中的项目

带有主细节的可可绑定问题,其中细节包含一个数组

使用ICommand和ServiceLocator传递父对象以MVVM方式加载子对象

ICommand覆盖SelectedItem

使用 Fluent API 在 EF Core 2.2 中避免使用 n 对 m 关系和父级的循环级联

使用查询获取父级和子级数据

ActiveAdmin:使用菜单标签和菜单父级

使用Powershell隐藏父级和子目录