Click here to Skip to main content
15,898,035 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
i am new .net learner and i am trying to fetch unpaid bill months in datagridview2 from datagridview1.

suppose, one person bills are there based on months, like January to October as paid months and November ,December both as unpaid months.

so when i search name of customer then datagridview1 is displayed January to October as paid months but How to other two unpaid months name fetch in datagridview2 ??

using query i am able to fetch paid months from database for datagridview1 and for datagridview2,

here i have add 12 month first as string like,

VB
Dim i As Integer
        Dim month(12) As String
        month(0) = "January"
        month(1) = "February"
        month(2) = "March"
        month(3) = "April"
        month(4) = "May"
        month(5) = "June"
        month(6) = "July"
        month(7) = "August"
        month(8) = "September"
        month(9) = "October"
        month(10) = "November"
        month(11) = "December"

and then

create a column for datagridview2, which is fetch the new rows like November and December.

how can i fetch remain two months in datagridview2??

What I have tried:

using query i am able to fetch paid months from database for datagridview1 and for datagridview2,

here i have add 12 month first as string like,

VB
Dim i As Integer
        Dim month(12) As String
        month(0) = "January"
        month(1) = "February"
        month(2) = "March"
        month(3) = "April"
        month(4) = "May"
        month(5) = "June"
        month(6) = "July"
        month(7) = "August"
        month(8) = "September"
        month(9) = "October"
        month(10) = "November"
        month(11) = "December"

and then

create a column for datagridview2, which is fetch the new rows like November and December.
Posted
Updated 23-Oct-18 17:20pm
v2
Comments
MadMyche 16-Oct-18 10:51am    
Best be would be to store all the accounting data ( bills and payments ) in a database and use that for populating the data tables. How else would you be tracking what is paid and not?
Member 11774405 16-Oct-18 11:12am    
using a loop may be were we can select last month of bill as paid from first datagridview and remain bill months as unpaid can add in second datagridview

You don't need to do two data fetches. You should use MVVM 5to accomplish what you want.

0) Create a model object that is responsible for getting data from the database (or other data source).

1) Create a viewmodel object that takes your model object, and adds properties that reflect the desired business model that will make it easier/more convenient to work with in the UI. In this case, you'll want to have an ObservableCollection of an item object that implements INotifyProperyChanged so any changes made to the collection will be immediately reflected in the UI.

2) Create converter that returns Visible, or Collapsed, based on what the gridview passes to it, so that one grid view will show "paid" objects, and the other will display "unpaid" objects.

That's the RIGHT way to do what you want in WPF.
 
Share this answer
 
When working with WPF, it is easier to do data first via Data Binding (WPF)[^]. This way the view and data are separated giving a window into the data. The benefit is that you're separating the data, and you can then choose how that data is seen by the user.

John is partially correct, the MVVM Design Pattern[^] will better help separate the data from the view. This solution will use MVVM, however there is a far more efficient WPF technique built into the .Net Framework to do what you want.

When working with Collections of data, and filtering, sorting, etc is used on in-memory collections, the best WPF method is to use the CollectionViewSource[^] and bind to the resulting view into you data.

Below is a sample of how to use the CollectionViewSource with the DataGrid and a ComboBox to select the filter type.

First, we need to implement wrappers for the INotifyPropertyChanged Interface[^] used to communicating changes in DataBinding.
C#
public abstract class ObservableBase : INotifyPropertyChanged
{
    public void Set<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string propertyName = "")
    {
        if (!EqualityComparer<TValue>.Default.Equals(field, default(TValue)) && field.Equals(newValue)) return;

        field = newValue;
        RaisePropertyChanged(propertyName);
    }

    public void RaisePropertyChanged (string propertyName)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    public event PropertyChangedEventHandler PropertyChanged;
}

public abstract class ViewModelBase : ObservableBase
{
    public bool IsInDesignMode
        => (bool) DesignerProperties.IsInDesignModeProperty
            .GetMetadata(typeof(DependencyObject))
            .DefaultValue;
}

Next we need a class to hold instance data for each item in our collection:
C#
public class PersonModel : ObservableBase
{
    private string name;
    public string Name
    {
        get => name;
        set => Set(ref name, value);
    }

    private decimal paid;
    public decimal Paid
    {
        get => paid;
        set => Set(ref paid, value);
    }

    private decimal owing;
    public decimal Owing
    {
        get => owing;
        set => Set(ref owing, value);
    }
}

Now we can create our ViewModel used to bind the data to the view:
C#
class MainViewModel : ViewModelBase
{
    public MainViewModel() => Mock();

    private Random rand = new Random();

    public ObservableCollection<PersonModel> People { get; }
        = new ObservableCollection<PersonModel>();

    private CollectionViewSource CSV { get; set; }
    public ICollectionView PeopleView { get; private set; }

    public List<string> PaymentStates { get; }
        = new List<string> {"All", "Not Paid", "Partially Paid", "Paid in Full"};

    private string selectedState;
    public string SelectedState
    {
        get => selectedState;
        set
        {
            Set(ref selectedState, value);
            RefreshFilter();
        }
    }

    private void Mock()
    {
        for (int i = 0; i < 500; i++)
        {
            var owed = rand.Next(100, 500);
            var paidState = rand.Next(1, 100);

            People.Add(new PersonModel
            {
                Name = $"Person {i}",
                Owing = owed,
                Paid = paidState > 0 && paidState < 33
                    ? 0
                    : paidState > 32 && paidState < 66
                        ? rand.Next(5, owed / 10) * 10
                        : owed
            });
        }

        selectedState = PaymentStates[0];

        CSV = new CollectionViewSource {Source = People};
        PeopleView = CSV.View;

        RefreshFilter();
    }

    private void RefreshFilter()
    {
        Func<PersonModel, bool> filterType;

        switch (PaymentStates.IndexOf(selectedState))
        {
            case 1: // not paid
                filterType = x => x.Paid == 0;
                break;
            case 2: // partially paid
                filterType = x => x.Paid > 0 && x.Paid < x.Owing;
                break;
            case 3: // paid in full
                filterType = x => x.Paid >= x.Owing;
                break;
            default:
                filterType = _ => true;
                break;
        }

        PeopleView.Filter = item => filterType(item as PersonModel);

        // update based on filter
        PeopleView.Refresh();
    }
}

Now we can finally implement our View:
XML
<Window x:Class="FilteredDataGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:FilteredDataGrid"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Text="Raw Data"/>
        <DataGrid Grid.Row="1"
                  ItemsSource="{Binding People}"/>
        <StackPanel Grid.Column="1" 
                    Orientation="Horizontal">
            <Label Content="Filter By:"/>
            <ComboBox ItemsSource="{Binding PaymentStates}"
                      SelectedItem="{Binding SelectedState}"
                      Width="100" Margin="10 0 0 0"/>
        </StackPanel>
        <DataGrid Grid.Row="1" Grid.Column="1"
                  x:Name="FilterResults"
                  ItemsSource="{Binding PeopleView}"/>
    </Grid>
</Window>

Changing the selection in the Combobox will change the filter applied and the results DataGrid will relect the applied filter.

Note: in the RefreshFilter() of the MainViewModel I'm using local functions to predefine the filter and not putting the complete filter in the PeopleView.Filter. Like any looping code, put as little inside the loop as possible to maximise the performance.

There should be enough information here to apply to your own project to implement the type of filtering that you want to achieve.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900