0

I want to start off by saying I am new to C#, WPF, XAML, and MVVM. I haven't been able to find and answer to what I'm looking for, but I can't tell if that's because it hasn't been asked or if I'm looking in the wrong places. If there is something out there already, pointing me in the right direction would be much appreciated.

Now to my problem, I am trying to make a Navigation dashboard/panel with 4 criteria:

  1. By default the button views only as text
  2. When hovered, there is an indication that the text is a button
  3. When selected, indicate that the button is selected and maintain that state until another page is selected
  4. Have non-button labels above groups of categorically similar pages

Here is an example of the format I am looking for that I found online.

I started the MVVM conversion using an article I found here. I added the MVVM Light Libraries to my project and used their RelayCommand and ViewModelBase. This brought me to the issues of not knowing how to add intermediate labels to the list of items within the panel and the RadioButtons never deselect.

To add labels I tried CompositeCollections based off a stackoverflow discussion here with no success. I then tried duplicating the process I already had and then stack them with labels in between, also with no success.

Moving to the deselection issue I found another stackoverflow post here suggesting lists but my RadioButton style was not applying properly and I was still unable to figure out how to add labels.

Here is what I have for the list code:

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

And this is my RadioButton template that I have been using everywhere for reference:

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

Any ideas of a way to get this done? I feel like its not that uncommon of a design so there must be some solution. I don't mind a solution in a completely different direction than what I have done, I just supplied the information to help.

Edit:

Based off of the comment made, I am not at a point where labels is the only issue standing in my way. This is the code for my 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
}

How would I be able to break up the PageViewModels list into separate lists while maintaining functionality? Would a nested list be a solution? Or could I give each page's ViewModel a string named "Group" similar to how it has "Name" and bind a control only to items within the PageViewModels list that have the same string for "Group"?

Community
  • 1
  • 1
  • Add groupname to radio button. – Ayyappan Subramanian Feb 12 '16 at 16:58
  • @Ayyappan Subramanian Thank you! I tried adding that to the ListBox I have shown like you suggested and nothing changed. However I added that to the base code that I had from the second link and that fixed the issue with deselection there. Now the only thing I need to figure out is how to add labels in between the buttons easily. – Cole Giannotti Feb 12 '16 at 17:12
  • You should try creating a ListBox inside ListBox. – Ayyappan Subramanian Feb 12 '16 at 17:29
  • The problem I am having with the ListBox is that it is not accepting the style formatting from my style template "NavRadio". Also I am still unable to group the pages into separate list arrays. When I bind my PageViewModels to a ListBox(or any other control) all of my pages are displayed when I only want a select few of them displayed. – Cole Giannotti Feb 12 '16 at 18:00

0 Answers0