当ComboBox离开可视树时,我注意到ComboBox.ItemsSource上的静态和动态资源之间存在行为差异。
绑定似乎没问题,因为当组合框处于焦点并且其SelectedIndex发生更改时,更改会正确通知另一个列表 - 两个对象都实现INotifyProperty - 并且两个List都是ObservableCollections。
当动态绑定的组合框失焦时,会发生奇怪的事情
XAML
<Window ... xmlns:me = "clr-namespace:WpfComboBoxBug">
<Window.Resources>
<me:ShippingList x:Key="sl" />
<me:DestinationList x:Key="dl" />
</Window.Resources>
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="21" />
<RowDefinition Height="421*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Custom:DataGrid Grid.Row="1"
ItemsSource="{StaticResource sl}" x:Name="dg" AutoGenerateColumns="False" Grid.RowSpan="2">
<Custom:DataGrid.Columns>
<Custom:DataGridTextColumn Header="Reference" Binding="{Binding Reference}" />
<Custom:DataGridTemplateColumn Header="Destination">
<Custom:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Destination.Name}"></TextBlock>
</DataTemplate>
</Custom:DataGridTemplateColumn.CellTemplate>
<Custom:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{StaticResource dl}" SelectedItem="{Binding Destination,Mode=TwoWay}" DisplayMemberPath="Name"/>
</DataTemplate>
</Custom:DataGridTemplateColumn.CellEditingTemplate>
</Custom:DataGridTemplateColumn>
</Custom:DataGrid.Columns>
</Custom:DataGrid>
<Custom:DataGrid Grid.Column="1" Grid.Row="1" ItemsSource="{StaticResource sl}" x:Name="dg2" AutoGenerateColumns="False" Grid.RowSpan="2">
<Custom:DataGrid.Columns>
<Custom:DataGridTextColumn Header="Reference" Binding="{Binding Reference}" />
<Custom:DataGridTemplateColumn Header="Destination">
<Custom:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Destination.Name}"></TextBlock>
</DataTemplate>
</Custom:DataGridTemplateColumn.CellTemplate>
<Custom:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{DynamicResource dynamicdl}" SelectedItem="{Binding Destination,Mode=TwoWay}" DisplayMemberPath="Name"/>
</DataTemplate>
</Custom:DataGridTemplateColumn.CellEditingTemplate>
</Custom:DataGridTemplateColumn>
</Custom:DataGrid.Columns>
</Custom:DataGrid>
<TextBox Height="23" Name="textBox1" VerticalAlignment="Top" Text="Static" />
<TextBox Height="23" Name="textBox2" VerticalAlignment="Top" Text="Dynamic" Grid.Column="2" />
</Grid>
</Window>
CS
using System;
/* snip */
namespace WpfComboBoxBug
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
ShippingList sl;
this.InitializeComponent();
sl = this.Resources["sl"] as ShippingList;
ResourceDictionary rd = new ResourceDictionary();
rd.Add("dynamicdl", this.FindResource("dl"));
dg2.Resources = rd;
dg.ItemsSource = CollectionViewSource.GetDefaultView(sl);
dg2.ItemsSource = CollectionViewSource.GetDefaultView(sl);
}
}
}
完整源代码:http://dl.free.fr/eI1VtkaB8(VS 2008 SP1,.NET 3.5 SP1)
我希望动态资源在这种情况下的行为类似于静态资源,因为我在开始时初始化它一次。
答案 0 :(得分:3)
我必须查看你的代码才能确定,但我猜你的ComboBox将其SelectedItem或SelectedValue双向绑定到一个属性。
使用StaticResource时,资源引用在XAML加载时解析。使用DynamicResource时,稍后将解析资源引用。所以可能发生的事情是你的ComboBox没有启动任何项目,这会强制其SelectedItem和SelectedValue为null。双向绑定会导致属性使用此值进行更新。
我个人认为ComboBox无法优雅地处理这种情况是ComboBox设计中的一个错误,而不是实现错误。
对于我自己的项目,我经常使用我创建的ComboBox和ListBox增强来解决这个问题:我可以使用其他属性来代替SelectedValue和SelectedItems。我的新属性接受任何值,直到设置ItemsSource,之后它与SelectedValue或SelectedItem保持同步。
您可以使用类似的技术,或者只是始终确保在SelectedValue或SelectedItem之前绑定/初始化ItemsSource。
<强>更新强>
当从可视树中删除控件时,一切都反过来:由于祖先的更改,ItemsSource立即被清除,然后DataContext被清除。在此期间,ComboBox有一个null SelectedItem,它传播到绑定属性。
具有额外SelectedItem和SelectedValue属性的增强型ComboBox或ListBox类也可以解决这个问题:每当ItemsSource为非null时,它应使SelectedItem / SelecteValue与自定义属性保持同步,并在ItemsSource为null时将它们分离。