【问题标题】:MVVM WPF datagrid Selected binding to combobox with complex objectMVVM WPF datagrid 选择绑定到具有复杂对象的组合框
【发布时间】:2017-06-20 07:44:37
【问题描述】:

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

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

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

    <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

【问题讨论】:

  • 为什么投反对票?至少发表评论
  • 提供的大部分代码似乎不需要重现您的问题,也不够。这有两个主要缺点 1) 读者必须从不相关的内容中过滤掉相关内容 2) 这使得您的问题不太可能对您以外的任何其他人有所帮助(因为它不是通用的)。当您似乎无法通过猜测来纠正时,第一步是通过逐步删除代码来隔离它,直到您在不删除错误的情况下无法删除任何内容。然后,如果您仍然看不到问题所在,请发布生成的代码和您的问题。
  • @franssu 我尽力使它尽可能简洁,感谢您的评论。我只是想明确一点,这里的人们应该尊重“提问者”当前的限制,并且我们知道何时有人问是否懒惰。顺便说一句,我已经更改了问题的代码以符合您的要求。
  • @franssu 再次更新了代码,符合要求吗?
  • 它正朝着正确的方向发展。但这并不是特别针对这个问题,而是您将在职业生涯中遇到的所有错误,以及您将来要问的所有问题。要找到错误,最好的方法是隔离它,尽可能多地

标签: wpf vb.net mvvm combobox datagrid


【解决方案1】:

一些事情。

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

接下来,您对SelectedItemDataGrid 的绑定是错误的。将其更新为(注意绑定关键字和大括号):

  <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();
    }
}

【讨论】:

  • 它有效,但我必须稍微更改您的代码...我不能将我的组合绑定到我的 SelectedSchedule 的属性对象吗?我是否总是在我的 VM 中声明要绑定的新属性?
  • 我建议对您的答案进行一些更改,所以这应该可行
  • 非常感谢您的帮助@d.moncada
  • @andrepaulo,是的,接受了您的编辑。我的愚蠢错误,写得太快了!
  • 我指出了这一点,因为如果其他人有同样的问题但知识较少......那么...... ;) tks
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-04
  • 2015-09-15
  • 1970-01-01
  • 2018-01-17
  • 2018-10-19
相关资源
最近更新 更多