列表框IsSynchronizedWithCurrentItem导致第一项的选择,即使它没有告诉它做 [英] Listbox IsSynchronizedWithCurrentItem causes selection of the first item even though nothing its telling it to do it

查看:89
本文介绍了列表框IsSynchronizedWithCurrentItem导致第一项的选择,即使它没有告诉它做的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我碰到的东西,也许是错误的WPF列表框来了。请查看代码,然后我解释发生了什么。

I came across something that maybe a bug in wpf listbox. Please see the code and then I explain what happens

窗口

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



用户控制

User control

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



背后的用户控件代码

code behind user control

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);
    }
}



视图模型

view model

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() };
    }
}

现在的问题是,如果用户控制内部(其中,列表框的),如果我不设置同步到真实的,那么它将不会看到在启动的第一个项目,如果我这样做设置,以后的东西迫使添加到集合。然后就算里面选择孩子我不设置一个值,但仍然设置了第一个孩子的价值。

Now the problem is that if inside the user control (where the listbox is) if I don’t set synchronize to true, then it won’t see the first item on start-up, if I do set it, then something forces an add to the collection. And then even if inside selected children I don’t set a value, it still sets the value of the first child.

这实际上是多选组合框,得到了这么远,这一个简单的事情把我拦住了一天的一半。而且我找不到是什么原因造成的。

This is actually multiselect combobox, got so far and this one simple thing stopped me for half of the day. And I can't find what is causing it.

任何帮助,将不胜感激。

Any help would be appreciated

推荐答案

这将帮助我们如何理解时IsSynchronizedWithCurrentItem设置为true,列表框的行为。的链接

This will help us on how to understand how listbox behaves when IsSynchronizedWithCurrentItem is set to true. Link

由于您的要求,这应该是假的。

Given your requirement, this should be false.

您LisBox.SelectionChanged事件处理程序将被调用每次你设置的值来ASLSelectedItems时间。

Your LisBox.SelectionChanged event handler will be invoked every time you set the Values to ASLSelectedItems.

我觉得它将被工作:


  1. 从你的列表框(lstBox)删除处理程序

  2. 然后修改DP

  1. Remove your handler from your ListBox (lstBox).
  2. Then modify your DP

公共静态只读的DependencyProperty ASLSelectedItemsProperty = DependencyProperty.Register(ASLSelectedItems的typeof(的ObservableCollection<对象>)的typeof( MultiSelectionComboBox),新PropertyMetadata(NULL,OnSelectedItemsChanged));

私有静态无效OnSelectedItemsChanged(DependencyObject的D,DependencyPropertyChangedEventArgsê )
{
//从您的处理程序
加入你的逻辑}

这篇关于列表框IsSynchronizedWithCurrentItem导致第一项的选择,即使它没有告诉它做的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆