Home > Enterprise >  WPF Column in ListView shall represent a ComboBox when IsFocused = true but a simple TextBox when Is
WPF Column in ListView shall represent a ComboBox when IsFocused = true but a simple TextBox when Is

Time:07-22

When the cell in the column is in focus the ComboBox shall appear but once the value is selected and the cell is not in focus anymore, only the text shall appear. So the ComboBox shall only be visible when cell is in focus.

This is my code but I've really no clue how to solve that.

                   <ListView.View>
                        <GridView>
                            <GridView.Columns>
                                
                                <GridViewColumn Header="SchichtID" Width="60">
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <ComboBox x:Name="SelectedShiftHID"
                                                SelectedIndex="{Binding SchichtID}"
                                                DisplayMemberPath="Bezeichnung"
                                                ItemsSource="{Binding DataContext.UiShiftHModelList, Mode=OneWay,RelativeSource={RelativeSource AncestorType=ListView},UpdateSourceTrigger=PropertyChanged}"/>
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>

                            </GridView.Columns>
                        </GridView>
                    </ListView.View>

1.EDIT: What I'm trying here is to put combobox into a column of a ListView. The values published there come from Model A. The DisplayedMemberPath is the description of the row from model a. We save the ID of that row from Model A in Model B. When the data is reloaded the correct description shall be loaded and shown again in the way explained in my initial post.

2.EDIT: @Anton (that guy deleted his answer?) - your answer doesn't work. It starts that there is no comboBox shown when focussing the cell neither it shows any text. enter image description here

In the XAML of the View im introducing the converters:

<UserControl.Resources>
        <helpers:LastRowVisibilityMultiValueConverter x:Key="LastRowVisibilityMultiValueConverter" />

        <helpers:ShiftHIDtoDescriptionConverter x:Key="ShiftHIDtoDescriptionConverter" ShiftH="{Binding DataContext.UiShiftHModelList, Mode=OneWay, ElementName=ShiftT, UpdateSourceTrigger=PropertyChanged}"/>

        <helpers:CellTemplateSelector x:Key="cellTemplateSelector" x:Name="cellTemplateSelector">
            <helpers:CellTemplateSelector.EditableTemplate>
                <DataTemplate>
                    <ComboBox x:Name="SelectedShiftHID"
                              SelectedIndex="{Binding ID}"
                              DisplayMemberPath="Bezeichnung"
                              ItemsSource="{Binding UiShiftHModelList, Mode=OneWay,ElementName=ShiftT,UpdateSourceTrigger=PropertyChanged}"/>
                </DataTemplate>
            </helpers:CellTemplateSelector.EditableTemplate>

            <helpers:CellTemplateSelector.ReadOnlyTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding SchichtID, Converter={StaticResource ShiftHIDtoDescriptionConverter}}"/>
                </DataTemplate>
            </helpers:CellTemplateSelector.ReadOnlyTemplate>
        </helpers:CellTemplateSelector>
        
    </UserControl.Resources>

There simply happens nada.

One error I've got in your suggested converter was:

public static readonly DependencyProperty ItemsProperty =     DependencyProperty.Register("Items", typeof(IEnumerable), typeof(ItemIdToStringConverter:DependencyObject), new PropertyMetadata(null));

This here: typeof(ItemIdToStringConverter:DependencyObject)

Following the adjusted converter:

public class ShiftHIDtoDescriptionConverter : DependencyObject, IValueConverter
{
    public static readonly DependencyProperty ShiftHProperty = DependencyProperty.Register("ShiftH", typeof(IEnumerable), typeof(ShiftHIDtoDescriptionConverter),new PropertyMetadata(null));

    public IEnumerable ShiftH
    {
        get { return (IEnumerable)GetValue(ShiftHProperty); }
        set { SetValue(ShiftHProperty, value); }
    }

    public object Convert(object shiftHID, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        int? id = shiftHID as int?;
        if (id != null) {
            return ShiftH.Cast<UiShiftHModel>().FirstOrDefault(m => m.ID == id)?.Bezeichnung;
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
        throw new NotImplementedException();
    }
}

This here is the XAML part:

<Border Grid.Row="1" Grid.Column="1" 
            Margin="10,10,10,10"
            BorderBrush="#FF474A57" 
            CornerRadius="10,10,10,10" 
            BorderThickness="2,2,2,2"
            Width="520"
            MaxHeight="300"
            Background="White">
        <StackPanel Margin="0,0,0,20" Orientation="Vertical">
            <StackPanel Grid.Column="0" Grid.RowSpan="1"
                Grid.Row="1"
                VerticalAlignment="Top">
                <Label HorizontalAlignment="Center" FontWeight="Bold">
                    Schichtdetails
                </Label>

                <ListView x:Name="ShiftT" MinHeight="150" MaxHeight="200" MinWidth="500" HorizontalContentAlignment="Stretch" HorizontalAlignment="Center"
                          ItemContainerStyle="{DynamicResource DifAlternationColorsLV}"
                          AlternationCount="2"
                          ItemsSource="{Binding UiShiftTModelList, UpdateSourceTrigger=PropertyChanged}" d:ItemsSource="{d:SampleData ItemCount=5}">
                    <ListView.View>
                        
                        <GridView>
                          
                            <GridView.Columns>

                                <GridViewColumn Header="ID" Width="30">
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <TextBox x:Name="ID" MinWidth="30"
               
                                                     Style="{StaticResource TBoxInListV}"
                                                     Text="{Binding ID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                                      
                                                     BorderThickness="0">
                                            </TextBox>
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>


                                <GridViewColumn Header="SchichtID" Width="60">
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <ContentControl ContentTemplateSelector="{StaticResource cellTemplateSelector}"/>
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>

                            </GridViewColumn>
                            </GridView.Columns>
                        </GridView>
                    </ListView.View>
                </ListView>
            </StackPanel>
        </StackPanel>
    </Border>

Watching the CellTemplateSelector with a breakpoint shows:

  public class CellTemplateSelector : DataTemplateSelector
{
    //Answer for question: switch appearance of the ListView column from combobox to textbox
    //https://stackoverflow.com/questions/73046926/wpf-column-in-listview-shall-represent-a-combobox-when-isfocused-true-but-a-si/73048416?noredirect=1#comment129022042_73048416
    public DataTemplate EditableTemplate { get; set; }

    public DataTemplate ReadOnlyTemplate { get; set; }

    public override DataTemplate
        SelectTemplate(object item, DependencyObject container) {
        ContentControl contentControl = container as ContentControl;

        if (contentControl != null) {
            if (contentControl.IsFocused)
                return EditableTemplate;

            else
                return ReadOnlyTemplate;
        }

        return null;
    }

that the contentControl is always null.

3.EDIT I guess its not a ContentControl its rather a ContenPresenter. Then the casting works. But now I'm fucked up with Binding Errors: enter image description here

4.EDIT Oh, there is another problem with the converter for the id to description. The code therefor from a yet deleted answer is completely bs. The passed id has to be looked up in the UiShiftHModel but there is no chance to pass the collection into the converter. Maybe via multi binding converter....

CodePudding user response:

First of all.. better to create own customControl with properties which allow you to switch templates for Readonly and Editable templates

Example

public class InteractiveContentControl : ContentControl
    {
        public static readonly DependencyProperty IsEditableProperty =
            DependencyProperty.Register("IsEditable", typeof(bool), typeof(InteractiveContentControl), new FrameworkPropertyMetadata(false, OnIsEditablePropertyChanged));

        public bool IsEditable
        {
            get { return (bool)GetValue(IsEditableProperty); }
            set { SetValue(IsEditableProperty, value); }
        }
        private static void OnIsEditablePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = d as InteractiveContentControl;
            control.ChangeTemplate();
        }    

        public static readonly DependencyProperty EditableTemplateProperty = DependencyProperty.Register("EditableTemplate", typeof(DataTemplate), typeof(InteractiveContentControl), new PropertyMetadata(null));
        public DataTemplate EditableTemplate
        {
            get { return (DataTemplate)GetValue(EditableTemplateProperty); }
            set { SetValue(EditableTemplateProperty, value); }
        }

        public static readonly DependencyProperty ReadonlyTemplateProperty = DependencyProperty.Register("ReadonlyTemplate", typeof(DataTemplate), typeof(InteractiveContentControl), new PropertyMetadata(null));
        public DataTemplate ReadonlyTemplate
        {
            get { return (DataTemplate)GetValue(ReadonlyTemplateProperty); }
            set { SetValue(ReadonlyTemplateProperty, value); }
        }


        public InteractiveContentControl():base()
        {
            DefaultStyleKey = typeof(ContentControl);
            this.Loaded  = onl oaded;
            this.LostFocus  = OnLostFocus;
            this.IsKeyboardFocusWithinChanged  = InteractiveContentControl_IsKeyboardFocusWithinChanged;
        }

        private void onl oaded(object sender, RoutedEventArgs e)
        {
            ChangeTemplate();
        }

        private void InteractiveContentControl_IsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            IsEditable = IsKeyboardFocusWithin;
        }

        private void OnLostFocus(object sender, RoutedEventArgs e)
        {
            IsEditable = IsKeyboardFocusWithin; 
        }
   
        private void ChangeTemplate()
        {            
            ContentTemplate = IsEditable ? EditableTemplate : ReadonlyTemplate;            
        }

        protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseDown(e);
            IsEditable = true;
        }        
    }

Also need to have class for convert Id to the Name from the comboBox.

public class ShiftHIDtoDescriptionConverter : DependencyObject, IMultiValueConverter
{
 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        int? id = (int?)values[0];
        IEnumerable<UiShiftHModel> items = values[1] as IEnumerable<UiShiftHModel>;

        if (id!=null && items!=null)
        {
            return items.FirstOrDefault(i => i.ID == id)?.Bezeichnung;
        }

        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Then you can define your resources in xaml

<UserControl.Resources>
    <helpers:ShiftHIDtoDescriptionConverter x:Key="ShiftHIDtoDescriptionConverter" />

    <DataTemplate x:Key="EditableTemplate" DataType="UIShiftTModel">
        <ComboBox x:Name="SelectedShiftHID"
                        ItemsSource="{Binding DataContext.UiShiftHModelList, Mode=OneWay, ElementName=ShiftT, UpdateSourceTrigger=PropertyChanged}"
                        SelectedValuePath="ID"        
                        SelectedValue="{Binding SchichID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"                              
                        DisplayMemberPath="Bezeichnung"/>
    </DataTemplate>

    <DataTemplate x:Key="ReadonlyTemplate" DataType="UIShiftTModel">
        <Grid>
            <TextBlock HorizontalAlignment="Stretch">
                <TextBlock.Text>
                    <MultiBinding Converter="{StaticResource ShiftHIDtoDescriptionConverter}">
                        <Binding Path="SchichID" />
                        <Binding Path="DataContext.UiShiftHModelList" ElementName="ShiftT" />
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </Grid>
    </DataTemplate>
</UserControl.Resources>

And then you will be able to define your GridView

<ListView x:Name="ShiftT" MinHeight="150"                                         
                      AlternationCount="2"
                      ItemsSource="{Binding UiShiftTModelList, UpdateSourceTrigger=PropertyChanged}" d:ItemsSource="{d:SampleData ItemCount=5}">
    <ListView.View>
        <GridView>
            <GridView.Columns>

                <GridViewColumn Header="ID" Width="30">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock x:Name="ID" MinWidth="30"                                                                    
                                Text="{Binding ID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

                <GridViewColumn Header="SchichtID" x:Name="colSchichtID">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <helpers:InteractiveContentControl Content="{Binding}" Width="200"
                                EditableTemplate="{StaticResource EditableTemplate}"
                                ReadonlyTemplate="{StaticResource ReadonlyTemplate}"
                                />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>
  • Related