Set 2 type controls(TextBox and ComboBox ) in same

2019-08-26 17:54发布

问题:

I have a DataGrid.

Inside it contains some columns; 2 are related to this question, one is a DataGridTextColumn(x:Name="varTypeColumn") which show Variable type, another is a DataGridTemplateColumn(x:Name="varValueColumn") which could be a TextBox or ComboBox inside.

If varTypeColumn is Bool type, varValueColumn should show a ComboBox which contains 2 items: True, False. If varTypeColumn is Int Type, varValueColumn should show a TextBox which let user input string.

So my question is that, is it possible to do it in xaml? I find some implementation which do it in .cs code, it try to get Row and get the Cell, at last set TextBox/ComboBox instance to Cell's Content property. It can work, but if the DataGrid contains big number items(e.g., more than 5000), it is very very slow to display it.

below is the code part:

        private void InitEditors()
    {
        for (int i = 0; i < _devLinkCollectionView.Count; i++)
        {
            DataGridRow row = devLinkDataGrid.GetRow(i);
            InitEditor(row);
        }
    }

    private void InitEditor(DataGridRow row)
    {
        DevLink link = row.Item as DevLink;
        if (link != null)
        {
            if (link.HasErrors)
            {
                ToolTipService.SetShowOnDisabled(row, true);
                row.IsEnabled = false;
                return;
            }

            // Create binding first
            Binding binding = new Binding("DefaultValue")
            {
                Mode = BindingMode.TwoWay,
                UpdateSourceTrigger = UpdateSourceTrigger.LostFocus,
                Source = link
            };

            DataGridCell cell = devLinkDataGrid.GetCell(row, 4);
            switch (link.VariableType)
            {
                case CarelStandardDataType.Bool:
                    ComboBox comboBox = new ComboBox();
                    comboBox.ItemsSource = new[] {string.Empty, "TRUE", "FALSE" };

                    comboBox.SetBinding(ComboBox.SelectedValueProperty, binding);
                    cell.Content = comboBox;
                    break;

                default:
                    TextBox textBox = new TextBox();
                    textBox.Style = (Style)FindResource("TextBoxInError");
                    cell.Content = textBox;

                    binding.ValidationRules.Add(new DevLinkValidationRule(link));
                    textBox.SetBinding(TextBox.TextProperty, binding);

                    break;
            }
        }
    }

回答1:

maybe this is what you want.

<Style x:Key="DataGridCellStyle1" TargetType="{x:Type DataGridCell}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridCell}">
                        <Grid Height="21.96">
                            <ComboBox x:Name="cbCondition1">
                                <ComboBoxItem Content="1"/>
                                <ComboBoxItem Content="2"/>
                            </ComboBox>

                            <TextBox x:Name="tbCondition2" Text="text"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <!--In your case, you should use custom Converter, just return type, or maybe you'd better add typeProperty in your model-->
                            <DataTrigger Binding="{Binding TypeColumn}" Value="Int">
                                <Setter Value="Visible" TargetName="cbCondition1" Property="Visibility"/>
                                <Setter Value="Hidden" TargetName="tbCondition2" Property="Visibility"/>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding TypeColumn}" Value="Bool">
                                <Setter Value="Hidden" TargetName="cbCondition1" Property="Visibility"/>
                                <Setter Value="Visible" TargetName="tbCondition2" Property="Visibility"/>
                            </DataTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                    <Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                </Trigger>
                <Trigger Property="IsKeyboardFocusWithin" Value="True">
                    <Setter Property="BorderBrush" Value="{DynamicResource {x:Static DataGrid.FocusBorderBrushKey}}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource SampleDataSource}}">
        <DataGrid Margin="160,106.5,119,139" ItemsSource="{Binding Collection}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding TypeColumn}"/>
                <DataGridTemplateColumn CellStyle="{StaticResource DataGridCellStyle1}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

==================sample data===============================

<SampleData:SampleDataSource xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.SampleDataSource">
    <SampleData:SampleDataSource.Collection>
        <SampleData:Item TypeColumn="Int" ValueColumn="Row1"/>
        <SampleData:Item TypeColumn="Bool" ValueColumn="Row2"/>
    </SampleData:SampleDataSource.Collection>
</SampleData:SampleDataSource>