Home > Back-end >  Binding to combobox datatemplate from observablecollection within view model
Binding to combobox datatemplate from observablecollection within view model

Time:03-03

I am trying to have a combobox reflect the changes in the underlying viewmodel when this item updates, I have tried to follow the MVVM approach and using INotifypropertyChanged but no matter what I try I am missing something to have this happen.

I am pretty sure I have the DataContext correct - the PropertyChanged event fires, the collection is populated from my DAL, I have tried specifying the SourceUpdateTrigger in the xaml for the combobox - I just cant figure where the break in the wiring is. Your help would be greatly appreciated, happy for direction to usual examples too.

XAML for combobox

<ComboBox  ItemsSource="{Binding partsResultsCollection}" x:Name="searchInput" TextBoxBase.TextChanged="searchInput_TextChanged" HorizontalAlignment="Left" Margin="231,88,0,0" VerticalAlignment="Top" Width="316" Height="25" IsEditable="True">
         <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock FontWeight="Bold" Text="PartNO:"/>
                    <TextBlock Text="{Binding Path=PartNumber}" Padding="10,0"/>
                    <TextBlock FontWeight="Bold" Text="DESC:"/>
                    <TextBlock Text="{Binding Path=Description}" Padding="10,0"/>
                    <TextBlock FontWeight="Bold" Text="QOH:"/>
                    <TextBlock Text="{Binding Path=QtyOnHand}" Padding="10,0"/>
                    <TextBlock FontWeight="Bold" Text="WHQ:"/>
                    <TextBlock Text="{Binding Path=WarehouseQTY}" Padding="10,0"/>
                    <TextBlock FontWeight="Bold" Text="LastSold:"/>
                    <TextBlock Text="{Binding Path=LastSold}" Padding="10,0"/>
                </StackPanel>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

ViewModel Class

class PartsResultsVM : INotifyPropertyChanged
{
    public ObservableCollection<PartsResults> _partsResultsCollection;
    private PartsResults _singularPartResult;
    public PartsDAL partsDAL = new PartsDAL();

    public ObservableCollection<PartsResults> partsResultsCollection
    {
        get { return _partsResultsCollection; }
        set {
              if (partsResultsCollection != value)
                _partsResultsCollection = value;
            OnPropertyChanged("partsResultCollection");
         }
    }

    public PartsResults singularPartResult
    {
        get { return _singularPartResult; }
        set {
              if (singularPartResult != value)
            {
                _singularPartResult = value;
                OnPropertyChanged("singularPart");
            }
            _singularPartResult = value; }
    }

    public PartsResultsVM()
    {
        _partsResultsCollection = new ObservableCollection<PartsResults>();
    }

    public void Update(String Query)
    {
        _partsResultsCollection.Clear();

        _partsResultsCollection = partsDAL.getPartListing(Query);
        OnPropertyChanged("Update");
        Debug.WriteLine("partresultcollection contains:"   _partsResultsCollection.Count   " Items");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
            Debug.WriteLine("PropertyChanged event fired info "   info);
        }
    }

The Page containing the combobox

public partial class PartsManagement : Page
{
    private String connectionString;
    private PartsResultsVM partsResultsVM;

    public PartsManagement()
    {
        InitializeComponent();
        connectionString = @"Provider = Microsoft.ACE.OLEDB.12.0; Data Source = C:\Register\SourceCode\DataBase\Medicar.mdb";
        partsResultsVM = new PartsResultsVM();
        this.DataContext = partsResultsVM;
    }

    private void searchInput_TextChanged(object sender, TextChangedEventArgs e)
    {
        partsResultsVM.Update(searchInput.Text);
    }
} 

Adding partresult model class

public class PartsResults 
{
    private string partNumber; 
    private string description;
    private int qtyOnHand;
    private int warehouseQTY;
    private DateTime lastSupplied;

    public string PartNumber
    {
        get {return partNumber;}
        set 
        { 
            partNumber = value;
            //this.RaisePropertyChanged("Partnumber");          
        }
    }

    public string Description 
    {
        get {return description;}
        set
        {
            description = value;
            //this.RaisePropertyChanged("Description");
        }
    }

    public int QtyOnHand 
    {
        get{return qtyOnHand;}
        set
        {
            qtyOnHand = value;
           // this.RaisePropertyChanged("QtyOnHand");
        }
    }

    public int WarehouseQTY
    {
        get{return warehouseQTY;}
        set
        {
            warehouseQTY = value;
            //this.RaisePropertyChanged("WarehouseQTY");
        }
    }

    public DateTime LastSupplied
    {
        get { return lastSupplied; }
        set
        {
            lastSupplied = value;
           // this.RaisePropertyChanged("LastSupplied");
        }
    }
}

CodePudding user response:

I think I understand the problem. You need the ICollectionView interface to display the data. Here you can find more detailed information.

CollectionView

Apply the following changes in the ViewModel.

public ICollectionView partsResultsCollectionView { get; private set; }

public ObservableCollection<PartsResults> partsResultsCollection = new ObservableCollection<PartsResults>();

public PartsResultsVM()
{
    partsResultsCollectionView = CollectionViewSource.GetDefaultView(partsResultsCollection);
    partsResultsCollection.Add(new PartsResults { PartNumber = "PartNumber1", Description = "Description1", LastSold = "LastSold1", QtyOnHand = "QtyOnHand1", WarehouseQTY = "WarehouseQTY1" });
}

If you want to make changes in a previously added PartResults element. You should implement INotifyPropertyChanged for each item.

Note : I didn't see you add the PartResults class. So I assumed they were all strings. You fix it :)

CodePudding user response:

So it appears that the issue was with the assigning of the results from the DAL here

_partsResultsCollection = partsDAL.getPartListing(Query);

which does not fire a "ObservableCollection.CollectionChanged Event"

https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1.collectionchanged?view=net-6.0

the ObservableCollection bound to the combobox did not notify of changes

when updating the ObservableCollection as follows

        results = partsDAL.getPartListing(Query);

        foreach (PartsResults partsResults in results)
        {
            _partsResultsCollection.Add(partsResults);
        }

with no other modifications the combobox populated as expected.

  • Related