2

I am still beginner in wpf - mvvm. I have a datagrid binded with a collection.

I need to populate the first column by the content of my textbox. So each time I add a new row, the first column should already have the content of my textbox.

How can I do that?

View:

<Grid DataContext="{Binding Source={StaticResource invoice}}">
    <StackPanel Orientation="Horizontal">
        <TextBox Width="71"
                 Name="InvoiveNumber"
                 Text="{Binding ??, Mode=OneWay}">
            <!-- My textbox -->
        </TextBox>
        <DatePicker></DatePicker>
        <Label Content="Shop" />
        <ComboBox Margin="5"
                  ItemsSource="{Binding Collection, Source={StaticResource shop}}"
                  DisplayMemberPath="shop1"
                  Width="53" />
        <Label Content="Supplier" />
        <ComboBox Margin="5"
                  ItemsSource="{Binding Collection, Source={StaticResource supplier}}"
                  DisplayMemberPath="supplier"
                  SelectedItem="{Binding Selected, Source={StaticResource supplier}, Mode=TwoWay}"
                  Width="46" />
    </StackPanel>
    <DataGrid x:Name="dataGridInvoice"
              Margin="5"
              Grid.Row="1"
              ItemsSource="{Binding Collection}"
              AutoGenerateColumns="False">
        <DataGrid.Columns>
            <!-- My column -->
            <DataGridTextColumn x:Name="dataGridTextColumn"
                                Header="Supplier Invoice Nb"
                                Binding="{Binding suppInvNumber, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                Width="*" />
            <DataGridComboBoxColumn Header="Ref Supplier"
                                    ItemsSource="{Binding Products, Source={StaticResource supplier}, Mode=TwoWay}"
                                    DisplayMemberPath="refsup"
                                    SelectedValueBinding="{Binding refSupp}"
                                    SelectedValuePath="refsup"
                                    Width="*" />
            <DataGridTextColumn Header="Quantity"
                                Binding="{Binding quantity, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                Width="*" />
            <DataGridTextColumn Header="Prix/MOQ"
                                Binding="{Binding unitPrice, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                Width="*" />
            <DataGridTextColumn Header="Total Price"
                                Binding="{Binding totalPrice, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                Width="*" />
        </DataGrid.Columns>
    </DataGrid>
    <Button  x:Name="BtnAdd"
             Content="Save"
             Command="{Binding SaveCommand}"
             Margin="94,0" />
    </StackPanel>
</Grid>

ViewModel:

public class InvoiceViewModel : ViewModelBase
{
    public Context ctx = new Context();

    public InvoiceViewModel()
    {
        Get(false);
    }


    private ObservableCollection<Invoice> collection;

    public ObservableCollection<Invoice> Collection
    {
        get
        {
            return collection;
        }
        set
        {
            collection = value;
            OnPropertyChanged("Collection");
        }
    }


    private Invoice _selected;
    public Invoice Selected
    {
        get
        {
            return _selected;
        }
        set
        {
            _selected = value;
            OnPropertyChanged("Selected");
        }
    }

    private void Get(bool loadDataFirst)
    {
        if (loadDataFirst) ctx.Invoices.Load();
        Collection = ctx.Invoices.Local;
    }


    private void Save()
    {
        ctx.SaveChanges();
    }

    private void Delete()
    {
        var id = Selected;
        var invoice = (from i in ctx.Invoices
                    where i.idInvoice == id.idInvoice
                    select i).SingleOrDefault();

        Collection.Remove(invoice);
    }

    private Invoice _currentItem;
    public Invoice CurrentItem
    {
        get
        {
            return _currentItem;
        }
        set
        {
            _currentItem = value;
            OnPropertyChanged("CurrentItem");
        }
    }


    #region "Command"

    private ICommand saveCommand;
    private ICommand removeCommand;

    public ICommand SaveCommand
    {
        get
        {
            return saveCommand ?? (saveCommand = new RelayCommand(p => this.Save(), p => this.CanSave()));
        }
    }


    private bool CanSave()
    {
        return true;
    }

    public ICommand DeleteCommand
    {
        get
        {
            return removeCommand ?? (removeCommand = new RelayCommand(p => this.Delete(), p => this.CanDelete()));
        }
    }

    public bool CanDelete()
    {
        if (Selected != null)
            return true;
        else
            return false;
    }

    #endregion

}
10
  • Can u explain what do you mean by "what I write in the textbox should be in the first column of each dataGridRow" ... Elaborate it little more to understand Commented Oct 2, 2015 at 1:54
  • First column ? or the textbox in your StackPanel ? And why you binding to static resources instead of the default DataContext (ViewModel) in all your stackpanel controls ? is that really what you intended to do ? Commented Oct 2, 2015 at 3:51
  • try Text="{Binding CurrentItem.suppInvNumber}"> for TextBox, i guess the add function would store CurrentItem to database and adde to the Collection. Commented Oct 2, 2015 at 4:37
  • the value of the textbox has to go in the first column of each row. In my stackpanel, I m binding combobox with static resources because I'm filling them from other ViewModel (ShopViewModel, SupplierViewModel,...) Commented Oct 2, 2015 at 4:41
  • Sorry @daniel, it doesn't work Commented Oct 2, 2015 at 4:46

2 Answers 2

3

First of all, thanks for such challenging problem. Because of this problem, I heavily worked with DataGrid today.

Problem solved after spending entire day and trying various approaches for perfect solution.

Put some number in the textbox, and click button. This number will appear in any new row automatically. Merely changing this number in the textbox won't bring any changes as I am not using that approach. Clicking the button is must. I could have disabled editing the first column, but left it as it is. This solution works equally well without any changes with AutoGenerateColumns="True" .

Following code can be used as is :

Window1.xaml

<Window x:Class="WpfDataControls.DataGrid.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="385.714" Width="598.872">

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="249*"/>
        <RowDefinition Height="79*"/>
    </Grid.RowDefinitions>

    <TextBox x:Name="tbSupplierInvoiceNumber" HorizontalAlignment="Left" Height="23" Margin="168,10,0,0" Grid.Row="1" TextWrapping="Wrap" Text="1" VerticalAlignment="Top" Width="120"/>
    <Button Content="Get invoices" HorizontalAlignment="Left" Margin="306,11,0,0" Grid.Row="1" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    <DataGrid x:Name="dgrdInvoice" HorizontalAlignment="Left" Margin="10,10,0,0" AutoGenerateColumns="False" CanUserAddRows="True" 
              VerticalAlignment="Top" Height="229" Width="571"
              LoadingRow="dgrdInvoice_LoadingRow">
        <DataGrid.Columns>
            <!-- My column -->
            <DataGridTextColumn x:Name="dataGridTextColumn"
                            Header="Supplier Invoice Nb"
                            Binding="{Binding suppInvNumber, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                            Width="*" />
            <DataGridTextColumn Header="Quantity"
                            Binding="{Binding quantity, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                            Width="*" />
            <DataGridTextColumn Header="Prix/MOQ"
                            Binding="{Binding unitPrice, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                            Width="*" />
            <DataGridTextColumn Header="Total Price"
                            Binding="{Binding totalPrice, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                            Width="*" />
        </DataGrid.Columns>
    </DataGrid>
    <TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" Grid.Row="1" TextWrapping="Wrap" Text="Initial suppInvNumber" VerticalAlignment="Top" Width="140"/>
    <TextBlock HorizontalAlignment="Left" Margin="111,38,0,0" Grid.Row="1" TextWrapping="Wrap" Text="Change this number and click get invoices to see the change" VerticalAlignment="Top"/>

</Grid>    
   </Window>

Window1.xaml.cs

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Diagnostics;

namespace WpfDataControls.DataGrid
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {      
        public Window1()
        {
            InitializeComponent();

            dgrdInvoice.AddingNewItem += dgrdInvoice_AddingNewItem;
        }       

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ViewModel vm = new ViewModel();
            dgrdInvoice.ItemsSource = vm.InvoiceCollection;
        }

        #region Grid events
            void dgrdInvoice_LoadingRow(object sender, DataGridRowEventArgs e)
            {
               e.Row.Loaded += dgrdInvoice_Row_Loaded;                
            }

            void dgrdInvoice_Row_Loaded(object sender, RoutedEventArgs e)
            {
                DataGridRow newRow = ((DataGridRow)sender);

                if (newRow.GetIndex() == dgrdInvoice.Items.Count - 1)
                {
                    newRow.Background = new SolidColorBrush(Colors.BlanchedAlmond);
                    DependencyObject reference = newRow;

                    while (true)
                    {
                        reference = VisualTreeHelper.GetChild(reference, 0);
                        if (reference is TextBlock)
                        {
                            TextBlock f = (TextBlock)reference;
                            f.Text = Convert.ToInt32(tbSupplierInvoiceNumber.Text).ToString();
                            break;
                        }
                    }
                }
            }

            void dgrdInvoice_AddingNewItem(object sender, AddingNewItemEventArgs e)
            {
                DataGridRow newRow = (DataGridRow)dgrdInvoice.ItemContainerGenerator.ContainerFromIndex(dgrdInvoice.Items.Count - 1);
                DependencyObject reference = newRow;
                int invoiceNumber;
                while (true)
                {
                    reference = VisualTreeHelper.GetChild(reference, 0);
                    if (reference is TextBlock)
                    {
                        invoiceNumber = Convert.ToInt32(tbSupplierInvoiceNumber.Text);
                        TextBlock f = (TextBlock)reference;
                        f.Text = invoiceNumber.ToString();
                        break;
                    }
                }

                e.NewItem = new Invoice() { suppInvNumber = invoiceNumber };
            }       
        #endregion

    }

    public class ViewModel
    {
        ObservableCollection<Invoice> _invoiceCollection;
        public ObservableCollection<Invoice> InvoiceCollection { get { return _invoiceCollection; } }

        public ViewModel()
        {
            _invoiceCollection = new ObservableCollection<Invoice>();

            _invoiceCollection.Add(new Invoice() { suppInvNumber = 1, quantity=120, unitPrice=23, totalPrice=56 });
            _invoiceCollection.Add(new Invoice() { suppInvNumber = 3, quantity = 122, unitPrice = 13, totalPrice = 23 });
            _invoiceCollection.Add(new Invoice() { suppInvNumber = 4, quantity = 234, unitPrice = 10, totalPrice = 43 });
            _invoiceCollection.Add(new Invoice() { suppInvNumber = 6, quantity = 512, unitPrice = 35, totalPrice = 67 });
            _invoiceCollection.Add(new Invoice() { suppInvNumber = 7, quantity = 612, unitPrice = 3, totalPrice = 120 });
        }
    }

    public class Invoice
    {
        public int suppInvNumber { get; set; }
        public int quantity { get; set; }
        public int unitPrice { get; set; }
        public int totalPrice { get; set; }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

,If I want to put the value of another textbox in the second column, how do i do?
do it and try yourself
0

I had to change the previous method because it works only if I populate the first column. With the following method, I can fill four columns.

    private void dataGridInvoice_AddingNewItem(object sender, AddingNewItemEventArgs e)
    {

                DataGridRow newRow = (DataGridRow)dataGridInvoice.ItemContainerGenerator.ContainerFromIndex(dataGridInvoice.Items.Count - 1);
                DependencyObject reference = newRow;
              //  MessageBox.Show(Convert.ToString(VisualTreeHelper.GetChildrenCount(reference)));
                string invoiceNumber = null;
                int _supplier = 0;
                int _shop = 0;
                DateTime _date = DateTime.Now;


                if (newRow != null)
                {
                    DataGridCellsPresenter presenter = GetVisualChildHelper<DataGridCellsPresenter>(newRow);

                    if (presenter == null)
                    {
                        dataGridInvoice.ScrollIntoView(newRow, dataGridInvoice.Columns[1]);
                        presenter = GetVisualChildHelper<DataGridCellsPresenter>(newRow);
                    }

                    DataGridCell cell0 = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(0);
                    DataGridCell cell1 = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(1);
                    DataGridCell cell2 = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(2);
                    DataGridCell cell3 = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(3);

                    invoiceNumber = InvoiceNumber.Text;
                    int value = Convert.ToInt32(shopComboBox.SelectedValue);
                    _shop = value;

                    value = Convert.ToInt32(supplierComboBox.SelectedValue);
                    _supplier = value;

                    _date = Convert.ToDateTime(datePicker.Text);

                    cell0.Content = invoiceNumber;
                    cell1.Content = _shop;
                    cell2.Content = _date;
                    cell3.Content = _supplier;
                }

                e.NewItem = new Invoice() { suppInvNumber = invoiceNumber, shop = _shop, supplier = _supplier, date = _date };

     }


        public static T GetVisualChildHelper<T>(Visual parent) where T : Visual
        {
            T child = default(T);
            int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < numVisuals; i++)
            {
                Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
                child = v as T;
                if (child == null)
                {
                    child = GetVisualChildHelper<T>(v);
                }
                if (child != null)
                {
                    break;
                }
            }
            return child;
        }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.