如何获取几个数据网格的SelectedItem?

时间:2017-03-01 15:15:41

标签: wpf binding datagrid mvvm-light

Foreach treeview-item我有一个自己的数据网格。 Treeview-items和datagrids由绑定填充。

在文本框中,我获得了对datagrids的选定项的绑定。但是这些文本框上的绑定仅适用于第一个数据网格。每个其他数据网格都不会将selecteditem传输到文本框:

wrong binding

以下是datagrid的树视图:

            <TreeView ItemsSource="{Binding Path=PlaceList}">
                <TreeView.ItemTemplate>
                    <DataTemplate>
                        <TreeViewItem Header="{Binding Path=Name}">
                            <DataGrid ItemsSource="{Binding MachinesInPlace, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                      SelectionUnit="FullRow"
                                      SelectedItem="{Binding SelectedMachine, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                      AutoGenerateColumns="True"
                                      IsSynchronizedWithCurrentItem="True"
                                      SelectionMode="Single">
                            </DataGrid>
                        </TreeViewItem>
                    </DataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>

这是文本框:

<TextBox Text="{Binding PlaceList/SelectedMachine.Name, ValidatesOnDataErrors=True}" />

我正在使用MvvmLight。我的ViewModel保存PlaceList:

    public ObservableCollection<PlaceModel> PlaceList { get; set; } = new ObservableCollection<PlaceModel>();

    public ObjectInspectorViewModel()
    {
        PlaceList = PlaceModel.GetPlaces(BaseResourcePaths.PlacesCsv);
    }

那是我的地方模特:

public class PlaceModel
{
    public int Id { get; set; }
    public string Name { get; set; } = "_CurrentObjectName";
    public string Length { get; set; }
    public string Width { get; set; }
    public string Height { get; set; }
    public ObservableCollection<MachineModel> MachinesInPlace { get; set; }
    public MachineModel SelectedMachine { get; set; }

    public static ObservableCollection<PlaceModel> GetPlaces(string filepath)
    {
        [...]
    }
}

我尝试了一些东西,但最后我不知道如何解决这个问题。有什么问题?我的建议是地方模型中的''SelectedMachine'属性......

这是一个示例项目(使用Sebastian Richter的附加解决方案)。它显示了问题:https://www.file-upload.net/download-12370581/DatagridTreeViewError.zip.html

1 个答案:

答案 0 :(得分:1)

我很安静,确保您忘记在班级INotifyPropertyChanged中实施PlaceModel。问题是在您更改选择后,将更新属性Placemodel.SelectedMachine,但不会触发任何事件来在视图中填充此更改。

因为您使用MVVM Light,所以您可以从已经实现此接口的ObservableObject 派生。 因此,请将PlaceModel更改为以下代码:

public class PlaceModel : ObservableObject
{
    private MachineModel _selectedMachine;
    public int Id { get; set; }
    public string Name { get; set; } = "_CurrentObjectName";
    public string Length { get; set; }
    public string Width { get; set; }
    public string Height { get; set; }
    public ObservableCollection<MachineModel> MachinesInPlace { get; set; }

    public MachineModel SelectedMachine
    {
        get
        {
            return _selectedMachine;
        }

        set
        {
            // raises Event PropertyChanged after setting value
            Set(ref _selectedMachine, value);
        }
    }

    public static ObservableCollection<PlaceModel> GetPlaces(string filepath)
    {
    [...]
}

修改

我猜绑定不知道要绑定到哪个元素ObservableCollection(多对一关系),因为您将其设置为TextBox中的引用。

因此,请尝试从模型中删除SelectedMachine属性并将其添加回ViewModel:

class ViewModel : ViewModelBase
{
     ...
     private MachineModel _selectedMachine;
     public MachineModel SelectedMachine
     {
        get
        {
            return _selectedMachine;
        }
        set
        {
        // raises Event PropertyChanged after setting value
        Set(ref _selectedMachine, value);
        }
    }
    ...
}

同时将您的XAML更改为以下代码(我使用了您的示例项目):

<Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
        <RowDefinition Height="2*"></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>

    <!-- Row #1 -->
    <Grid>
        <!-- TreeView und DataGrids-->
        <TreeView ItemsSource="{Binding Path=PlaceList}">
            <TreeView.ItemTemplate>
                <DataTemplate>
                    <TreeViewItem Header="{Binding Path=Name}">
                        <DataGrid ItemsSource="{Binding MachinesInPlace, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                  SelectedItem="{Binding DataContext.SelectedMachine, RelativeSource={RelativeSource AncestorType=Window},Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                    </TreeViewItem>
                </DataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>

    <!-- Row #2 -->
    <Grid Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition Width="2*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>

        <Label Grid.Row="0"
               Content="ID" />
        <!-- Textboxen aktualisieren nur bei Auswahl der ersten Datagrid -->
        <TextBox Grid.Column="2"
                 Grid.Row="0"
                 Text="{Binding SelectedMachine.Id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        <Label Grid.Row="1"
               Content="Name" />
        <TextBox Grid.Column="2"
                 Grid.Row="1"
                 Text="{Binding SelectedMachine.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Grid>

关键是为SelectedItem设置正确的DataContext。为此,我使用了以下XAML代码:

<DataGrid ItemsSource="{Binding MachinesInPlace, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                  SelectedItem="{Binding DataContext.SelectedMachine, RelativeSource={RelativeSource AncestorType=Window},Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

通过这个,您的示例项目可以正确更新TextBox。