0

I am learning on how to create custom control in WPF. I have few problems that I am stuck with.

Basically, I am trying to create custom control for navigation bar that has two level.

  • Level 1 contains a big icons with a title text; and
  • Level 2 contains a small icons where the user can click on it and event will be generated.

This is what I am trying to archieve:

--------------------------------
|                              |
|  ICON     TITLE 1            |
|                              |
|      small icon     option 1 |
|      small icon     option 2 |
|      small icon     option 3 |
|                              |
|                              |
|  ICON     TITLE 2            |
|                              |
|      small icon     option 1 |
|      small icon     option 2 |
|      etc...                  |
|                              |
--------------------------------

Here is my Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Global.WPFs.GUIs">
    <Style TargetType="{x:Type local:GNavBar}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:GNavBar}">
                    <ScrollViewer x:Name="PART_Scroll"
                                  Background="{TemplateBinding Background}"
                                  BorderBrush="{TemplateBinding BorderBrush}"
                                  BorderThickness="{TemplateBinding BorderThickness}"
                                  HorizontalAlignment="Stretch"
                                  VerticalAlignment="Stretch"
                                  VerticalScrollBarVisibility="Auto"
                                  Focusable="False">
                        <ItemsControl x:Name="PART_Items">
                            <ItemsControl.ItemContainerStyle>
                                <Style TargetType="ContentPresenter">
                                    <Setter Property="Margin" Value="0"/>
                                    <Setter Property="Control.Padding" Value="0 8 0 2"/>
                                    <Setter Property="Control.HorizontalContentAlignment" Value="Stretch"/>
                                </Style>
                            </ItemsControl.ItemContainerStyle>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <StackPanel VerticalAlignment="Center" HorizontalAlignment="Stretch">
                                        <Grid>
                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="76"></RowDefinition>
                                            </Grid.RowDefinitions>
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="76" />
                                                <ColumnDefinition Width="*" />
                                            </Grid.ColumnDefinitions>
                                            <Image Grid.Column="0" Source="{Binding ImgSrc}" Width="72" Height="72" HorizontalAlignment="Center" VerticalAlignment="Center"></Image>
                                            <TextBlock Grid.Column="1" Text="{Binding Text}" Margin="4 0 0 0" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="20"></TextBlock>
                                        </Grid>
                                        <ListBox ItemsSource="{Binding Items}"
                                                 BorderThickness="0"
                                                 Background="Transparent" 
                                                 ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                                                 ScrollViewer.VerticalScrollBarVisibility="Disabled">
                                            <ListBox.ItemContainerStyle>
                                                <Style TargetType="ListBoxItem">
                                                    <Setter Property="Margin" Value="0"/>
                                                    <Setter Property="Control.Padding" Value="0"/>
                                                </Style>
                                            </ListBox.ItemContainerStyle>
                                            <ListBox.ItemTemplate>
                                                <DataTemplate>
                                                    <Border>
                                                        <Grid>
                                                            <Grid.RowDefinitions>
                                                                <RowDefinition Height="36"></RowDefinition>
                                                            </Grid.RowDefinitions>
                                                            <Grid.ColumnDefinitions>
                                                                <ColumnDefinition Width="16" />
                                                                <ColumnDefinition Width="16" />
                                                                <ColumnDefinition Width="*" />
                                                            </Grid.ColumnDefinitions>
                                                            <Image Grid.Column="1" Source="{Binding ImgSrc}" Width="16" Height="16" HorizontalAlignment="Center" VerticalAlignment="Center"></Image>
                                                            <TextBlock Grid.Column="2" Text="{Binding Text}" Margin="4 0 0 0" HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="16"></TextBlock>
                                                        </Grid>
                                                    </Border>
                                                </DataTemplate>
                                            </ListBox.ItemTemplate>
                                        </ListBox>
                                    </StackPanel>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </ScrollViewer>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Everything is working fine, but I have two problems:

  1. How do I go about with detecting which item is clicked so I can raise the event to the parent class?
  2. Scrolling works fine if I scroll in TITLE, but as soon as the mouse pointer hit listbox, the scrolling stops working.

Thanks...


This is what I'm trying to achieve: Sample NavBar

14
  • ListBox will consume the scroll event, as it contains a list of items, so you need to handle the scroll event and set the e.Handled = false. For the events of being clicked then you need to attach an event handler to Image and TextBlock. That could be done through Style and an event setter. Commented Nov 25, 2017 at 17:04
  • @XAMlMAX, I know that, I've google it. hehehe ;) but how to handle the event inside a template? Commented Nov 27, 2017 at 2:50
  • I see. Another option would be to use TreeView. Which would do everything you need to achieve. Commented Nov 27, 2017 at 9:52
  • @XAMlMAX, how to detect which node (eg. item in the treeview) has been clicked (so that I can use it to raise event to calling function) inside a template? Also, is it possible to use TreeView to display different size of icons (eg. title icon is a big icon 64x64 where as small icon is 16x16)? Commented Nov 28, 2017 at 12:06
  • 1
    @XAMlMAX, there is no need to apologize. I am very grateful that you are trying to help :) Unfortunately, I can't use TreeView as I have no idea how to style the TreeView to match what I am trying to achieve. I have, however, just successfully implementing MVVM to handle all the problems that I've faced. I'll posted the solution when I'm a bit free. Thanks XAMIMAX for your kind help. Commented Dec 1, 2017 at 9:43

2 Answers 2

1

To detect which item gets clicked, you can bind SelectedItem in your ListBox. eg; SelectedItem={Binding Property,Mode=TwoWay} So once you click on the items, In the setter you can raise notify property changed. You can also get the Item index from your Items collection. For that you just need to bind SelectedIndex in your ListBox.

Sign up to request clarification or add additional context in comments.

5 Comments

OMG! That is very clever! Will try that... How about the 2nd problem on the scrolling?
I'm not pretty sure why its happening , ideally it should not happen, but you can try ScrollViewer.CanContentScroll="True" and why you are keeping ScrollViewer.VerticalScrollBarVisibility="Disable" ,ScrollViewer.VerticalScrollBarVisibility="Disabled" ,you can set "Auto" instead. For this kind of control, I would prefer to use DataGrid instead of listbox.
I've tried all settings (eg. make it "Auto", etc), but it the scrolling always stop at ListBox. This is because ListBox will consume the scrolling. The only way to stop it is to handle the scroll event, but I am not sure how to handle any event inside the template :(
Btw, here is the reference to scrolling problem (which I need to handle "somehow" inside template): stackoverflow.com/questions/40625475/…
Without working solution , its difficult to find the actual problems.
0

For 1 -

Instead of Border, use a button with a control template that defines your image + text.

Create a ICommand property in the View model for each item, then bind it to the listbox item button's Command.

Handle the click in the view-model.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.