C# Listbox IsSynchronizedWithCurrentItem导致选择第一个项目,即使没有任何命令它这样做
我在wpf列表框中发现了一些可能是bug的东西。请看代码,然后我解释发生了什么 窗口C# Listbox IsSynchronizedWithCurrentItem导致选择第一个项目,即使没有任何命令它这样做,c#,wpf,xaml,combobox,listbox,C#,Wpf,Xaml,Combobox,Listbox,我在wpf列表框中发现了一些可能是bug的东西。请看代码,然后我解释发生了什么 窗口 <Window > <Grid> <local:MultiSelectionComboBox Width="200" MinHeight="25" HorizontalAlignment="Center"
<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>
用户控制
<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>
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);
}
}
全选
代码隐藏用户控件
<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>
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);
}
}
公共部分类MultiSelectionComboBox:ComboBox
{
#区域字段、依赖项、命令和构造函数
私有列表框列表框;
私有项控件项控件;
私有复选框;
public static readonly dependencProperty ASLSelectedItemsProperty=dependencProperty.Register(“ASLSelectedItems”、typeof(ObservableCollection)、typeof(MultiSelectionComboBox)、new PropertyMetadata(null));
公共静态只读DependencyProperty ASLDisplayMemberPathProperty=DependencyProperty.Register(“ASLDisplayMemberPath”、typeof(字符串)、typeof(多选组合框)、new PropertyMetadata(“说明”);
公共多选组合框()
{
初始化组件();
}
public DelegateCommand UnselectCommand{get;private set;}
public DelegateCommand CheckAllCommand{get;private set;}
公共可观测集合ASLSelectedItems
{
获取{return(observetecollection)GetValue(aslselecteditemsprroperty);}
set{SetValue(ASLSelectedItemsProperty,value);}
}
公共字符串ASLDisplayMemberPath
{
获取{return(string)GetValue(ASLDisplayMemberPathProperty);}
set{SetValue(asldisplaymberpathProperty,value);}
}
#端区
私有void CheckAll()
{
如果(checkBox.IsChecked==true)
{
listBox.SelectAll();
}
其他的
{
listBox.UnselectAll();
}
}
私有控件()
{
checkBox=Template.FindName(“checkBox”,this)作为复选框;
listBox=Template.FindName(“lstBox”,this)作为listBox;
itemsControl=Template.FindName(“itemsControl”,this)作为itemsControl;
}
私有布尔错误=真;
private void ListBoxOnSelectionChanged(对象发送者,选择ChangedEventArgs e)
{
e、 AddedItems.Cast().Where(item=>!ASLSelectedItems.Contains(item)).ForEach(p=>ASLSelectedItems.Add(p));
e、 RemovedItems.Cast().Where(item=>ASLSelectedItems.Contains(item)).ForEach(p=>ASLSelectedItems.Remove(p));
checkBox.IsChecked=(listBox.itemsource as IList).Count==listBox.SelectedItems.Count;
}
应用程序模板()上的公共重写无效
{
base.OnApplyTemplate();
GetControls();
SetControls();
UnselectCommand=newdelegateCommand(p=>listBox?.SelectedItems.Remove(p));
CheckAllCommand=新的DelegateCommand(CheckAll);
}
私有void SetControls()
{
listBox.DisplayMemberPath=ASLDisplayMemberPath;
itemsControl.DisplayMemberPath=ASLDisplayMemberPath;
}
私有无效测试\u已加载(对象发送器,路由目标e)
{
(发送方为TextBlock)?.SetBinding(TextBlock.TextProperty,ASLDisplayMemberPath);
}
}
视图模型
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() };
}
}
公共类MainWindowViewModel
{
公共可观测集合模型{get;set;}
公共ObservableCollection SelectedModels{get;set;}
公共主窗口视图模型()
{
模型=新的ObservableCollection()
{
新模型(){FirstName=“Amelia”,年龄=0},
新模型(){FirstName=“Bruno”,Age=5},
新模型(){FirstName=“Colin”,年龄=47},
新模型(){FirstName=“Daniel”,年龄=32},
新模型(){FirstName=“Iza”,Age=28},
新模型(){FirstName=“James”,年龄=23},
新模型(){FirstName=“Simon”,年龄=23}
};
SelectedModels=new ObservableCollection{Models.FirstOrDefault()};
}
}
现在的问题是,如果在用户控件内(列表