WPF ItemSsource DataGrid TreeViewItem额外的行错误

时间:2014-05-20 19:22:21

标签: c# wpf datagrid treeviewitem

我看到一个奇怪的行为:我有一个TreeViewItem绑定到具有多行的源,如下所示:

<TreeViewItem Name="TreeViewItem1" >                                    
    <TreeViewItem.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding IP,FallbackValue=BindingError,Mode=TwoWay}" />
        </DataTemplate>
    </TreeViewItem.ItemTemplate>
</TreeViewItem>

使用此代码在运行时绑定:

TreeViewItem1.ItemsSource = MySource;

到目前为止,它按预期工作:假设我在MySource中有2行 - TreeViewItem显示2个子节点,其中填入了正确的值。 然后我以类似的方式将DataGrid绑定到同一个源:

<DataGrid Grid.Row="0" Name="MyDataGrid" AutoGenerateColumns="False" CanUserDeleteRows="True" >
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="IP" Binding="{Binding IP}" Header="IP" />
        <DataGridTextColumn x:Name="Port" Binding="{Binding Port}" Header="Port" />
    </DataGrid.Columns>
</DataGrid>

代码隐藏

MyDataGrid.Items.Clear();
MyDataGrid.ItemsSource = MySource;

DataGird有3行:来自MySource的2行,填写了正确的值,还有一行用于添加行。

问题:就在那时,TreeViewItem也获得了一个3d孩子,即使MySource仍然只有2个。这没有任何意义,但这就是我所看到的。好像DatGrid和TreeViewItem都不是绑定到MySource,而是绑定到两个控件之间共享的模仿它的内部结构。

可能不相关,但是对于记录MySource是一个ObservableCollection,每个元素都实现了INotifyPropertyChanged,因此在两个控件上正确更新了添加/删除行以及更改每行的值。唯一的问题是TreeViewItem中的额外行。

1 个答案:

答案 0 :(得分:0)

您是否尝试过设置:

CanUserAddRows="False"

到您的数据网格?我总是设置它,然后使用一个按钮向我的数据网格添加行。从我的角度来看,这对我们的业务用户更有意义。

如果这对您不起作用,您也可以不将datagrid和treeview绑定到同一个可观察集合,然后保持树视图可观察集合同步。

另一个编辑 这仍然不是一个完美的解决方案,但你的问题激起了我的兴趣。我仍然是用户点击按钮添加项目的粉丝;)。这是我发现的。

如果我将TreeViewItem源设置为集合视图,如下所示:

Window Xaml:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" Background="Red" >
<Window.Resources>
            <CollectionViewSource x:Key="TreeViewCollection" Source="{Binding AllRoles, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/>
</Window.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="57*"/>
        <RowDefinition Height="125*"/>
        <RowDefinition Height="138*"/>
    </Grid.RowDefinitions>
    <TreeViewItem Name="TreeViewItem1" Background="White" Grid.RowSpan="3" IsExpanded="True" ItemsSource="{Binding Source ={StaticResource TreeViewCollection}}">
        <TreeViewItem.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding ip,FallbackValue=BindingError,Mode=TwoWay}" />
            </DataTemplate>
        </TreeViewItem.ItemTemplate>
    </TreeViewItem>
    <DataGrid Grid.Row="2" Name="MyDataGrid" AutoGenerateColumns="False" CanUserDeleteRows="True" CanUserAddRows="True"
              ItemsSource="{Binding AllRoles, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}">
        <DataGrid.Columns>
            <DataGridTextColumn x:Name="IP" Binding="{Binding ip}" Header="IP" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

代码背后:

namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public ObservableCollection<Role> AllRoles { get; private set; }

    public MainWindow()
    {
        this.InitializeComponent();
        var allRoles = new ObservableCollection<Role>();
        allRoles.Add(new Role{ip = "bob"});
        allRoles.Add(new Role{ip = "john"});
        this.AllRoles = allRoles;

        TreeViewItemSource = GetNonsCollectionView(allRoles);
    }

    public CollectionView DataGridViewSource { get; private set; }
    public CollectionView TreeViewItemSource { get; private set; }

    public CollectionView GetNonsCollectionView(ObservableCollection<Role> nonsList)
    {
        return (CollectionView)CollectionViewSource.GetDefaultView(nonsList);
    }
}

public class Role : INotifyPropertyChanged
{
    public string ip { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

}

你会看到这个工作。我目前看到的问题是当用户通过设置焦点向网格添加新行时更新集合视图。我累了,否则我会深入研究。

以下是我在此过程中发现的一些链接。

MSFT Employee Comments on similar issue似乎我上面的第二个解决方案是她的。

Guy on MSFT forum describes issue

我一直以为我在WPF上很体面,我没有线索......