もっと詳しく

Since the WPF control library lacks a number of nice controls from windows forms one either has to buy one the pricy WPF libraries or build the necessary controls on his own. Here’s my implementation of a CheckedListBox with an item context menu.

First of all we have to define the WPF ListBox we want to reshape:

<listbox selectionmode=”Single”/>

Alright then define the context menu for a listbox item:

<usercontrol.resources>
   <contextmenu x:key=”ListBoxItemContextMenu”>
      <menuitem header=”Action1″>
      <menuitem header=”Action2″>
   </menuitem></menuitem></contextmenu>
</usercontrol.resources>

If hosting the listbox in a window notice, that you have to use
<window.resources></window.resources>
instead of <usercontrol.resources></usercontrol.resources>

Now define an item template for the listbox so that we get a checked list box item. Add the template below the ContextMenu

<datatemplate x:key=”ListBoxItemTemplate”>
   <dockpanel contextmenu=”{StatisResource ListBoxItemContextMenu}”>
      &lt; CheckBox DockPanel.Dock=”Left” Margin=”5″ IsChecked=”{Binding Path=YourBooleanProperty, Mode=TwoWay}”/&gt;
      <label content=”{Binding Path=Name}” foreground=”Black” width=”Auto”>
   </label></dockpanel>
</datatemplate>

This makes the item have a white background and a black foreground. Instead of DockPanel a StackPanel with horizontal orientation can be used. One problem of this solution is, that the DockPanel or the Label does not seem to fill the whole width of the list box. One can recognize this fact since a right mouse click on the label does open the context menu, but when clicking outside the label (right of the label) nothing happens.

Now we already have a simple checked list box that uses a boolean property of your data objects presented in the list box and a Name property for the label.

When now selecting an item in the listbox the background becomes blue and the font remains black, that’s what we want to change next:

<datatemplate x:key=”ListBoxItemSelectedTemplate”>
            <dockpanel contextmenu=”{StaticResource ListBoxItemContextMenu}”>
                &lt; CheckBox DockPanel.Dock=”Left” Margin=”5″ IsChecked=”{Binding Path=YourBooleanProperty, Mode=TwoWay}”/>
                <label content=”{Binding Path=Name}” foreground=”White”>
            </label></dockpanel>
        </datatemplate>

Now we have two data templates that must be switched when an item of the list box gets selected. To solve this we use a style trigger.

<style targettype=”{x:Type ListBoxItem}” x:key=”CheckedListBoxStyle”>
            <setter Property=”ContentTemplate” Value=”{StaticResource ListBoxItemTemplate}”></Setter>
            <Style.Triggers>
                <trigger Property=”IsSelected” Value=”True”>
                    <setter Property=”ContentTemplate” Value=”{StaticResource ListBoxItemSelectedTemplate}”></Setter>
                </Trigger>
            </Style.Triggers>
      
</style>

Now the template of the item changes when the item gets selected and unselected.
To complete the process, we now set the listbox ContainerStyle to the CheckedListBoxStyle from above.

<listbox itemcontainerstyle=”{StaticResource CheckedListBoxStyle}” selectionmode=”Single”>
</listbox>