Listbox IsSynchronizedWithCurrentItem导致选择第一个项目,即使它没有告诉它这样做

adm*_*tDK 9 c# wpf xaml combobox listbox

我遇到了一些可能是wpf列表框中的错误的东西.请查看代码然后我解释会发生什么

窗口

<Window >
<Grid>
    <local:MultiSelectionComboBox Width="200"
                                  MinHeight="25"
                                  HorizontalAlignment="Center"
                                  VerticalAlignment="Center"
                                  ASLDisplayMemberPath="FirstName"
                                  ASLSelectedItems="{Binding SelectedModels}"
                                  ItemsSource="{Binding Models}" />
    <ListBox HorizontalAlignment="Right"
             VerticalAlignment="Top"
             DisplayMemberPath="FirstName"
             ItemsSource="{Binding SelectedModels}" />
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

用户控制

<ComboBox>
<ComboBox.Style>
    <Style TargetType="{x:Type ComboBox}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ComboBox}">
                    <Grid x:Name="MainGrid"
                          Width="Auto"
                          Height="Auto"
                          SnapsToDevicePixels="true">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="0" />
                        </Grid.ColumnDefinitions>
                        <Popup x:Name="PART_Popup"
                               Grid.ColumnSpan="2"
                               Margin="1"
                               AllowsTransparency="true"
                               IsOpen="{Binding Path=IsDropDownOpen,
                                                RelativeSource={RelativeSource TemplatedParent}}"
                               Placement="Center"
                               PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}">
                            <Border x:Name="DropDownBorder"
                                    MinWidth="{Binding Path=ActualWidth,
                                                       ElementName=MainGrid}"
                                    MaxHeight="{TemplateBinding MaxDropDownHeight}">
                                <ScrollViewer CanContentScroll="true">
                                    <StackPanel>
                                        <CheckBox x:Name="checkBox" 
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ComboBox}, Path=CheckAllCommand}">select all</CheckBox>
                                        <ListBox x:Name="lstBox"
here lies the problem without the line below I dont get to see the result on start up,
with the it selects the first item even if nothing is triggering it
                                                 IsSynchronizedWithCurrentItem="True"
                                                 ItemsSource="{TemplateBinding ItemsSource}"
                                                 KeyboardNavigation.DirectionalNavigation="Contained"
                                                 SelectionChanged="ListBoxOnSelectionChanged"
                                                 SelectionMode="Multiple"
                                                 SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                    </StackPanel>
                                </ScrollViewer>
                            </Border>
                        </Popup>
                        <ToggleButton Grid.ColumnSpan="2"
                                      MinWidth="20"
                                      HorizontalAlignment="Right"
                                      Background="{TemplateBinding Background}"
                                      BorderBrush="{TemplateBinding BorderBrush}"
                                      IsChecked="{Binding Path=IsDropDownOpen,
                                                          Mode=TwoWay,
                                                          RelativeSource={RelativeSource TemplatedParent}}"
                                      Style="{DynamicResource ToggleButtonStyle1}" />
                        <ItemsControl x:Name="itemsControl"
                                      Margin="4,2,0,2"
                                      ItemsSource="{Binding Path=SelectedItems,
                                                            ElementName=lstBox}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel IsItemsHost="True" Orientation="Horizontal" />
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Border Margin="1"
                                            HorizontalAlignment="Left"
                                            VerticalAlignment="Top"
                                            Background="#383838"
                                            CornerRadius="2"
                                            Padding="5,2,3,2">
                                        <StackPanel Orientation="Horizontal">
                                            <TextBlock x:Name="Test"
                                                       Foreground="White"
                                                       Loaded="Test_OnLoaded"
                                                       Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
                                                                                                     AncestorType={x:Type ComboBox}},
                                                                      Path=ASLDisplayMemberPathActualValue}" />
                                            <Button Width="12"
                                                    Height="12"
                                                    Margin="5,0,0,0"
                                                    Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
                                                                                                     AncestorType=ComboBox},
                                                                      Path=UnselectCommand}"
                                                    CommandParameter="{Binding}">
                                                <Button.Template>
                                                    <ControlTemplate TargetType="{x:Type Button}">
                                                        <Grid>
                                                            <Ellipse x:Name="PART_ButtonBackground"
                                                                     Fill="White"
                                                                     Opacity="0" />
                                                            <TextBlock x:Name="PART_Text"
                                                                       Margin="0,0,0,1"
                                                                       HorizontalAlignment="Center"
                                                                       VerticalAlignment="Center"
                                                                       FontSize="10"
                                                                       Foreground="White"
                                                                       Text="X" />
                                                        </Grid>
                                                        <ControlTemplate.Triggers>
                                                            <Trigger Property="IsMouseOver" Value="True">
                                                                <Setter TargetName="PART_ButtonBackground" Property="Opacity" Value="0.8" />
                                                                <Setter TargetName="PART_Text" Property="Foreground" Value="Black" />
                                                            </Trigger>
                                                        </ControlTemplate.Triggers>
                                                    </ControlTemplate>
                                                </Button.Template>
                                            </Button>
                                        </StackPanel>
                                    </Border>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ComboBox.Style>
</ComboBox>
Run Code Online (Sandbox Code Playgroud)

用户控制背后的代码

public partial class MultiSelectionComboBox : ComboBox
{
    #region fields, dependencies, command and constructor
    private ListBox listBox;
    private ItemsControl itemsControl;
    private CheckBox checkBox;

    public static readonly DependencyProperty ASLSelectedItemsProperty = DependencyProperty.Register("ASLSelectedItems", typeof(ObservableCollection<object>), typeof(MultiSelectionComboBox), new PropertyMetadata(null));
    public static readonly DependencyProperty ASLDisplayMemberPathProperty = DependencyProperty.Register("ASLDisplayMemberPath", typeof(string), typeof(MultiSelectionComboBox), new PropertyMetadata("Description"));

    public MultiSelectionComboBox()
    {
        InitializeComponent();
    }

    public DelegateCommand<object> UnselectCommand { get; private set; }
    public DelegateCommand CheckAllCommand { get; private set; }

    public ObservableCollection<object> ASLSelectedItems
    {
        get { return (ObservableCollection<object>)GetValue(ASLSelectedItemsProperty); }
        set { SetValue(ASLSelectedItemsProperty, value); }
    }

    public string ASLDisplayMemberPath
    {
        get { return (string)GetValue(ASLDisplayMemberPathProperty); }
        set { SetValue(ASLDisplayMemberPathProperty, value); }
    }
    #endregion

    private void CheckAll()
    {
        if (checkBox.IsChecked == true)
        {
            listBox.SelectAll();

        }
        else
        {
            listBox.UnselectAll();
        }
    }

    private void GetControls()
    {
        checkBox = Template.FindName("checkBox", this) as CheckBox;
        listBox = Template.FindName("lstBox", this) as ListBox;
        itemsControl = Template.FindName("itemsControl", this) as ItemsControl;
    }

    private bool bug = true;
    private void ListBoxOnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        e.AddedItems.Cast<object>().Where(item => !ASLSelectedItems.Contains(item)).ForEach(p => ASLSelectedItems.Add(p));
        e.RemovedItems.Cast<object>().Where(item => ASLSelectedItems.Contains(item)).ForEach(p => ASLSelectedItems.Remove(p));
        checkBox.IsChecked = (listBox.ItemsSource as IList).Count == listBox.SelectedItems.Count;
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        GetControls();
        SetControls();
        UnselectCommand = new DelegateCommand<object>(p => listBox?.SelectedItems.Remove(p));
        CheckAllCommand = new DelegateCommand(CheckAll);
    }

    private void SetControls()
    {
        listBox.DisplayMemberPath = ASLDisplayMemberPath;
        itemsControl.DisplayMemberPath = ASLDisplayMemberPath;
    }

    private void Test_OnLoaded(object sender, RoutedEventArgs e)
    {
        (sender as TextBlock)?.SetBinding(TextBlock.TextProperty, ASLDisplayMemberPath);
    }
}
Run Code Online (Sandbox Code Playgroud)

查看模型

public class MainWindowViewModel
{
    public ObservableCollection<Model> Models { get; set; }
    public ObservableCollection<object> SelectedModels { get; set; }

    public MainWindowViewModel()
    {
        Models = new ObservableCollection<Model>()
        {
            new Model() {FirstName = "Amelia", Age = 0},
            new Model() {FirstName = "Bruno", Age = 5},
            new Model() {FirstName = "Colin", Age = 47},
            new Model() {FirstName = "Daniel", Age = 32},
            new Model() {FirstName = "Iza", Age = 28},
            new Model() {FirstName = "James", Age = 23},
            new Model() {FirstName = "Simon", Age = 23}
        };
        SelectedModels = new ObservableCollection<object> {Models.FirstOrDefault() };
    }
}
Run Code Online (Sandbox Code Playgroud)

现在的问题是,如果我在用户控件(列表框所在的位置)内部,如果我没有将synchronize设置为true,那么它将不会在启动时看到第一个项目,如果我设置它,那么就会强制添加到集合中.然后,即使在选定的孩子中我没有设置值,它仍然设置第一个孩子的值.

这实际上是多选组合框,到目前为止,这一个简单的事情让我停止了半天.我无法找到导致它的原因.

任何帮助,将不胜感激

tgp*_*dyk 3

这将帮助我们了解当 IsSynchronizedWithCurrentItem 设置为 true 时列表框的行为方式。关联

根据您的要求,这应该是错误的。

每次将值设置为 ASLSelectedItems 时,都会调用 LisBox.SelectionChanged 事件处理程序。

我认为它将通过以下方式起作用:

  1. 从列表框 (lstBox) 中删除处理程序。
  2. 然后修改你的DP

    public static readonly DependencyProperty ASLSelectedItemsProperty = DependencyProperty.Register("ASLSelectedItems", typeof(ObservableCollection<object>), typeof(MultiSelectionComboBox), new PropertyMetadata(null, OnSelectedItemsChanged));

    private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // Add your logic from your handler }