简体   繁体   中英

How to bind label text placed inside a split Button Content with the selected List box item?

I am trying to create a drop-down like control using WPF split button. I can get drop down working but what I want to achieve next is that if a user select an item from dropdown menu, that text is updated as split Button Content. Also, By default when this control is loaded, first item name is set to split button content.

My preference is to do it in xaml itself.

Here's existing code:

<userControls:BaseUserControl x:Class="UserControls.TestControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"              
         xmlns:userControls="clr-namespace:MainAssembly.UserControls"
         xmlns:const="clr-namespace:MainAssembly.const"
         xmlns:toolkit="abc/Wpf.Toolkit"
         xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">

<userControls:BaseUserControl.Resources>
    <ResourceDictionary>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
        <toolkit:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
        <toolkit:MultiValueToObjectArrayConverter x:Key="MultiValueToObjectArrayConverter" />
        <toolkit:BoolToInvertedBoolToVisibilityConverter x:Key="BoolToInvertedBoolToVisibilityConverter" />
    </ResourceDictionary>
</userControls:BaseUserControl.Resources>

<xctk:SplitButton Name="TestSplitBtn" ToolBar.OverflowMode="AsNeeded"
                                          Margin="5,1,5,1"
                                          >
    <xctk:SplitButton.DropDownContent>
        <ListBox Name="DropDownMenu" Margin="5,1,5,5"
                                  ItemsSource="{Binding DropDownContentCollection}"
                                  ToolBar.OverflowMode="AsNeeded"                                                                        
                                  Visibility="{Binding DropDownContentCollection, Converter={StaticResource NullToVisibilityConverter}}"
                                  ToolTip="{x:Static const:const.toolTip}"
                                      MaxWidth="150">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Button Style="{DynamicResource TransparentButton}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Left" Command="{Binding DataContext.TestCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBox}}}" CommandParameter="{Binding}">
                        <Button.Content>
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
                                <Rectangle Fill="{DynamicResource Icon_Test}" Margin="4,0,5,0" Height="16" Width="16" />
                                <TextBlock HorizontalAlignment="Left" VerticalAlignment="Center">
                                    <TextBlock.Text>
                                        <MultiBinding StringFormat="{} {0}({1})">
                                            <Binding Path="Name" />
                                            <Binding Path="ImageCount" />
                                        </MultiBinding>
                                    </TextBlock.Text>
                                </TextBlock>
                            </StackPanel>
                        </Button.Content>
                    </Button>
                </DataTemplate>
            </ListBox.ItemTemplate>
            <ListBox.Style>
                <Style TargetType="{x:Type ListBox}" BasedOn="{StaticResource ListBoxStyle}">
                    <Setter Property="ItemContainerStyle">
                        <Setter.Value>
                            <Style TargetType="ListBoxItem">
                                <Setter Property="AutomationProperties.AutomationId" Value="{Binding Name}"/>
                            </Style>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListBox.Style>
        </ListBox>
    </xctk:SplitButton.DropDownContent>

    <xctk:SplitButton.Content>
        <toolkit:LabelledButton x:Name="TestSeries"
                                                        AutomationProperties.AutomationId="TestBtn"
                                                        CommandParameter="{Binding ViewerState}" Margin="0,1,0,0" Height="56">
            <toolkit:LabelledButton.Content>
                <Rectangle Fill="{DynamicResource Icon_Test}" Margin="0,2,0,-5"/>

            </toolkit:LabelledButton.Content>
            <toolkit:LabelledButton.Style>
                <Style TargetType="{x:Type toolkit:LabelledButton}" BasedOn="{StaticResource {x:Type toolkit:LabelledButton}}">
                    <Setter Property="LabelText" Value="{Binding SelectedImageSeries, Mode=TwoWay}" />
                    <Setter Property="ToolTip" Value="{Binding SelectedImageSeries, Mode=TwoWay}" />
                </Style>
            </toolkit:LabelledButton.Style>
        </toolkit:LabelledButton>
    </xctk:SplitButton.Content>

    <xctk:SplitButton.Style>
        <Style TargetType="{x:Type xctk:SplitButton}" BasedOn="{StaticResource TestSplitButtonStyle}">
            <Setter Property="Visibility" Value="Visible"/>
        </Style>
    </xctk:SplitButton.Style>
</xctk:SplitButton>

Also, when I click on the button, It execute the command associated but dropdown menu doesn't get closed.

You also have to bind the ListBox.SelectedItem property to SelectedImageSeries .

It looks like your are using the SplitButton too complicated. I've posted a simplified solution. Since we are now properly binding the SelectedImageSeries item from the ListBox , there is no need to add a Button to the DataTemplate of the ListBoxItem .
Instead of executing the TestCommand , you can handle the selected item directly in the property setter. I have added a method OnSelectedImageSeriesChanged to the view model for this purpose.

There is also no need to add another button ( LabelButton ) nested into the SplitButton.Content . You can modify the content layout by assigning a DataTemplate to SplitButton.ContentTemplate and bind a ICommand to the SplitButton.Command property and optionally use SplitButton.CommandParameter .

BindingMode.TwoWay is only required when you send back data to the data source. It's redundant in every place you have used it: LabelText and ToolTip never send data (they can't). Most of the properties that can send data as they are reflecting user input are binding TwoWay by default eg, TextBox.Text , ListBox.SelectedItem , ToggleButton.IsChecked etc.

View Model

class MainViewModel
{
  public ObservableCollection<ImageSeries> DropDownContentCollection { get; }

  private ImageSeries selectedImageSeries;   
  public ImageSeries SelectedImageSeries
  {
    get => this.selectedImageSeries;
    set 
    { 
      this.selectedImageSeries = value; 
      OnPropertyChanged();

      // Handle ListBox item selected. Replaces command.
      OnSelectedImageSeriesChanged();
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;
  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

SplitButton

<xctk:SplitButton Width="100" 
                  Content="{Binding SelectedImageSeries}"
                  Command="{Binding HandleButtonPressedCommand}"
                  CommandParameter="{Binding ViewerState}">
  <xctk:SplitButton.ContentTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding}" />
        <Rectangle Fill="{DynamicResource Icon_Test}" Width="20" Height="20" />
      </StackPanel>
    </DataTemplate>
  </xctk:SplitButton.ContentTemplate>
  <xctk:SplitButton.DropDownContent>
    <ListBox ItemsSource="{Binding DropDownContentCollection}" SelectedItem="{Binding SelectedImageSeries}" />
  </xctk:SplitButton.DropDownContent>
</xctk:SplitButton>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM