MVVM WPF 数据网格选择绑定到具有复杂对象的组合框

问题描述 投票:0回答:1

我正在尝试实现一个 DataGrid,其中其中一列有一个复杂的对象,而组合框(网格外)有一个该列的同一时间对象的列表。使用 WPF 和 MVVM。

当我在数据网格中选择线条时,我希望组合框显示相应的值。

但我不知道我做错了什么。 有人可以帮忙吗?

    <ComboBox x:Name="cmbResourceList" 
              HorizontalAlignment="Left" 
              ItemsSource="{Binding MainListSource}"
              DisplayMemberPath="Description"
                SelectedValue="{Binding Path=ScheduleVM.Schedule.ResourceList}"
              Width="185"/>

    <DataGrid x:Name="dgScheduleItems"   
              AutoGenerateColumns="False" 
              ItemsSource="{Binding Path=ScheduleSource}" 
              SelectionMode="Single"
              IsReadOnly="True"
              SelectedItem="SelectedSchedule">

        <DataGrid.Columns>
            <DataGridTextColumn Header="Id"             Binding="{Binding Id}"                          Width="40"/>
            <DataGridTextColumn Header="Resource List"  Binding="{Binding ResourceList.Description}"    Width="*"/>
            <DataGridTextColumn Header="Task List"      Binding="{Binding TaskList.Description}"        Width="*"/>
            <DataGridTextColumn Header="Description"    Binding="{Binding Description}"                 Width="100"/>
        </DataGrid.Columns>

    </DataGrid>

这里是 Vb.Net 中的类

Public Class MainList
    Public Property Id As Integer
    Public Property Description As String
End Class


Public Class Schedule
    Public Property Id As Integer
    Public Property Description As String
    Public Property ResourceList As MainList
    Public Property TaskList As MainList
End Class


Public Class MainListRepository
    Private _mainLists As List(Of MainList)

    Public Sub New()
        _mainLists = New List(Of MainList) From
        {
            New MainList() With {.Id = 1, .Description = "First List"},
            New MainList() With {.Id = 2, .Description = "Second List"},
            New MainList() With {.Id = 3, .Description = "Third List"}
        }
    End Sub

    Public Function GetMainLists() As List(Of MainList)
        Return _mainLists
    End Function
End Class


Public Class ScheduleRepository
    Private _schedules As List(Of Schedule)

    Public Sub New()
        _schedules = New List(Of Schedule) From
        {
            New Schedule() With {.Id = 1, .Description = "Schedule 1", .ResourceList = New MainList() With {.Id = 2, .Description = "Second List"}, .TaskList = New MainList() With {.Id = 1, .Description = "First List"}},
            New Schedule() With {.Id = 2, .Description = "Schedule 2", .ResourceList = New MainList() With {.Id = 1, .Description = "First List"}, .TaskList = New MainList() With {.Id = 2, .Description = "Second List"}},
            New Schedule() With {.Id = 3, .Description = "Schedule 3", .ResourceList = New MainList() With {.Id = 1, .Description = "First List"}, .TaskList = New MainList() With {.Id = 3, .Description = "Third List"}},
            New Schedule() With {.Id = 4, .Description = "Schedule 4", .ResourceList = New MainList() With {.Id = 3, .Description = "Third List"}, .TaskList = New MainList() With {.Id = 1, .Description = "First List"}}
        }
    End Sub

    Public Function GetSchedules() As List(Of Schedule)
        Return _schedules
    End Function
End Class

Public MustInherit Class ViewModelBase
    Implements INotifyPropertyChanged

    Protected Sub New()
    End Sub
    
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    
    Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String)
        Me.VerifyPropertyName(propertyName)

        Dim handler As PropertyChangedEventHandler = Me.PropertyChangedEvent
        If handler IsNot Nothing Then
            Dim e = New PropertyChangedEventArgs(propertyName)
            handler(Me, e)
        End If
    End Sub
    
    Private privateThrowOnInvalidPropertyName As Boolean
    Protected Overridable Property ThrowOnInvalidPropertyName() As Boolean
        Get
            Return privateThrowOnInvalidPropertyName
        End Get
        Set(ByVal value As Boolean)
            privateThrowOnInvalidPropertyName = value
        End Set
    End Property
End Class

Public Class ScheduleVM
    Inherits ViewModelBase

    Private _Schedule As Schedule
    Public Property Schedule() As Schedule
        Get
            Return _Schedule
        End Get
        Set(ByVal value As Schedule)
            _Schedule = value

            OnPropertyChanged("Schedule")
        End Set
    End Property

    Public Sub New(schedule As Schedule)
        _Schedule = schedule
    End Sub

End Class


Friend Class SchedulePopupVM
    Inherits ViewModelBase

    Private _ScheduleSource As List(Of Schedule)
    Public Property ScheduleSource() As List(Of Schedule)
        Get
            Return _ScheduleSource
        End Get
        Set(ByVal value As List(Of Schedule))
            _ScheduleSource = value

            OnPropertyChanged("ScheduleSource")
        End Set
    End Property

    Private _MainListSource As List(Of MainList)
    Public Property MainListSource() As List(Of MainList)
        Get
            Return _MainListSource
        End Get
        Set(ByVal value As List(Of MainList))
            _MainListSource = value

            OnPropertyChanged("MainListSource")
        End Set
    End Property


    Private _SelectedSchedule As Schedule
    Public Property SelectedSchedule() As Schedule
        Get
            Return _SelectedSchedule
        End Get
        Set(ByVal value As Schedule)
            _SelectedSchedule = value
            Me.ScheduleVM = New ScheduleVM(value)

            OnPropertyChanged("SelectedSchedule")
        End Set
    End Property

    Private _ScheduleVM As ScheduleVM
    Public Property ScheduleVM() As ScheduleVM
        Get
            Return _ScheduleVM
        End Get
        Set(ByVal value As ScheduleVM)
            _ScheduleVM = value

            OnPropertyChanged("ScheduleVM")
        End Set
    End Property

    Public Sub New()
        Dim repo As ScheduleRepository = New ScheduleRepository()
        Dim repoMain As MainListRepository = New MainListRepository()

        _ScheduleSource = repo.GetSchedules()
        _MainListSource = repoMain.GetMainLists()

    End Sub

End Class
wpf vb.net mvvm combobox datagrid
1个回答
1
投票

一些事情。

您的两个

SelectedValues
(在您的组合框中)都绑定到项目集合。您不希望这样,这些属性旨在绑定到项目集合中的各个项目。

接下来,您对

SelectedItem
DataGrid
的绑定是错误的。将其更新为(注意绑定关键字和大括号):

  <DataGrid x:Name="dgScheduleItems"   
      AutoGenerateColumns="False" 
      ItemsSource="{Binding Path=ScheduleSource}" 
      SelectionMode="Single"
      IsReadOnly="True"
      SelectedItem="{Binding SelectedSchedule}"
      Margin="0,106,0,0">

接下来,对于您的

ComboBoxes
,您希望绑定到单个值。不过,您为
SelectedValue
绑定的值必须是对其 ItemsSource 中的值之一的引用。

更新它们以绑定到新属性。示例:

   <ComboBox x:Name="cmbTaskList" 
            HorizontalAlignment="Left" 
            ItemsSource="{Binding MainListSource}"
            DisplayMemberPath="Description"
            SelectedValue="{Binding MainListSourceSelectedValue, Mode=TwoWay}"
            Margin="244,30,0,0" 
            VerticalAlignment="Top" 
            Width="185"/>

然后,当 SelectedSchedule 属性更改时设置 NEW 属性 (MainListSourceSelectedValue)。类似于(在 c# 中)

public MainList MainListSourceSelectedValue
{
    get { return _mainListSourceSelectedValue; }
    set
    {
        if (_mainListSourceSelectedValue == value) return; 
        _mainListSourceSelectedValue = value;

        RaisePropertyChanged();
    }
}

public Schedule SelectedSchedule
{
    get { return _selectedSchedule; }
    set
    {          
        if (_selectedSchedule == value) return;
        _selectedSchedule = value;

        foreach (var mainListItem in MainList)
        {
            if (mainListItem.Description.equals(_selectedSchedule.ResourseList.Description))
            {
                MainListSourceSelectedValue = mainListItem;
                break;
            }
        }

        RaisePropertyChanged();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.