C# 带有标签标题的导航按钮

C# 带有标签标题的导航按钮,c#,wpf,xaml,mvvm,navigation,C#,Wpf,Xaml,Mvvm,Navigation,首先,我想说我是C#、WPF、XAML和MVVM的新手。我一直无法找到并回答我要找的东西,但我不知道这是因为没有人问我,还是我找错了地方。如果已经有了什么,请给我指出正确的方向,我将不胜感激 现在我的问题是,我正在尝试制作一个具有4个条件的导航仪表板/面板: 默认情况下,按钮仅作为文本查看 悬停时,会显示文本是按钮 选中后,指示按钮已选中并保持该状态,直到选择另一页 在分类相似的页面组上方具有非按钮标签 是我在网上找到的格式的一个例子 我使用找到的一篇文章开始了MVVM转换。我将MVVM Lig

首先,我想说我是C#、WPF、XAML和MVVM的新手。我一直无法找到并回答我要找的东西,但我不知道这是因为没有人问我,还是我找错了地方。如果已经有了什么,请给我指出正确的方向,我将不胜感激

现在我的问题是,我正在尝试制作一个具有4个条件的导航仪表板/面板:

  • 默认情况下,按钮仅作为文本查看
  • 悬停时,会显示文本是按钮
  • 选中后,指示按钮已选中并保持该状态,直到选择另一页
  • 在分类相似的页面组上方具有非按钮标签
  • 是我在网上找到的格式的一个例子

    我使用找到的一篇文章开始了MVVM转换。我将MVVM Light库添加到我的项目中,并使用了它们的RelayCommand和ViewModelBase。这让我想到了不知道如何将中间标签添加到面板内的项目列表中,并且单选按钮从不取消选择的问题

    为了添加标签,我尝试了基于stackoverflow讨论的CompositeCollections,但没有成功。然后我尝试复制我已经完成的过程,然后在它们之间添加标签,但也没有成功

    移动到取消选择问题,我发现另一个stackoverflow帖子建议列表,但我的单选按钮样式没有正确应用,我仍然无法确定如何添加标签

    以下是我的列表代码:

    <ListBox ItemsSource="{Binding PageViewModels}" SelectedItem="{Binding CurrentPageViewModel}">
                <ListBox.ItemContainerStyle>
                    <Style TargetType="{x:Type ListBoxItem}">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                    <RadioButton Style="{StaticResource NavRadio}"
                                             Content="{TemplateBinding Content}"
                                             IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}"/>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ListBox.ItemContainerStyle>
            </ListBox>
    
    
    
    这是我的单选按钮模板,我在任何地方都使用它作为参考:

    <Style x:Key="NavRadio" TargetType="{x:Type RadioButton}">
        <Setter Property="MinHeight" Value="35"/>
        <Setter Property="MinWidth" Value="200"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RadioButton}">
                    <Grid x:Name="NavButtonGrid">
                        <Rectangle>
                            <Rectangle.Fill>
                                <LinearGradientBrush StartPoint="0,0"
                                                     EndPoint="1,0">
                                    <GradientStop Offset="0"
                                                  Color="{DynamicResource ColorBackNavSelect}"/>
                                    <GradientStop x:Name="SelectStop"
                                                  Offset="0"
                                                  Color="{DynamicResource ColorBackNavSelect}"/>
                                    <GradientStop x:Name="DefaultStop"
                                                  Offset="0"
                                                  Color="Transparent"/>
                                    <GradientStop Offset="1"
                                                  Color="Transparent"/>
                                </LinearGradientBrush>
                            </Rectangle.Fill>
                        </Rectangle>
                        <ContentPresenter x:Name="NavButtonContent"
                                          Margin="30,0,0,0"
                                          VerticalAlignment="Center"
                                          HorizontalAlignment="Left"
                                          TextElement.Foreground="{DynamicResource ForeNav}"
                                          TextElement.FontSize="{DynamicResource NavFontSize}">
                        </ContentPresenter>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Trigger.EnterActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="DefaultStop"
                                                         Storyboard.TargetProperty="Offset"
                                                         To="1"
                                                         Duration="0:0:0.15"/>
                                        <DoubleAnimation Storyboard.TargetName="SelectStop"
                                                         Storyboard.TargetProperty="Offset"
                                                         To="1"
                                                         Duration="0:0:0.15"
                                                         BeginTime="0:0:0.15"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="SelectStop"
                                                         Storyboard.TargetProperty="Offset"
                                                         To="0"
                                                         Duration="0:0:0.06"/>
                                        <DoubleAnimation Storyboard.TargetName="DefaultStop"
                                                         Storyboard.TargetProperty="Offset"
                                                         To="0"
                                                         Duration="0:0:0.06"
                                                         BeginTime="0:0:0.06"/>
    
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.ExitActions>
                            <Setter TargetName="NavButtonContent" Property="TextElement.Foreground" Value="{DynamicResource ForeNavSelect}"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="NavButtonContent" Property="TextElement.FontWeight" Value="Bold"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter TargetName="NavButtonContent" Property="TextElement.Foreground" Value="{DynamicResource ForeNavSelect}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
    
    
    有什么办法可以做到这一点吗?我觉得这不是一个罕见的设计,所以必须有一些解决方案。我不介意在一个完全不同于我所做的方向的解决方案,我只是提供信息来帮助

    编辑:

    根据我的评论,我并不是站在标签是唯一阻碍我前进的问题的位置上。这是我的MainWindowViewModel的代码:

    #region Fields
    
        private ICommand _changePageCommand;
    
        private IPageViewModel _currentPageViewModel;
        private List<IPageViewModel> _pageViewModels;
    
        #endregion
    
        public MainWindowViewModel()
        {
            // Add available pages
            PageViewModels.Add(new HomeViewModel());
            PageViewModels.Add(new ReportsViewModel());
            PageViewModels.Add(new PurchasesViewModel());
            PageViewModels.Add(new InventoryViewModel());
            PageViewModels.Add(new PackingsViewModel());
            PageViewModels.Add(new HistoryViewModel());
            PageViewModels.Add(new ContactsViewModel());
            PageViewModels.Add(new DefinitionsViewModel());
            PageViewModels.Add(new AdminViewModel());
    
            // Set starting page
            CurrentPageViewModel = PageViewModels[0];
        }
    
        #region Properties / Commands
    
        public ICommand ChangePageCommand
        {
            get
            {
                if (_changePageCommand == null)
                {
                    _changePageCommand = new RelayCommand<object>(
                        param => ChangeViewModel((IPageViewModel)param),
                        param => param is IPageViewModel);
                }
    
                return _changePageCommand;
            }
        }
    
    
        public List<IPageViewModel> PageViewModels
        {
            get
            {
                if (_pageViewModels == null)
                    _pageViewModels = new List<IPageViewModel>();
    
                return _pageViewModels;
            }
        }
    
        public IPageViewModel CurrentPageViewModel
        {
            get
            {
                return _currentPageViewModel;
            }
            set
            {
                if (_currentPageViewModel != value)
                {
                    _currentPageViewModel = value;
                    RaisePropertyChanged("CurrentPageViewModel");
                }
            }
        }
    
        #endregion
    
        #region Methods
    
        private void ChangeViewModel(IPageViewModel viewModel)
        {
            if (!PageViewModels.Contains(viewModel))
                PageViewModels.Add(viewModel);
    
            CurrentPageViewModel = PageViewModels
                .FirstOrDefault(vm => vm == viewModel);
        }
    
        #endregion
    }
    
    #区域字段
    专用ICommand _changePageCommand;
    私有IPageViewModel\u currentPageViewModel;
    私有列表pageViewModels;
    #端区
    公共主窗口视图模型()
    {
    //添加可用页面
    添加(新的HomeViewModel());
    添加(新的ReportsViewModel());
    添加(新的PurchasesViewModel());
    添加(新的InventoryViewModel());
    添加(新的PackingsViewModel());
    添加(新的HistoryViewModel());
    添加(新联系人viewmodel());
    添加(新定义viewmodel());
    添加(新的AdminViewModel());
    //设置起始页
    CurrentPageViewModel=PageViewModels[0];
    }
    #区域属性/命令
    公共ICommand ChangePageCommand
    {
    得到
    {
    如果(_changePageCommand==null)
    {
    _changePageCommand=newrelaycommand(
    param=>ChangeViewModel((IPageViewModel)param),
    param=>param是IPageViewModel);
    }
    返回_changepage命令;
    }
    }
    公共列表页面视图模型
    {
    得到
    {
    如果(_pageViewModels==null)
    _pageViewModels=新列表();
    返回页面视图模型;
    }
    }
    公共IPageViewModel CurrentPageViewModel
    {
    得到
    {
    返回_currentPageViewModel;
    }
    设置
    {
    如果(_currentPageViewModel!=值)
    {
    _currentPageViewModel=值;
    RaisePropertyChanged(“CurrentPageViewModel”);
    }
    }
    }
    #端区
    #区域方法
    私有void ChangeViewModel(IPageViewModel viewModel)
    {
    如果(!PageViewModels.Contains(viewModel))
    PageViewModels.Add(viewModel);
    CurrentPageViewModel=PageViewModels
    .FirstOrDefault(vm=>vm==viewModel);
    }
    #端区
    }
    
    如何在维护功能的同时将PageViewModels列表拆分为单独的列表?嵌套列表是解决方案吗?或者我可以给每个页面的ViewModel一个名为“Group”的字符串,类似于它的“Name”,并将控件仅绑定到PageViewModels列表中具有相同“Group”字符串的项目吗?

    将groupname添加到收音机中