none
WPF Datagrid Combobox SelectedItem not Binding to Powershell Object correctly RRS feed

  • Question

  • I am having a bit of trouble correctly binding my Datagrid ComboBox selected item to my PowerShell object. I am using a two way binding for the ComboBox with a 'UpdateSourceTrigger=PropertyChanged' parameter. The source objects correctly get added as items to the ComboBoxes and the source object will update as a selection is changed. However When I save the object or else launch for the first time, the selected items do not get bound. Instead all ComboBox are generated as having no selected value.

    My WPF XAML Datagrid Code:

              <DataGrid Name="CustomDescription_Fields_DG" HorizontalAlignment="Left" Width="626" Margin="185,113,0,87" IsReadOnly="True" AutoGenerateColumns="False" GridLinesVisibility="None" AlternatingRowBackground="#FFEFEFF2" >
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Field}" Header="Applied Fields" Width="395"/>
                    <DataGridTemplateColumn Header="Position" Visibility="Visible" Width="60">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox SelectedItem="{Binding Path=Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding ItemCount}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
                <DataGrid.CellStyle>
                    <Style TargetType="{x:Type DataGridCell}">
                        <Style.Triggers>
                            <Trigger Property="DataGridCell.IsSelected" Value="True">
                                <Setter Property="BorderBrush">
                                    <Setter.Value>
                                        <SolidColorBrush Color="Transparent"/>
                                    </Setter.Value>
                                </Setter>
                                <Setter Property="Foreground"
                            Value="{DynamicResource
                                   {x:Static SystemColors.ControlTextBrushKey}}"/>
                                <Setter Property="Background">
                                    <Setter.Value>
                                        <SolidColorBrush Color="Transparent"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </DataGrid.CellStyle>
            </DataGrid>

    This is my PowerShell Object that is used as the Datagrid Itemssource:


    WPF Application Once Launched:


    You can see that when the application is launched that the combobox items are correctly bound to the 'ItemCount' field of the Itemssource object. What Should happen (Or at least what I'm trying to achieve) is that the selected item should be the Item that is defined within the 'Position' field of the itemssource object.

    I'm not to sure what I am doing wrong. Any help would be very much appreciated.

    Thanks.



    Sunday, May 21, 2017 5:58 AM

Answers

  • Alrighty, so it would seem that the problem I was having was quite simple. The reason that my desired integer was not displaying as the combo boxes selected item was due to the 'Text' value not being set. 

    I was so used to setting the selected item of a combobox within powershell by just specifying the "$ComboboxVariable.Selecteditem = ....." . I was trying to achieve the same thing through my XAML not realising I needed the 'Text' value specified.

                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <ComboBox  
                                        ItemsSource="{Binding ItemCount}"
                                        SelectedItem="{Binding Path=Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                        Text="{Binding Path=Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                                    </ComboBox>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>

    I appreciate people trying to help despite me being 'Vague'  or not using the appropriate Code snipping tool. On the bright side at least no one stooped to the level of condasenction.

    Thanks again. 

    Josh.

    • Marked as answer by Josh.Ads Tuesday, May 23, 2017 5:45 AM
    Tuesday, May 23, 2017 5:45 AM

All replies

  • You have not bound to any PowerShell code that we can see.


    \_(ツ)_/

    Sunday, May 21, 2017 6:08 AM
  • Im not sure what you mean? I have a Powerhsell Object as displayed in the picture. That Object within Powershell is used as the Itemssource for that Datagrid:

    I Also specified within the XAML that the combobox be bound to that Objects specific Fields:

    Please see Below:


    Sunday, May 21, 2017 6:29 AM
  • You are still being way too vague. Please do not post pictures of your screen.  Post code with the correct code posting tool.

    You cannot directly bind PowerShell objects to XAML in the XAML code.  XAML controls must be bound manually to variables.


    \_(ツ)_/

    Sunday, May 21, 2017 3:23 PM
  • Sorry, I am relatively new to using these Blogs. 

    I usually assign functionality to the WPF items from within powershell using that items XAML Name. The issue I'm having is that due to the comboboxes being auto generated within the datagrid, I cannot assign individual names to them within the XAML as they dont exist yet.

    These are the two powershell functions I am using responsible for importing a csv's contents and storing it an an array called '$DescriptionObject'. The second function looks at which items within that $descriptionobject have the property named 'ischecked' that equals $True and uses it as the datagrids Itemssource.

    I have a separate combobox within my wpf that has a bunch of fields with checkboxes bound to the contents. Every time I check a new field the 'Populate-PositionDG' function is run which resets the Datagrids Itemssource using the new $DescriptionObject with the updated 'Ischecked' values. This allows me to control which objects are added to my Datagrid. 

    To my understanding I am Parsing my $DescriptionObject to the Datagrid, and the following XAML binds that objects properties to its combobox:

    <DataTemplate>
                                <ComboBox SelectedItem="{Binding Path=Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding ItemCount}"/>
                            </DataTemplate>


    Powershell Functions:

        #Adding Description Object to Combobox.
        Function Import-DescriptionObject {
            
            #Importing Description Objects
            $CustomDescription_Name_TB.Clear()
            #clearing Object
            $DescriptionObject = $null
            $CustomWord_TB.Clear()
    
            If ($AvailableDescriptions_DG.SelectedItem.Name){
                $DescriptionName = $AvailableDescriptions_DG.SelectedItem.Name
                [Array]$DescriptionObject = Import-csv -Path "$DescriptionPath\$DescriptionName\Description.csv" -ErrorAction SilentlyContinue
                $Separator = Get-content -Path "$DescriptionPath\$DescriptionName\Seperator.db" | select -Index 0 -ErrorAction SilentlyContinue
                $CustomWord = Get-content -Path "$DescriptionPath\$DescriptionName\Custom Word.db" | select -Index 0 -ErrorAction SilentlyContinue
                
                #Adding Template Name
                $CustomDescription_Name_TB.addtext($AvailableDescriptions_DG.SelectedItem.Name)
    
                #Adding Sperator
                If ($Separator){
                    $CustomDescription_Separator_COB.selecteditem = $Separator
                }
                Else{
                    $CustomDescription_Separator_COB.SelectedIndex = -1
                }
                #Adding Custom Word
                If ($CustomWord){
                    $CustomWord_TB.addtext($CustomWord)
                }
                
                #Description Object Used as Datagrids Itemssource
                Set-Variable -Name DescriptionObject -Value $DescriptionObject -Scope Global
                
                #Populating Available Field ComboBox
                Populate-AvailableFields
    
                #Populating Position DG
                Populate-PositionDG
            }
            Else{
                $AvailableFields_COB.itemssource = $Null
                $CustomDescription_Fields_DG.itemssource = $Null
                $DescriptionObject = $null
                $FieldCount_TB.Text = $Null
            }
        }
    
        #Adding Creation Object imported from CSV file
        Function Populate-AvailableFields {
            If ($DescriptionObject){
                $AvailableFields_COB.itemssource = $DescriptionObject
            }
            Else{
                $AvailableFields_COB.itemssource = $Null
                StatusBar -StatusBarText "No Description Object Available."
            }
        }
    
    
        #populating Positions DG with Creation Object where value 'Ischecked' -eq True
        Function Populate-PositionDG {
            If ($AvailableDescriptions_DG.SelectedItem.Name){
                If ($DescriptionObject.ischecked -contains $True){
                    Try{
                        #Counting Object
                        $Count = 0
                        $DescriptionObject | % {
                            If ($_.IsChecked -eq $True){
                                $Count ++
                            }
                            #$_.position = "1"
                            $_.ItemCount = (1..10)
                        }
                        $FieldCount_TB.Text = "$Count fields selected."
    
                        ($DescriptionObject.Position[0]).gettype()
    
    
    
                        #Adding Items to Datagrid
                        $CustomDescription_Fields_DG.ItemsSource = [array]($DescriptionObject | Where-Object {$_.IsChecked -eq $True})
                    }
                    Catch{
                        Get-Error_Window -Error $Error[0] -LineNumber (Get-CurrentLine)
                    }
                    
                    #Adding Position Numbers
                    Set-Variable -Name CustomDescription_Fields_DG -Value $CustomDescription_Fields_DG -Scope Global
                    
                    #Checking if Custom Word is selected
                    If (($AvailableFields_COB.Items | ? {$_.Field -eq 'Custom Word'}).ischecked -eq $True){
                        $CustomWord_TB.Visibility = 'Visible'
                        $CustomWord_lbl.Visibility = 'Visible'
                    }
                    Else{
                        $CustomWord_TB.Visibility = 'Hidden'
                        $CustomWord_lbl.Visibility = 'Hidden'
                    }              
                }
                Else{
                    $CustomDescription_Fields_DG.ItemsSource = $null
                    $FieldCount_TB.Text = "0 fields selected."
                }
            }
        }
    

    I hope that helps.

    Apologies again for being super confusing. 

     

    Sunday, May 21, 2017 4:00 PM
  • ComboBox cells are accessed through the ComboBox variable.  YOU can add events.  When you need to fill a ComboBox yuo have to fill it from a datasource when the column is defined. 

    The XAML "BindingPath" is not usable with PowerShell. You must do the binding in PowerShell code.


    \_(ツ)_/

    Sunday, May 21, 2017 4:09 PM
  • Here are numerous discussions and examples of how t bind a ComboBox.

    https://www.google.com/?gws_rd=ssl#newwindow=1&q=powershell+bind+datagridview+combobox+column&spf=1495383031935


    \_(ツ)_/

    Sunday, May 21, 2017 4:11 PM
  • Hi,

    If you search about an example about "how to bind", below I give you a example of what I use in my scripts. In fact, the purpose is to tell the script to loop over each node of the xaml file to retrieve the attribute "Name" and transform it to a variable that it can modify. Attention that the Name attribute is mandatory for sure.

    #region ############### XAML ###############
    function Set-Variables
    {
      [CmdletBinding(SupportsShouldProcess,ConfirmImpact = 'Low')]
      Param(
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [PSObject]$Object
      )
      
      BEGIN{}
      PROCESS
      {   
        Set-Variable -Name ($Object.Name) -Value $window.FindName($Object.Name) -Scope Global
      }
      END{}
    }
    
    try
    { 
      #Construction of [xml] objects
      [xml]$xamlGUI = Get-Content -Path "$ScriptPath\GUI.xaml" 
    
      #Process xaml
      $reader = (New-Object -TypeName System.Xml.XmlNodeReader -ArgumentList $xamlGUI) #Parse content into reader object type
      $window = [Windows.Markup.XamlReader]::Load( $reader ) #Use the reader to load it trough a window
    
      #Create hooks to each named object in the XAML -> Link XAML <> C#
      $xamlGUI.SelectNodes('//*[@Name]') | Set-Variables
    }
    catch 
    {
      #catch the error
    }
    #endregion

    Hope it helps,


    Sunday, May 21, 2017 9:16 PM
  • Sorry but that only binds to named controls.

    You are trying to bind to a ComboBox which does not have a name.

    Here is your ComboBox cell:

    <ComboBox
     SelectedItem="{Binding Path=Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
     ItemsSource="{Binding ItemCount}"
    />

    It has no name and can only bind to primitive XAML objects as specified.

    To get its value you have to reference the grid cell and return the value.


    \_(ツ)_/

    Sunday, May 21, 2017 10:33 PM
  • ho sure, it is just to give him a good "start" to how to bind the xaml file. Sure he has to set a PSObservable item in the code. In one of my script for example I do it like this (don't be rude it's an old script):

     $OBSarrayFreeIp = New-Object -TypeName System.Collections.ObjectModel.ObservableCollection[Object]   
      foreach($Ip in $ArrayFreeIp)
      {
        $OBSarrayFreeIp.Add((
            New-Object -TypeName PSObject -Property @{
              CustomFreeListIp = $Ip.ToString()
            }
        ))
      }
    
      #Create the Databinding property for the ComboBox [This property name has to be the binding name in the XAML]
      $ItemFreeIpProperty = New-Object -TypeName PSObject -Property @{
        ListFreeIp = $OBSarrayFreeIp.CustomFreeListIp
      }
        
      #Create the DataContext for the combobox
      $cmbbox_freeiplist.DataContext = $ItemFreeIpProperty
    I do not say it is the best way to do the binding of course, but it works great.


    Monday, May 22, 2017 9:30 PM
  • Alrighty, so it would seem that the problem I was having was quite simple. The reason that my desired integer was not displaying as the combo boxes selected item was due to the 'Text' value not being set. 

    I was so used to setting the selected item of a combobox within powershell by just specifying the "$ComboboxVariable.Selecteditem = ....." . I was trying to achieve the same thing through my XAML not realising I needed the 'Text' value specified.

                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <ComboBox  
                                        ItemsSource="{Binding ItemCount}"
                                        SelectedItem="{Binding Path=Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                        Text="{Binding Path=Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                                    </ComboBox>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>

    I appreciate people trying to help despite me being 'Vague'  or not using the appropriate Code snipping tool. On the bright side at least no one stooped to the level of condasenction.

    Thanks again. 

    Josh.

    • Marked as answer by Josh.Ads Tuesday, May 23, 2017 5:45 AM
    Tuesday, May 23, 2017 5:45 AM