0

In my wpf project, I have a datagrid which is being populated by a dataset and contains some columns and many rows. I want to iterate through Column[1] Rows[i] (for example get the values inside the cells of column[1] for all the rows in the datagrid). My question is how can I bind these cells value to a single textbox ? I know using multibinding would be one of the way to achieve the solution but I have not found any help regarding multibinding a textbox through a datagrid. For example, I have read the following questions:

How to bind multiple values to a single WPF TextBlock?

How to use a MultiBinding on DataGridTextColumn?

Also, binding a single value is achievable and I have already done that. I would appreciate any help. Thanks in advance !!

My XAML:

<DataGrid x:Name="datagridbatch"
          FontSize="13.333" FontWeight="Normal"
          IsReadOnly="True"
          SelectionChanged="datagridbatch_SelectionChanged"  
          SelectionUnit="FullRow" SelectionMode="Single"
          VerticalAlignment="Top" HorizontalAlignment="Right"
          Height="615" Width="373" Margin="0,0,0,-582"
          CanUserResizeColumns="False" CanUserResizeRows="False"
          CanUserDeleteRows="False" CanUserAddRows="False"
          RowHeight="30"
          Grid.Row="5" Grid.Column="1"
          CanUserReorderColumns="False" CanUserSortColumns="False"
          ColumnHeaderHeight="25" ColumnWidth="*"
          ScrollViewer.CanContentScroll="True"
          ScrollViewer.VerticalScrollBarVisibility="Auto" />
<TextBox x:Name="input2"
         Margin="0,0,0,0" Width="490" Height="30"
         Grid.Row="0" Grid.Column="1"
         HorizontalAlignment="Left"
         Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}"
         FontSize="13.333" FontWeight="Normal"
         Text="{Binding SelectedItem.UNIQUEPART_ID, ElementName=datagridbatch}"
         BorderBrush="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}"
         FontFamily="Tahoma"
         IsReadOnlyCaretVisible="True"
         HorizontalScrollBarVisibility="Auto"
         ScrollViewer.CanContentScroll="True"/>
Community
  • 1
  • 1
Zak29
  • 15
  • 5
  • you can use the converter while assigning the text to TextBox, in the converter you can return the value based on the selecteditem of the grid. Can you try this way ? Please ignore if already tried. – Elavarasan M Dec 22 '16 at 09:48
  • Please specify "multiple cell values". Do you want to create a text from __all rows__, from __selected rows__ or from some other subset of possible values? – grek40 Dec 22 '16 at 09:53
  • @grek40 sorry, I edited the question. I actually need the values from the cells of selected rows and specified column (could be from 1 to 10000) but I need all of them. I, then use them as input parameters for a query. – Zak29 Dec 22 '16 at 10:15

1 Answers1

0

The idea is using a normal Binding with a converter that handles a collection of items. Using a MultiBinding doesn't really work out for a dynamic collection of binding source items. So whats needed:

  • A DataGrid with items, where each item contains a specific property
  • A TextBox
  • A Binding on the TextBox.Text property, where the SelectedItems from DataGrid are bound with a converter to create a single text
  • A Converter that takes an items collection and creates a string from the item properties
  • Some update logic to ensure updated text, when the selected items update

Lets start with the xaml, it can be pretty simple:

<Window.Resources>
    <local:ItemsToTextConverter x:Key="cItemsToTextConverter"/>
</Window.Resources>

<!-- your surrounding controls -->

<DataGrid x:Name="datagridbatch" SelectionChanged="datagridbatch_SelectionChanged"/>
<TextBox x:Name="input2" Text="{Binding ElementName=datagridbatch,Path=SelectedItems,Converter={StaticResource cItemsToTextConverter},Mode=OneWay}"/>

Note that the binding works only one way - its not as easy to distribute the string value back into multiple items as it is to compress the items into a single string.

The Converter needs to take an items collection and extract a string from the property:

public class ItemsToTextConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var items = value as IEnumerable;
        if (items != null)
        {
            // note: items may contain the InsertRow item, which is of different type than the existing items.
            // so the items collection needs to be filtered for existing items before casting and reading the property
            var items2 = items.Cast<object>();
            var items3 = items2.Where(x => x is MyItemType).Cast<MyItemType>();
            return string.Join(Environment.NewLine, items3.Select(x => x.UNIQUEPART_ID));
        }
        return string.Empty;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new InvalidOperationException();
    }
}

Also, DataGrid.SelectedItems will not automatically fire a binding update, when the selection changes, so you need to trigger a manual update in the selection change event handler:

void datagridbatch_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var binding = BindingOperations.GetBindingExpression(input2, TextBox.TextProperty);
    if (binding != null)
    {
        binding.UpdateTarget();
    }
}
grek40
  • 13,113
  • 1
  • 24
  • 50
  • I have a few questions regarding these code lines: var items2 = items.Cast(); var items3 = items2.Where(x => x is MyItemType).Cast(); return string.Join(Environment.NewLine, items3.Select(x => x.UNIQUEPART_ID)); 1sr question: what do you mean by items may contain InsertRow item which is of different type than the existing items. 2. Are you filtering the items collection in the above mentioned lines ? if yes, can you please elaborate ? 3rd: What does **MyItemType** do in the codeline: MyItemType).Cast(); – Zak29 Dec 23 '16 at 12:42
  • (1) `DataGrid.SelectedItems` can contain a special item that is there to allow creation of a new data row and it has a special type. Therefore, even if all your input items have the type `MyItemType` (made that up, because you never told us the typename for the data inside your `DataGrid`) you can't assume that all items in `SelectedItems` have that type. This is why I filter the items by type before casting. The `Where` method is available on `IEnumerable` but not on `IEnumerable`, so I first cast all items to `object`. Can write more explanation when Christmas is over ;) – grek40 Dec 24 '16 at 14:08