Search code examples
c#wpflistviewdata-bindingobservablecollection

how to refresh a listview by clicking element in another listview WPF


i'm trying to code a POS system. i want to have two list, one with articles and when user click on an article the article is added to the second list and the list reflesh automatically. here is my code

using Newtonsoft.Json;
    public class ArticlesDetailsViewModel : INotifyPropertyChanged, IArticleViewModel
    {
        public ArticlesDetailsViewModel()
        {
            string baseUrl = "http://api.market.csa.com/api/v1.1/Article/ListArticle";
            
            bool dr;
            using (HttpClient client = new HttpClient())
            {
                var response = client.GetAsync(baseUrl);
                var result = response.Result;
                dr = result.IsSuccessStatusCode;
            if (dr)
            {
                    string jsonstring = result.Content.ReadAsStringAsync().Result;
                    var articles = JsonConvert.DeserializeObject<ListArticleResponse>(jsonstring);
                    foreach(var art in articles.data)
                    {
                        ListArticle.Add(art);
                        
                    }
            }
            else
            {
                MessageBox.Show("Une erreur s'est produite lors de la recuration des articles, vérifiez votre connexion internet", "Error", MessageBoxButton.OK, MessageBoxImage.Error);

             }

            }
            //intializing ICollectionView using collection(ObservableCollection)
            ArticleCollection = CollectionViewSource.GetDefaultView(ListArticle);
            CommandeCollection = CollectionViewSource.GetDefaultView(ListCommande);




            ArticleCollection.Filter = Filter;
        }
        private ObservableCollection<ArticleModel> _ListArticle = new ObservableCollection<ArticleModel>();

        public ObservableCollection<ArticleModel> ListArticle
        {
            get { return _ListArticle; }
            set { _ListArticle= value;
                NotifyPropertyChanged("ListArticle");
            }
        }


        private ICollectionView _ArticleCollection;

        public ICollectionView ArticleCollection
        {
            get { return _ArticleCollection; }
            set { _ArticleCollection= value;
                NotifyPropertyChanged("ArticleCollection");
            }
        }

        private ICollectionView _CommandeCollection;

        public ICollectionView CommandeCollection
        {
            get { return _CommandeCollection; }
            set { _CommandeCollection=value;
                NotifyPropertyChanged("CommandeCollection");
            }
        }



        private bool Filter(object emp)
        {
            ArticleModel employee = emp as ArticleModel;
            //you can write logic for filter here
            if (!string.IsNullOrEmpty(ArticleName) && !string.IsNullOrEmpty(ArticleCode))
                return employee.NomArticle.Contains(ArticleName) && employee.NomArticle.Contains(ArticleName);
            else if (string.IsNullOrEmpty(ArticleName))
                return employee.Code.Contains(ArticleCode);
            else
                return employee.NomArticle.Contains(ArticleName);
        }

       
        private string _articleName = string.Empty;
        public string ArticleName
        {
            get { return _articleName;
                
                }
            set
            {
                _articleName=value;
                NotifyPropertyChanged("ArticleName");
                ArticleCollection.Refresh();
            }
        }


        private string _articleCode = string.Empty;
        public string ArticleCode
        {
            get { return _articleCode; }
            set
            {
                _articleCode= value;
                NotifyPropertyChanged("ArticleCode");
                ArticleCollection.Refresh();
            }
        }


        private ArticleModel _ArticleSelected = new ArticleModel();
        public ArticleModel ArticleSelected
        {
            get {
                return _ArticleSelected; }
            set
            {
                _ArticleSelected=value;
                
                NotifyPropertyChanged("ArticleSelected");
            }
        }

        

        private ObservableCollection<ArticleModel> _ListCommande = new ObservableCollection<ArticleModel>();

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
                PropertyChanged(this, new PropertyChangedEventArgs("CommandeCollection"));
            }
        }
        public ObservableCollection<ArticleModel> ListCommande
        {
            get
            {
                return _ListCommande;
            }
            set
            {
                _ListCommande= value;
                NotifyPropertyChanged("ListCommande");
            }
        }

    }
}

the xaml for the commande list:

<UserControl
    x:Class="WantaMarketDesktop.View.CommandesListingView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WantaMarketDesktop.View"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="0.5*"/>
        </Grid.ColumnDefinitions>


        <ListView ScrollViewer.CanContentScroll="True" ScrollViewer.IsDeferredScrollingEnabled="True" ScrollViewer.VerticalScrollBarVisibility="Visible" ItemsSource="{Binding CommandeCollection,UpdateSourceTrigger=PropertyChanged}" Grid.ColumnSpan="2" >

            <ListView.View>

                <GridView  AllowsColumnReorder="True" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.CanContentScroll="True" >
                    <GridView.Columns>
                        <GridViewColumn Header=" ID" DisplayMemberBinding="{Binding IdArticle}"/>
                        <GridViewColumn Header="Nom" DisplayMemberBinding="{Binding NomArticle}"/>
                        <GridViewColumn Header="Quantite" DisplayMemberBinding="{Binding Quantite}"/>
                        <GridViewColumn Header="Prix" DisplayMemberBinding="{Binding Prix}"/>

                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>
        <Label Grid.Row="1" Content="Montant total de la commande :   " FontSize="13"/>
        <Label Grid.Row="1" Grid.Column="1" FontWeight="SemiBold" Content="2750     XFA"  FontSize="17" Width="auto" VerticalAlignment="Center" HorizontalAlignment="Stretch" FontStyle="Normal"  />
    </Grid>
</UserControl>

the xaml article list

<UserControl x:Class="WantaMarketDesktop.View.ArticlesDetails"
             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:WantaMarketDesktop.View"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="0,10,0,0">
        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="5">
            <TextBlock Text="Code  : " VerticalAlignment="Center" Margin="10,5,5,5"/>
            <TextBox Text="{Binding ArticleCode,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" Width="200"/>

            <TextBlock Text="Nom  : " VerticalAlignment="Center" Margin="10,5,5,5"/>
            <TextBox Text="{Binding ArticleName,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" Width="200"/>
        </StackPanel>


        <StackPanel Grid.Row="1" Margin="10,0">
            <Separator HorizontalAlignment="Stretch" Height="5" Margin="0,5,0,10"/>
            <!--setting ItemsSource of ListView to ICollectionView-->
            <ListView Cursor="Hand" ItemsSource="{Binding ArticleCollection}" SelectedItem="{Binding ArticleSelected}" HorizontalAlignment="Stretch" VerticalAlignment="Top" >
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <UniformGrid  Columns="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ListView.ItemTemplate>
                    <DataTemplate >
                        <StackPanel Orientation="Vertical" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
                            <Image ToolTip="{Binding Carracteristique}"  Source="https://phonesdata.com/files/models/Xiaomi-Redmi-Note-10S-298.jpg" HorizontalAlignment="Stretch" VerticalAlignment="Top" Stretch="UniformToFill" MinHeight="50" MaxHeight="100"  />
                            <TextBlock Text="{Binding NomArticle}" ToolTip="{Binding NomArticle}" HorizontalAlignment="Stretch" FontSize="12" FontFamily="Franklin Gothic Medium" VerticalAlignment="Bottom" />
                            <WrapPanel Orientation="Horizontal" Margin="0,5,0,0">
                                <TextBlock  Text="{Binding Prix}"   HorizontalAlignment="Right" FontSize="11" FontFamily="Franklin Gothic Medium" VerticalAlignment="Bottom" />

                                <TextBlock Text="{Binding Code}" Margin="60,0,0,0"  HorizontalAlignment="Stretch" FontSize="9" FontFamily="Franklin Gothic Medium" VerticalAlignment="Center" />

                            </WrapPanel>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
                
            </ListView>
           
        </StackPanel>
    </Grid>
</UserControl>

and the Interface

public interface IArticleViewModel
{
    ObservableCollection<ArticleModel> ListArticle { get; set; }
    ObservableCollection<ArticleModel> ListCommande { get; set; }
}

for now i have this enter image description here

i want to do that when we click on article image , the article add to the list at the left


Solution

  • It is esssential that all controls that depend on the same data (DataContext) must share the same instance of the view model class (DataContext).

    Normally you don't set the DataContext explicitly. You use DataContext inheritance where all child elements implicitly inherit their DataContext from their parent element.

    Add ArticlesDetailsViewModel as a public property to your MainViewModel. Set the MainViewModel as the DataContext of the MainWindow. Then let the common parent of both UserControl elements bind its DataContext to the ArticlesDetailsViewModel property of the MainViewModel (current DataContext).

    Don't forget to remove the DataContext assignment from all UserControl constructors.

    MainViewModel.cs

    class MainViewModel : INotifyPropertyChanged
    {
      // Shared instance
      public IArticleViewModel ArticlesDetailsViewModel { get; }
    
      public MainViewModel => this.ArticlesDetailsViewModel = new ArticlesDetailsViewModel();
    }
    

    MainWindow.xaml.cs

    partial class MainWindow : Window
    {
      public MainWindow()
      {
        InitializeComponenet();
       
        this.DataContext = new MainViewModel();
      }
    }
    

    MainWindow.xaml

    <!-- DataContext is 'MainViewModel' ==> explcitly set -->
    <Window>
        
      <!-- DataContext is 'MainViewModel' ==> inherited -->
      <StackPanel>
        
        <!-- DataContext is 'MainViewModel' ==> inherited -->
        <Button />
        
        <!-- DataContext is 'MainViewModel' ==> inherited -->
        <ListBox />
        
        <!-- DataContext is 'ArticlesDetailsViewModel' ==> explcitly set -->
        <StackPanel DataContext="{Binding ArticlesDetailsViewModel}">
        
          <!-- DataContext is 'ArticlesDetailsViewModel' ==> inherited -->
          <CommandesListingView />
        
          <!-- DataContext is 'ArticlesDetailsViewModel' ==> inherited -->
          <ArticlesDetails />
        </StackPanel>
      </StackPanel>
    </Window>