简体   繁体   中英

WPF MVVM ComboBox data binding

I am trying to create a simple WPF application and bind data to combobox but I am not having any luck. My PeriodList is getting populated fine but is not getting bind to the combobox. Do I need to set the DataContext in XAML or in code behind? Please help, I am very confused.

Here is my XAML

<UserControl x:Class="FinancialControlApp.KeyClientReportView"
             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:FinancialControlApp"
             mc:Ignorable="d" 
             d:DesignHeight="300" Width="630">

    <UserControl.Resources>
        <!-- DataTemplate (View) -->
        <DataTemplate DataType="{x:Type local:KeyClientReportModel}">
        </DataTemplate>
    </UserControl.Resources>

    <DockPanel Margin="20">
        <DockPanel DockPanel.Dock="Top" VerticalAlignment="Center">
            <TextBlock Margin="10,2" DockPanel.Dock="Left" Text="Start Period" VerticalAlignment="Center" />

            <ComboBox Name="cmbStartPeriod" Margin="10,2" Width="112" VerticalAlignment="Center" ItemsSource="{Binding PeriodList}">
            </ComboBox>

            <TextBlock Margin="10,2" DockPanel.Dock="Left" Text="End Period" VerticalAlignment="Center" />

            <ComboBox Name="cmbEndPeriod" Margin="10,2" Width="112" VerticalAlignment="Center" ItemsSource="{Binding PeriodList}" />

            <!--<Button Content="Save Product" DockPanel.Dock="Right" Margin="10,2" VerticalAlignment="Center"
                        Command="{Binding Path=SaveProductCommand}" Width="100" />-->

            <Button Content="Run" DockPanel.Dock="Left" Margin="10,2" 
                        Command="{Binding Path=GetProductCommand}" IsDefault="True" Width="100" />
        </DockPanel>

        <!--<ContentControl Margin="10" Content="{Binding Path=PeriodName}" />-->
        <ContentControl Margin="10"></ContentControl>
    </DockPanel>
</UserControl>

Here is my model

     namespace FinancialControlApp
    {
       public class KeyClientReportModel : ObservableObject
       {

        private string _periodName;

        public string PeriodName
        {
            get { return _periodName; }
            set
            {
                if (value != _periodName)
                {
                    _periodName = value;
                    OnPropertyChanged("PeriodName");
                }
            }
        }

        List<KeyClientReportModel> _periodList = new List<KeyClientReportModel>();

        public List<KeyClientReportModel> PeriodList
        {
            get { return _periodList; }
            set
            {
                _periodList = value;
                OnPropertyChanged("PeriodList");
            }
        }
      }
}

And here is my ViewModel

    namespace FinancialControlApp
{
    public class KeyClientReportViewModel : ObservableObject, IPageViewModel
    {
        private KeyClientReportModel _currentPeriod;
        private ICommand _getReportCommand;
        private ICommand _saveReportCommand;

        public KeyClientReportViewModel()
        {
            GetPeriod();
        }

        public string Name
        {
            get { return "Key Client Report"; }
        }

        public ObservableCollection<KeyClientReportModel> _periodName;
        public ObservableCollection<KeyClientReportModel> PeriodName
        {
            get { return _periodName; }
            set
            {
                if (value != _periodName)
                {
                    _periodName = value;
                    OnPropertyChanged("PeriodName");
                }
            }
        }

        private void GetPeriod()
        {
            DataSet ds = new DataSet();
            DataTable dt = new DataTable();
            Helper_Classes.SQLHelper helper = new Helper_Classes.SQLHelper();

            ds = helper.getPeriod();
            dt = ds.Tables[0];
            PeriodName = new ObservableCollection<KeyClientReportModel>();
            foreach (DataRow dr in dt.Rows)
            {
                var period = dr["Period"].ToString();
                if (period != null)
                {
                    PeriodName.Add(new KeyClientReportModel { PeriodName = period });
                }
                //p.PeriodName = dr["Period"].ToString();           
            }
        }
}
}

UPDATE: So I attach a Value Converter to Break into the Debugger and here is what I see. I see

I see 5 items in the list

Change

ItemsSource="{Binding KeyClientReportModel.PeriodList}"

To:

ItemsSource="{Binding PeriodList}"

Make sure your ViewModel is set to the DataContext property of your view.

Set the combobox DisplayMemberPath to the property Name of your KeyClientReportViewModel class.

Or alternatively override the .ToString() method inside the KeyClientReportViewModel class in order to provide the Combobox item display text.

This can help you

------View

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        <!-- To get the ViewModel -->
        xmlns:viewmodels="clr-namespace:WpfApp1.ViewModels"
        Title="MainWindow">
    <Window.DataContext>
        <!-- Assigning the ViewModel to the View -->
        <viewmodels:MainWindowViewModel />
    </Window.DataContext>
    <DockPanel VerticalAlignment="Center"
               DockPanel.Dock="Top">
        <TextBlock Margin="10,2"
                   VerticalAlignment="Center"
                   DockPanel.Dock="Left"
                   Text="Start Period" />
        <ComboBox Name="cmbStartPeriod"
                  Width="112"
                  Margin="10,2"
                  VerticalAlignment="Center"
                  ItemsSource="{Binding PeriodName}" // Items in the ViewModel 
                  DisplayMemberPath="Name"/> // Property to display
    </DockPanel>
</Window>

------- ViewModel

public class MainWindowViewModel
{
    public MainWindowViewModel()
    {
        var items = new List<KeyClientReportModel>
        {
            new KeyClientReportModel
            {
                Name = "First",
                Value = 1
            },
            new KeyClientReportModel
            {
                Name = "Second",
                Value = 1
            }
        };

        PeriodName = new ObservableCollection<KeyClientReportModel>(items);
    }

    // You don't need to notify changes here because ObservableCollection 
    // send a notification when a change happens. 
    public ObservableCollection<KeyClientReportModel> PeriodName { get; set; }

}

public class KeyClientReportModel
{
    public int Value { get; set; }
    public string Name { get; set; }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM