Я вижу странное поведение: у меня есть TreeViewItem, связанный с источником с несколькими строками:
<TreeViewItem Name="TreeViewItem1" >
<TreeViewItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding IP,FallbackValue=BindingError,Mode=TwoWay}" />
</DataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
Связанный во время выполнения с этим кодом:
TreeViewItem1.ItemsSource = MySource;
До сих пор он работает так, как ожидалось: скажем, у меня есть 2 строки на MySource - 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 строки: 2 из MySource с заполненными правильными значениями и еще один для добавления строк.
ПРОБЛЕМА: это то, что в этот момент TreeViewItem ТАКЖЕ получает 3d-ребенка, хотя MySource все еще имеет только 2. Это не имеет смысла, но то, что я вижу. Как если бы оба DatGrid и TreeViewItem были привязаны не к MySource, а к некоторой внутренней структуре, имитирующей ее, которая разделяется между двумя элементами управления.
Вероятно, это не имеет значения, но для записи MySource является ObservableCollection с каждым элементом, реализующим INotifyPropertyChanged, поэтому добавление/удаление строк, а также изменение значений для каждой строки должным образом обновляются на обоих элементах управления. Единственная проблема заключается в дополнительной строке в TreeViewItem.
Вы пытались установить:
CanUserAddRows="False"
К вашей сетке данных? Я всегда устанавливал это, а затем использовал кнопку для добавления строк в мои сетки данных. С моей точки зрения, это имеет смысл для наших бизнес-пользователей.
Если это не сработает для вас, вы также не можете привязать свои datagrid и treeview к одной и той же наблюдаемой коллекции, а затем сохранить синхронизируемую коллекцию дерева просмотра.
Другое Редактировать Это все еще не идеальное решение, но ваш вопрос вызвал мой интерес. Я все еще поклонник кнопок, нажимающих кнопки для добавления элементов;). Вот что я нашел.
Если я установил источник TreeViewItem в виде коллекции таким образом:
Окно 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 по аналогичной проблеме выглядят так, как будто мое второе решение выше.
Гай на форуме MSFT описывает проблему
Я всегда думал, что я порядочный в WPF, я понятия не имел...