Search code examples
wpfxamltriggersdatagriddatatrigger

Based on ComboBox selection, change another ComboBox to TextBox using DataTrigger inside DataGrid CellTemplate


I have one DataGrid where I am using CellTemplate to define various Data columns. Like below

<DataGridTemplateColumn Header="Movie Source" Width="*">
      <DataGridTemplateColumn.CellTemplate>
           <DataTemplate>
              <ComboBox x:Name="cbMovieSource" Width="100" 
                      ItemsSource="{Binding Path=MovieSources, Mode=Twoway}" 
                      SelectedItem="{Binding Path=MovieSourceSelected, Mode=Twoway, UpdateSourceTrigger=PropertyChanged}" 
                      IsSynchronizedWithCurrentItem="False">
              </ComboBox>
           </DataTemplate>
       </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>

Now, I have 3/4 data columns in that DataGrid, Based on one Data column 'Movie Source'- ComboBox's value " Manual Entry", I have to change another Data column 'Movie Hall' ComboBox into TextBox to allow user enter data. I have used Data trigger to do that.

Problem is --

  1. While loading page initially its showing blank instead of default ComboBox -'Movie Hall'.

  2. And while I am changing Movie Source ComboBox's value to "Manual Entry" its not changing Movie Hall ComboBox into TextBox but if I click in that blank space TextBox appearing.

I am using Observable Collection for Item source and data loading is not a problem. But how I will get initially ComboBox but after selecting certain value from ComboBox, into TextBox is the issue here.

My Data trigger code is like below -

<DataGridTemplateColumn Header="Movie Hall" Width="*">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ContentControl>
                <ContentControl.Style>
                    <Style TargetType="av:ContentControl" >
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ElementName=cbMovieSource, Path=SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                                <Setter Property="ContentTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <ComboBox x:Name="cbMovieHall" Width="120" 
                                                      ItemsSource="{Binding MovieHalls, Mode=Twoway}" 
                                                      SelectedItem="{Binding MovieHallsSelected, Mode=Twoway, UpdateSourceTrigger=PropertyChanged}">      
                                            </ComboBox>
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Path=MovieSourceSelected}" Value ="Manual Entry">
                                <Setter Property="ContentTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <TextBox Width="120"  Visibility="Visible" 
                                                Text="{Binding DataContext.TextA, RelativeSource={RelativeSource AncestorType=DataGridRow}}"/>
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ContentControl.Style>
            </ContentControl>
       </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Initial Loading

enter image description here

After selecting value enter image description here

After clicking on blank space under Movie Hall header-

enter image description here


Solution

  • I think now issue is not in any xaml code written here, everything is just fine with DataTrigger, CellTemplate etc. Because you mentioned after clicking its changing means trigger working but UpdateSourceTrigger = PropertyChanged not working that's why Trigger is firing after manual click.

    You also mentioned all other columns and this column also working fine with Data population that means all your ComboBox columns are having item source with collection which is declared in mvvm style, INotifyPropertyChanged. And I see in comment that selected property is string and item source is collection of string.

    You have not wrote any c# code for those properties but with the problem I am assuming you have observable collections with data class not direct string collection. Please make sure your c# code is like below in ViewModel class -

     private ObservableCollection<MovieData> _dataGridCollection;
        public ObservableCollection<MovieData> DataGridCollection 
        {
              get => _dataGridCollection;
              set
              {
                  var changed = DataGridCollection != value;
                  if (changed)
                  {
                      _dataGridCollection = value;
                      NotifyPropertyChanged($"DataGridCollection ");
                   }
               }
        }
    

    And Model class like below -

     Public class MovieData : INotifyPropertyChanged
        {
            private string _movieSourceSelected;
            public string MovieSourceSelected
            {
                get => _movieSourceSelected;
                set
                {
                   _movieSourceSelected = value;
                   NotifyPropertyChanged("MovieSourceSelected");
                 }
            }
        }
    

    And for Xaml part, @Étienne Laneville wrote excellent code there, nothing is wrong in that part but still for answer completion adding to his answer with few minor modifications like Direct Visibility set in control itself and again inside style setter will prevent data trigger to work properly and Grid to StackPanel and Hidden to Collapsed as Hidden always occupies the space and StackPanel puts controls with VerticalOrientation default with one control after another not with same space, which is required here and Grid will put both control in same place..

    <DataGridTemplateColumn Header="Movie Hall" Width="*">
        <av:DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <StackPanel>
                    <ComboBox Width="120"     
                              IsSynchronizedWithCurrentItem="False"                                  
                              ItemsSource="{Binding MovieHalls, Mode=Twoway}"
                              SelectedItem="{Binding MovieHallsSelected, Mode=Twoway, UpdateSourceTrigger=PropertyChanged}">
                                <ComboBox.Style>
                                    <Style TargetType="ComboBox">
                                        <Setter Property="Visibility" Value="Visible" />
                                            <Style.Triggers>
                                                <DataTrigger Binding="{Binding Path=MovieSourceSelected,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                                             Value="Manual Entry">
                                                    <Setter Property="Visibility" Value="Collapsed" />
                                                </DataTrigger>
                                            </Style.Triggers>
                                    </Style>
                                </ComboBox.Style>
                    </ComboBox>
                     <TextBox Width="120"                                                   
                              Text="{Binding DataContext.TextA, RelativeSource={RelativeSource AncestorType=av:DataGridRow}}">
                                <TextBox.Style>
                                    <Style TargetType="TextBox">
                                        <Setter Property="Visibility" Value="Collapsed" />
                                            <Style.Triggers>
                                                <DataTrigger Binding="{Binding Path=MovieSourceSelected,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                                             Value="Manual Entry">
                                                        <Setter Property="Visibility"  Value="Visible" />
                                                </DataTrigger>
                                            </Style.Triggers>
                                    </Style>
                                </TextBox.Style>
                    </TextBox>
                 </StackPanel>
            </DataTemplate>
         </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    

    Edit after answer acceptance :Long story short, your ComboBox was not changing into TextBox because your trigger was not firing automatically. And your trigger was not firing automatically because your UpdateSourceTrigger = PropertyChanged was not working. And UpdateSourceTrigger was not working because your c# code was missing INotifyPropertyChanged implementation with that bind property of Selected Item of Source ComboBox.