c# – WPF不绑定ComboBox SelectedItem
我已经广泛搜索,但我找不到任何解决方案.
我在我的项目中有几个ComboBox,我正在寻找一个自动完成解决方案,然后我发现了一个很好的并应用于我的项目,我将解决方案的样式也应用到我项目中的所有ComboBox. 在那之后,SelectedItem停止了工作,有人可以帮助我吗? 我的组合框: <ComboBox Name="CbOwnerType" Grid.Column="1" Grid.Row="2" ItemsSource="{Binding Path=OwnerTypes,Mode=OneWay}" SelectedItem="{Binding Owner.OwnerType,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="Id" DisplayMemberPath="Name" Margin="5,10,0" /> 我的风格: <Style TargetType="{x:Type ComboBox}"> <Setter Property="FocusVisualStyle" Value="{x:Null}" /> <Setter Property="Foreground" Value="Black" /> <Setter Property="FontWeight" Value="ExtraBold" /> <Setter Property="IsEditable" Value="False"/> <Setter Property="IsSynchronizedWithCurrentItem" Value="False" /> <Setter Property="StaysOpenOnEdit" Value="True" /> <Setter Property="SnapsToDevicePixels" Value="True"/> <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/> <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/> <Setter Property="ScrollViewer.CanContentScroll" Value="true"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ComboBox}"> <Grid> <ToggleButton Name="ToggleButton" Template="{StaticResource ComboBoxToggleButton}" Grid.Column="2" Focusable="True" IsChecked="{Binding Path=IsDropDownOpen,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" BorderThickness="0" /> <ContentPresenter Name="ContentSite" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Margin="5,20,0" VerticalAlignment="Center" HorizontalAlignment="Left" /> <TextBox x:Name="PART_EditableTextBox" Style="{x:Null}" Template="{StaticResource ComboBoxTextBox}" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="3,3,23,3" Focusable="True" Background="Transparent" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}" /> <Popup Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide"> <Themes:SystemDropShadowChrome Margin="4,6,4,6" CornerRadius="4"> <Grid Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}"> <Border x:Name="DropDownBorder" Background="{StaticResource WindowBackgroundBrush}" BorderThickness="1" BorderBrush="{StaticResource SolidBorderBrush}" /> <ScrollViewer Margin="4,6" SnapsToDevicePixels="True"> <ItemsPresenter /> </ScrollViewer> </Grid> </Themes:SystemDropShadowChrome> </Popup> </Grid> <ControlTemplate.Triggers> <Trigger Property="HasItems" Value="false"> <Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/> </Trigger> <Trigger Property="IsGrouping" Value="true"> <Setter Property="ScrollViewer.CanContentScroll" Value="false"/> </Trigger> <Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true"> <Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/> <Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> UPDATE 我的ToggleButton <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}" > <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition Width="20" /> </Grid.ColumnDefinitions> <Border x:Name="Border" Grid.ColumnSpan="2" BorderBrush="{StaticResource LabPetsStandardColor}" BorderThickness="1" CornerRadius="5" /> <Border Grid.Column="0" Margin="1" Background="Transparent" BorderBrush="{StaticResource NormalBorderBrush}" BorderThickness="0" CornerRadius="5,5" /> <Path x:Name="Arrow" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z"> <Path.Fill> <SolidColorBrush Color="Black" /> </Path.Fill> </Path> </Grid> <ControlTemplate.Triggers> <Trigger Property="ToggleButton.IsMouSEOver" Value="true"> <Setter TargetName="Border" Property="Background" Value="{StaticResource LabPetsStandardColor}" /> </Trigger> <Trigger Property="ToggleButton.IsChecked" Value="true"> <Setter TargetName="Border" Property="Background" Value="{StaticResource LabPetsPressedStandardColor}" /> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" /> <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" /> <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/> <Setter TargetName="Arrow" Property="Fill" Value="{StaticResource DisabledForegroundBrush}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> 我的TextBox <Style x:Key="ComboBoxTextBox" TargetType="{x:Type TextBox}"> <Setter Property="OverridesDefaultStyle" Value="True" /> <Setter Property="AllowDrop" Value="True" /> <Setter Property="MinWidth" Value="0" /> <Setter Property="MinHeight" Value="0" /> <Setter Property="FocusVisualStyle" Value="{x:Null}" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TextBox}"> <ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" Background="#00FFFFFF" Name="PART_ContentHost" Focusable="False" VerticalAlignment="Center" VerticalContentAlignment="Center" Margin="0"> <ScrollViewer.Style> <Style TargetType="ScrollViewer"> <Setter Property="OverridesDefaultStyle" Value="True" /> </Style> </ScrollViewer.Style> </ScrollViewer> </ControlTemplate> </Setter.Value> </Setter> </Style> 请帮助我一些? 更新2 找到了一个黑客,不是完美的解决方案,而是一种有效的工作…… 如果我插入属性SelectedValue和值Owner.OwnerTypeId,它就像一个魅力…但是,这是正确的吗? 我的Combobox现在: <ComboBox Name="CbOwnerType" Grid.Column="1" Grid.Row="2" ItemsSource="{Binding Path=OwnerTypes,Mode=OneWay}" SelectedItem="{Binding Owner.OwnerType}" SelectedValue="{Binding Owner.OwnerTypeId}" SelectedValuePath="Id" DisplayMemberPath="Name" Margin="5,0" /> 这是一个解决方案,不是我喜欢它,但它是一个解决方案…… Obs.:当我更改选择时,SelectedItem工作,只是在我加载视图时不起作用. 更新3 好吧,它像我说的那样工作,但问题是WPF在我的ViewModel上打了4次,所以我改变了我的ComboBox: <ComboBox Name="CbOwnerType" Grid.Column="1" Grid.Row="2" ItemsSource="{Binding Path=OwnerTypes,Mode=OneWay}" SelectedItem="{Binding Owner.OwnerType}" SelectedValue="{Binding Owner.OwnerTypeId,Mode=OneTime}" SelectedValuePath="Id" DisplayMemberPath="Name" Margin="5,0" /> 所以,现在,WPF只搜索OwnerTypeId,当我更改项目时,WPF只会命中2次. 更新4 好的,另一个奇怪的发现…… 更新5 对不起,我忘记发布我的模特了. 型号所有者: public class Owner { public int Id { get; set; } public int OwnerTypeId { get; set; } public string Name { get; set; } public string Address { get; set; } public string FormatedPhone { get { if (this.Phone == null) return string.Empty; switch (this.Phone.Length) { case 11: return Regex.Replace(this.Phone,@"(d{2})(d{4})(d{4})","($1) $2-$3"); case 12: return Regex.Replace(this.Phone,@"(d{2})(d{5})(d{4})","($1) $2-$3"); default: return this.Phone; } } } public string Phone { get; set; } public string CellPhone { get; set; } public string FormatedCellPhone { get { if (this.CellPhone == null) return string.Empty; switch (this.CellPhone.Length) { case 11: return Regex.Replace(this.Phone,"($1) $2-$3"); default: return this.CellPhone; } } } public string Email { get; set; } public virtual OwnerType OwnerType { get; set; } public virtual ICollection<Animal> Animals { get; set; } public Owner() { this.OwnerType = new OwnerType(); this.Animals = new List<Animal>(); this.ErrorList = new StringBuilder(); } 型号所有者类型: public class OwnerType { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Owner> Owners { get; set; } public OwnerType() { this.Owners = new List<Owner>(); } } 解决方法
您的SelectedItem绑定不起作用,因为WPF通过.Equals()方法将SelectedItem与ItemsSource中的项进行比较,默认情况下,通过引用进行比较.包含SelectedItem的内存中的实例与ItemsSource中的项目之一在内存中不是同一个实例
有3种方法可以解决这个问题. >首先,您已经发现可以将SelectedValue绑定到项目的值类型属性,并设置SelectedValuePath. <ComboBox ItemsSource="{Binding Path=OwnerTypes}" SelectedValue="{Binding Owner.OwnerTypeId}" SelectedValuePath="Id" DisplayMemberPath="Name" /> 这通常是我使用的解决方案,因为它通常是最简单的 public class Owner() { public int OwnerTypeId { get; set; } public OwnerType OwnerType { get { return StaticClass.OwnerTypes .FirstOrDefault(p => p.Id == this.OwnerTypeId); } set { if (value != null) OwnerTypeId = value.Id; } } } >最后,您可以覆盖OwnerType对象上的.Equals()方法,以便在Id属性相同时将两个值视为相等. public override bool Equals(object obj) { if (obj == null || !(obj is OwnerType)) return false; return ((OwnerType)obj).Id == this.Id); } 我通常会尝试避免使用此方法,除非我知道我总是希望仅通过Id属性来比较此对象的相等性,但有时这是最好的方法. 此外,每当你覆盖.Equals()时,它的优良做法是覆盖.GetHashCode(). 作为旁注,您通常不希望绑定SelectedItem和SelectedValue.它们是设置相同内容的两种不同方式,您可以通过绑定它们来获得意外结果. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |