MVVM,ComboBox Binding和DatagridTemplateColumn?

时间:2017-04-08 08:29:49

标签: c# wpf mvvm combobox datagrid

我使用DatagridTemplateColumn ComboBox,但ItemSource不会使用绑定集合。

我应该提到DataGrid正在被绑定,并且veiwModel中的任何其他集合都在工作,只是数据网格中的ComboBox不起作用。

这是MCVE示例代码:

<UserControl 
         d:DataContext="{d:DesignInstance d:Type=viewModels:StaffInfoDetailViewModel, IsDesignTimeCreatable=False}">    

    <DataGrid Grid.Column="0" Grid.ColumnSpan="6" AutoGenerateColumns="False" ItemsSource="{Binding SectionStaffMasterDisplay}" Grid.Row="4" Grid.RowSpan="2" AlternationCount="2" CanUserAddRows="True" CanUserDeleteRows="True" GridLinesVisibility="None" VerticalAlignment="Top" CanUserSortColumns="False">

            <DataGridTemplateColumn Width="190" Header="資格">                    
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <ComboBox 
                           DisplayMemberPath="ItemName" 
                           SelectedValuePath="ItemName" 
                           SelectedItem="{Binding Path=Name, UpdateSourceTrigger=LostFocus}" 
                           ItemsSource="{Binding Path=LicenceComboBox}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
           .....more XAML

ViewModel

public class StaffInfoDetailViewModel : CollectionViewModel<StaffInfoDetailWrapper>
{
    public StaffInfoDetailViewModel()
    {           
        LicenceComboBoxItems();
        MasterDataDisplay();
    } 


    public void LicenceComboBoxItems()
    {            
        foreach (var item in DataProvider.StartUpSection)
        {
             LicenceComboBox.Add(item);
        }
    }

    private ObservableCollection<Licence> _licenceComboBox = new ObservableCollection<Licence>(); 

    public ObservableCollection<Licence> LicenceComboBox
    {
        get { return _licenceComboBox; }
        set
        {
            _licenceComboBox = value;
            OnPropertyChanged();
        }
    }

    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

Model类:

public partial class Licence
{
    public System.Guid Id { get; set; } // ID (Primary key)
    public string ItemName { get; set; } // ItemName (length: 50)
    public string Section { get; set; } // Section (length: 50)

    public Licence()
    {
        InitializePartial();
    }

    partial void InitializePartial();
}

datagrid集合。

 private ObservableCollectionEx<StaffInfoDetail> _sectionStaffMasterDisplay = new ObservableCollectionEx<StaffInfoDetail>();

    public ObservableCollectionEx<StaffInfoDetail> SectionStaffMasterDisplay
    {
        get { return _sectionStaffMasterDisplay; }
        set
        {
            if (value != _sectionStaffMasterDisplay)
            {
                _sectionStaffMasterDisplay = value;
                OnPropertyChanged();
            }
        }
    }

集合填充的Entity类,

public partial class StaffInfoDetail
{
    public System.Guid Id { get; set; } // ID (Primary key)
    public byte[] Image { get; set; } // Image (length: 2147483647)
    public int? StaffNo { get; set; } // StaffNo
    public string SecondName { get; set; } // SecondName (length: 50)
    public string FirstName { get; set; } // FirstName (length: 50)
    public string Section { get; set; } // Section (length: 50)
    public string SubSection { get; set; } // SubSection (length: 50)
    public string Licence { get; set; } // Licence (length: 50)
    public System.DateTime? StartDate { get; set; } // StartDate
    public System.DateTime? EndDate { get; set; } // EndDate
    public long? NightShiftOne { get; set; } // NightShiftOne
    public long? NightShiftTwo { get; set; } // NightShiftTwo
    public long? Lunch { get; set; } // Lunch
    public long? Unplesant { get; set; } // Unplesant
    public string JobType { get; set; } // JobType (length: 50)
    public bool Kaizen { get; set; } // Kaizen
    public int KaizenPercentage { get; set; } // KaizenPercentage
    public bool? CurrentStaff { get; set; } // CurrentStaff
    public string Notes { get; set; } // Notes (length: 4000)

    public StaffInfoDetail()
    {
        InitializePartial();
    }

    partial void InitializePartial();
}

填充集合的方法,我将调用者添加到public StaffInfoDetailViewModel()的原始代码中:

public void MasterDataDisplay()
    {
        SectionStaffMasterDisplay.AddRange(DataProvider.StaffInfos.Where(p => 
                                              p.CurrentStaff == true && 
                                              DataProvider.StartUpSection.Contains(p.Section)).ToObservable());
    }

我看不到DataContext的问题,但是为什么当其他所有属性都正常工作时这不能正确绑定?

单步执行代码即可正确显示LicenceComboBox

3 个答案:

答案 0 :(得分:1)

我在这里看到Combobox ItemsSource不是DataGrid ItemsSource的一部分。所以他们两个都在共享不同的DataContext。 Combobox ItemsSource的DataContext是ViewModel,我假设ViewModel是datagrid的DataContext。如果我的假设是正确的,那么你需要将相对源添加到Combobox的ItemsSource的绑定。

使用以下语法:

install_github(repo = "Rwebdriver",username = "crubba")  

为typeOfAncestor使用正确的值,你的Combobox应该被填充。

要阅读有关RelativeSource和AncestorType的更多信息,请浏览this SO post

答案 1 :(得分:1)

此问题与DataContext有关。 DataGrid中的每一行都有自己的DataContext - 来自DataGrid.ItemsSource的集合项。

让我们在这个

上有一个非常简单的例子
using System.Collections.ObjectModel;
using GalaSoft.MvvmLight;

namespace WpfApp4.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            BarCollection = new ObservableCollection<BarModel>
            {
                new BarModel { Id = 1, Name = "Bar 1", },
                new BarModel { Id = 2, Name = "Bar 2", },
                new BarModel { Id = 3, Name = "Bar 3", },
            };

            FooCollection = new ObservableCollection<FooViewModel>
            {
                new FooViewModel{ Id = 1, },
                new FooViewModel{ Id = 2, },
                new FooViewModel{ Id = 3, },
            };

        }


        public ObservableCollection<BarModel> BarCollection { get; set; }
        public ObservableCollection<FooViewModel> FooCollection { get; set; }
    }

    public class FooViewModel : ViewModelBase
    {
        private BarModel _bar;

        public int Id { get; set; }
        public BarModel Bar { get => _bar; set => Set( ref _bar, value ); }
    }

    public class BarModel
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public override string ToString()
        {
            return Name;
        }
    }
}

我们在FooViewModel中展示了MainViewModel.FooCollectionDataGrid)的集合,并希望使用Bar修改ComboBox属性。可能的值位于MainViewModel.BarCollection

这是绑定的XAML

<Window x:Class="WpfApp4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp4"
        mc:Ignorable="d"
        DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <CollectionViewSource x:Key="BarCollectionSource" Source="{Binding Path=BarCollection}"/>
    </Window.Resources>

    <Grid>
        <DataGrid ItemsSource="{Binding Path=FooCollection}" AutoGenerateColumns="True">
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Bar">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Bar}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <ComboBox 
                               DisplayMemberPath="Name" 
                               SelectedItem="{Binding Bar, UpdateSourceTrigger=LostFocus}" 
                               ItemsSource="{Binding Source={StaticResource BarCollectionSource}}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

通过声明CollectionViewSource并将BarCollection绑定到它来完成魔术

<Window.Resources>
    <CollectionViewSource 
        x:Key="BarCollectionSource" 
        Source="{Binding Path=BarCollection}"/>
</Window.Resources>

并将其绑定到ComboBox.ItemsSource

<ComboBox 
    DisplayMemberPath="Name" 
    SelectedItem="{Binding Bar, UpdateSourceTrigger=LostFocus}" 
    ItemsSource="{Binding Source={StaticResource BarCollectionSource}}"/>

答案 2 :(得分:1)

由于id recomItem1 359 Mushroom Chicken 360 Mushroom Chicken 361 Mushroom Chicken, Grilled Chicken 362 Grilled Chicken 363 Grilled Chicken SELECT g1.id AS id, GROUP_CONCAT(i1.itemName) AS recomItem1 FROM `item` AS i1 CROSS JOIN ( SELECT 1 AS pos UNION ALL SELECT 2 AS pos UNION ALL SELECT 3 AS pos UNION ALL SELECT 4 AS pos UNION ALL SELECT 5 AS pos ) q2 JOIN `genRecom` AS g1 ON i1.itemId = CAST(NULLIF(SUBSTRING_INDEX(g1.recomItem1, ',', -pos), SUBSTRING_INDEX(g1.recomItem1, ',', 1 - pos)) AS UNSIGNED) GROUP BY g1.id; DataContext的{​​{1}}是ComboBox对象而DataGrid属性属于StaffInfoDetail类,您需要使用LicenceComboBox才能绑定此属性。

试试这个:

StaffInfoDetailViewModel