将列表绑定到WPF中的ComboBox

时间:2018-05-13 03:54:17

标签: c# wpf

我正在尝试使用MVVM创建一个使用WPF的UI,但我遇到了一些麻烦。我想要一个包含两列的DataGrid。第一列是标签,第二列中有一个ComboBox。标签列始终显示,但ComboBox中没有显示任何内容。我不认为我正确绑定它,但我不确定如何修复它。

我创建了一个具有我想要在DataGrid中显示的属性的类。标签将是Parameter属性,我有一个名为Revisions for ComboBox的列表属性。

class RevisionMapModel
{
    private string _parameter;
    public string Parameter
    {
        get { return _parameter; }
    }

    private List<string> _revisions;
    public List<string> Revisions
    {
        get { return _revisions; }

    }

    private string _selection;
    public string Selection
    {
        get { return _selection; }
        set { _selection = value; }
    }


    public RevisionMapModel(string parameter, List<string> revisions)
    {

        // set the parameter name and the list of revisions
        _parameter = parameter;
        _revisions = revisions;
        _selection = "";


        // add a default revision
        _revisions.Add("None");

        // attempt to find which revision matches with this parameter
        FullRevisionMatch(_parameter, _revisions);

        // if a full match isn't found, then try again
        if (_selection == "None")
        {
            PartialRevisionMatch(_parameter, _revisions);
        }
    }
}

以下是用作DataContext的ViewModel类。 DataGrid绑定到RevisionMapModels属性,该属性是前一个类的列表。

class RevisionMapViewModel
{

    private string _label;
    public string Label
    {
        get { return _label; }

    }

    private List<RevisionMapModel> _revisionMapModels;
    public List<RevisionMapModel> RevisionMapModels
    {
        get { return _revisionMapModels; }
    }


    public RevisionMapViewModel(List<Definition> parameters, List<Revision> revisions, string label)
    {

        // instantiate the list
        _revisionMapModels = new List<RevisionMapModel>();
        _label = label;



        // convert the parameters and revisions to strings
        List<string> revisionDescriptions = revisions.Select(r => r.Description).ToList();
        List<string> parameterNames = parameters.Select(p => p.Name).ToList();


        // create classes for each parameter
        List<string> reservedRevisions = new List<string>();
        for (int i=0; i< parameterNames.Count; i++)
        {
            RevisionMapModel model = new RevisionMapModel(parameterNames[i], revisionDescriptions);


            // check to ensure this parameter is not mapped to a revision that is already selected
            if (reservedRevisions.Contains(model.Selection))
            {
                // change the selection to none if it's already used
                model.Selection = "None";
            }
            else
            {
                reservedRevisions.Add(model.Selection);
            }


            // add it to the list
            _revisionMapModels.Add(model);

        }


    }

}

这是我的XAML。我猜它无法绑定到Revisions属性,因为它是一个列表。我已经尝试了很多东西,但似乎没有任何东西可以显示出来。

<Window x:Class="SheetRevisions.RevisionMapView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:SheetRevisions"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" MinWidth="500" MinHeight="500" Width="500">
    <Grid>
        <DataGrid Margin="20,40,20,45" MinWidth="50" MinHeight="47" ItemsSource="{Binding RevisionMapModels}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Parameter Name" Binding="{Binding Parameter}" Width="Auto"/>
                <DataGridComboBoxColumn Header="Revision Description" ItemsSource="{Binding Revisions}" Width="*" />        
            </DataGrid.Columns>
        </DataGrid>
        <Label Content="{Binding Label}" HorizontalAlignment="Left" Height="25" Margin="20,10,0,0" VerticalAlignment="Top" Width="412"/>
        <Button Content="Cancel" HorizontalAlignment="Right" Margin="0,0,20,10" VerticalAlignment="Bottom" Width="75" IsCancel="True"/>
        <Button Content="OK" HorizontalAlignment="Right" Margin="0,0,110,10" VerticalAlignment="Bottom" Width="75" IsDefault="True"/>

    </Grid>
</Window>

我是WPF的新手,所以感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

如前所述,您需要在ViewModel中实现INotifyPropertyChanged。像

这样的东西
RevisionMapViewModel : INotifyPropertyChanged

//...your code here

public event PropertyChangedEventHandler PropertyChanged;

protected void NotifyPropertyChanged(String info) {
    if (PropertyChanged != null) {
        PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}

然后,我认为RevisionMapModel应该是一个公共类。 此外,如果您在Visual Studio中工作,可以在“输出”窗口中看到有关错误绑定的一些提示。

答案 1 :(得分:0)

除了上面关于实现INotifyPropertyChanged的注释之外,我还需要更改我的XAML以使用DataGridTemplateColumn而不是DataGridComboBoxColumn。它与我从这篇文章中发现的列表不是有效来源有关:

https://social.msdn.microsoft.com/Forums/en-US/e14be49f-1c03-420e-8a15-ca98e7eedaa2/how-to-bind-net-4-datagridcomboboxcolumn-to-a-collection-within-a-collection?forum=wpf

工作XAML:

<Window x:Class="SheetRevisions.RevisionMapView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:SheetRevisions"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" MinWidth="500" MinHeight="500" Width="500">

    <Grid>
        <DataGrid Margin="20,40,20,45" MinWidth="50" MinHeight="47" ItemsSource="{Binding RevisionMapModels}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Parameter Name" Binding="{Binding Parameter}" Width="*" IsReadOnly="True"/>


                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox ItemsSource="{Binding Revisions}" SelectedItem="{Binding Selection}" Width="Auto"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>


            </DataGrid.Columns>
        </DataGrid>
        <Label Content="{Binding Label}" HorizontalAlignment="Left" Height="25" Margin="20,10,0,0" VerticalAlignment="Top" Width="412"/>
        <Button Content="Cancel" HorizontalAlignment="Right" Margin="0,0,20,10" VerticalAlignment="Bottom" Width="75" IsCancel="True"/>
        <Button Content="OK" HorizontalAlignment="Right" Margin="0,0,110,10" VerticalAlignment="Bottom" Width="75" IsDefault="True"/>

    </Grid>
</Window>

修订模型:

public class RevisionMapModel : INotifyPropertyChanged
{

    #region fields

    private Logger _logger = LogUtils.LogFactory.GetCurrentClassLogger();

    private string _parameter;
    public string Parameter
    {
        get { return _parameter; }
        set { }
    }

    private List<string> _revisions;
    public List<string> Revisions
    {
        get { return _revisions; }


    }

    private string _selection;
    public string Selection
    {
        get { return _selection; }
        set
        {
            _selection = value;
            OnPropertyRaised("Selection");
        }

    }

    public event PropertyChangedEventHandler PropertyChanged;


    public RevisionMapModel(string parameter, List<string> revisions)
    {

        // set the parameter name and the list of revisions
        _parameter = parameter;
        _revisions = revisions;
        _selection = "";



        // add a default revision
        _revisions.Add("None");

        // attempt to find which revision matches with this parameter
        FullRevisionMatch(_parameter, _revisions);

        // if a full match isn't found, then try again
        if (_selection == "None")
        {
            PartialRevisionMatch(_parameter, _revisions);
        }
    }

    protected void OnPropertyRaised(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}