Combobox.ItemsSource上的StaticResource vs DynamicResource行为

时间:2010-03-03 11:21:10

标签: wpf dynamic static combobox

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

我希望动态资源在这种情况下的行为类似于静态资源,因为我在开始时初始化它一次。

  • 我在这里发现了一个错误吗?
  • 如果不是这样,你会如何解释其中的差异?

1 个答案:

答案 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时将它们分离。