Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics

Dashboard
Notifications
Mark all as read
Q&A

How to filter data from the view using MVVM Pattern?

+2
−1

I am trying to filter data in the DataGrid using the texboxes using the MVVM pattern. Just not sure how to do it. Would appreciate any guidance.

My current code:

Model

public class Technical_BestBeforeDates_Model
{
    public int Id { get; private set; }
    public string ProductCode { get; private set; }
    public string ProductDescription { get; private set; }
}

ViewModel

public class Technical_BestBeforeDates_ViewModel : BaseViewModel
{
    // Properties
    public int Id { get; set; }
    public string ProductCode { get; set; }
    public string ProductDescription { get; set; }

    // Private model
    private Technical_BestBeforeDates_Model Technical_BestBeforeDates_Model;

    // Update Method
    public void GetValuesFromModel()
    {
        Id = Technical_BestBeforeDates_Model.Id;
        ProductCode = Technical_BestBeforeDates_Model.ProductCode;
        ProductDescription = Technical_BestBeforeDates_Model.ProductDescription;
    }

    public Technical_BestBeforeDates_ViewModel(Technical_BestBeforeDates_Model model)
    {
        Technical_BestBeforeDates_Model = model;

        GetValuesFromModel();
    }
}

RecordViewModel

public class Technical_BestBeforeDates_Record_ViewModel : BaseViewModel
{
    // Hold list of view models
    public List<Technical_BestBeforeDates_ViewModel> VMs { get; set; }

    // Recieve data from View Model
    public Technical_BestBeforeDates_Record_ViewModel()
    {
        var records = GetDataFromDatabase();

        VMs = new List<Technical_BestBeforeDates_ViewModel>();

        foreach (Technical_BestBeforeDates_Model model in records)
        {
            VMs.Add(new Technical_BestBeforeDates_ViewModel(model));
        }
    }

    // Get data using dapper
    public List<Technical_BestBeforeDates_Model> GetDataFromDatabase()
    {
        string query = @"SELECT 
                            b.id AS ID, 
                            ProductCode, 
                            ProductDescription
                        FROM technical_bestbeforedates b";

        using (var conn = new MySqlConnection(ConfigurationManager.ConnectionStrings["MySQL"].ConnectionString))
        {
            conn.Open();

            // Using dapper to fill the model
            var Records = conn.Query<Technical_BestBeforeDates_Model>(query).ToList();

            return Records;
        }
    }
}

View

        <DockPanel>
            <DataGrid ItemsSource="{Binding VMs}"
                      AutoGenerateColumns="False"
                      IsReadOnly="True"
                      ColumnWidth="auto">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Id}" Header="Id" />
                    <DataGridTextColumn Binding="{Binding ProductCode}" Header="Product Code" />
                    <DataGridTextColumn Binding="{Binding ProductDescription}" Header="Product Description" />
                </DataGrid.Columns>
            </DataGrid>
        </DockPanel>
Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

1 comment

I wrote some thoughts but it would be better if you provide MCVE rather than some random parts of code. Let me explain: You ask about filter so part that related to DB shouldn't be included at all. It's unclear how exactly BaseViewModel class looks. What's a purpose of Technical_BestBeforeDates_ViewModel? And feel free to correct my poor English grammar. FoggyFinder‭ about 1 month ago

1 answer

+2
−0

I wrote quick (and somewhere dirty) example to show one of possible approaches:

  1. Add properties corresponding to each filter:
private string productCode;
private string productDescription;

public string ProductCode 
{ 
    get => productCode;
    set => SetProperty(ref productCode, value);
}

public string ProductDescription 
{ 
    get => productDescription;
    set => SetProperty(ref productDescription, value);
}
  1. To keep it simple assume we want to filter data by pressing a button. So we have to add a command:
public ICommand FilterCommand { get; }
  1. Replace List with ObservableCollection
public Technical_BestBeforeDates_Record_ViewModel()
{
    VMs = new ObservableCollection<Technical_BestBeforeDates_Model>();
    FilterCommand = new RelayCommand(_ => UpdateDataFromDatabase());

    UpdateDataFromDatabase();
}

public void UpdateDataFromDatabase()
{
    VMs.Clear();
    // ToDo: replace with call to a DB
    var records = DataStorage.GetFilteredData(ProductCode, ProductDescription);
    foreach (Technical_BestBeforeDates_Model model in records)
    {
        VMs.Add(model);
    }
}
  1. Write a UI
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <TextBlock
            Grid.Row="0"
            Grid.Column="0"
            Margin="5"
            HorizontalAlignment="Center"
            Text="Code" />
        <TextBlock
            Grid.Row="1"
            Grid.Column="0"
            Margin="5"
            HorizontalAlignment="Center"
            Text="Description" />
        <TextBox
            Grid.Row="0"
            Grid.Column="1"
            Margin="5"
            Text="{Binding ProductCode}" />
        <TextBox
            Grid.Row="1"
            Grid.Column="1"
            Margin="5"
            Text="{Binding ProductDescription}" />
        <Button
            Grid.Row="2"
            Grid.Column="1"
            MaxWidth="100"
            Margin="5"
            HorizontalAlignment="Right"
            Command="{Binding FilterCommand}"
            Content="Filter" />
    </Grid>
    <DataGrid
        Grid.Row="1"
        AutoGenerateColumns="False"
        ColumnWidth="auto"
        IsReadOnly="True"
        ItemsSource="{Binding VMs}">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Id}" Header="Id" />
            <DataGridTextColumn Binding="{Binding ProductCode}" Header="Product Code" />
            <DataGridTextColumn Binding="{Binding ProductDescription}" Header="Product Description" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

In the code above I assume that

  1. BaseViewModel class implements INotifyPropertyChanged interface and has SetProperty method.

  2. Technical_BestBeforeDates_Record_ViewModel class is a "main" VM for that UserControl with DataGrid and a filter panel.

  3. Technical_BestBeforeDates_Model class actually contains constructor so user can create its instance.

I've create a gist with full code to make it easier to you if some parts aren't clear enough.

https://gist.github.com/FoggyFinder/3d25d3260eaec06f819106cde33b914d

Why does this post require moderator attention?
You might want to add some details to your flag.

7 comments

Hi, yes you're right regarding BaseViewModel, it only has the INotifyPropertChanged. I had been advised to create Technical_BestBeforeDates_ViewModel for the purpose of preventing the UI accesing the Model directly. gzi98‭ about 1 month ago

@gzi98 I see no reason to create duplicate types merely to avoid connection between Model and View in case of displaying data. FoggyFinder‭ about 1 month ago

@FoggyFiner It kinda defeats the idea of using MVVM right? gzi98‭ about 1 month ago

@gzi98 There is no right answer to the Q. Someone think it's against the pattern but other have quite the opposite opinion. Anyway, I see no reason to create a proxy for object that can't be mutated "outside". But I'm a purist when it comes to creating objects. FoggyFinder‭ about 1 month ago

How do I replace the dummy data with the real database? I have never seen such code before private static readonly Technical_BestBeforeDates_Model[] data = new Technical_BestBeforeDates_Model[] gzi98‭ about 1 month ago

Show 2 more comments

Sign up to answer this question »