简体   繁体   中英

How can I make sure my WPF DataGrid shows at least one row when ItemsSource is empty? (Editable ComboBox cells)

I have a DataGrid that allows a user to edit properties of electronic devices such as what inputs and outputs the devices have for the purposes of drawing schematics. There may be scenarios in which the user is editing a previously saved device - in this case the ItemsSource will be bound an already defined object's properties. More often, the user will be creating a new device from scratch, so the ItemsSource will be empty to start. When this is the case, my DataGrid is completely blank, and I want it to show one blank row. My cells are made up of editable ComboBoxes.

I'm so far unable to get the DataGrid to show a previously defined ItemsSource, as well as show a blank row when ItemsSource is empty.

XAML:

<DataGrid Grid.Column="0" Grid.ColumnSpan="2"
              Grid.Row="1" Grid.RowSpan="2"
              ScrollViewer.VerticalScrollBarVisibility="Auto"
              ItemsSource="{Binding InputList}">
        <DataGrid.Columns>

            <DataGridTemplateColumn Header="Label" Width="*">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox IsEditable="True"
                                    Text="{Binding NewLabel}"
                                    ItemsSource="{Binding Label}"
                                    SelectedValue="{Binding SelectedLabel}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

            <DataGridTemplateColumn Header="Signal" Width="*">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox IsEditable="True"
                                    Text="{Binding NewSignal}"
                                    ItemsSource="{Binding Signal}"
                                    SelectedValue="{Binding SelectedSignal}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

            <DataGridTemplateColumn Header="Terminal" Width="*">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox IsEditable="True"
                                    Text="{Binding NewTerminal}"
                                    ItemsSource="{Binding Terminal}"
                                    SelectedValue="{Binding SelectedTerminal}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

        </DataGrid.Columns>

    </DataGrid>

Bindings are as follows: InputList - a list of Structs {Label, Signal, Terminal} for a previously defined device. New structs will be created upon saving if this is a new device. This List(IOStruct) is a property of my device object.

NewLabel - user can type a new Label if it is one that hasn't been used previously Labels - master list of previously defined labels (for quick adding using autocomplete)

SelectedLabel - this will be used to generate the new struct if the user chooses a previously defined label

Next two columns have similar bindings but for Signal types and Terminal types.

Running the application without InputList defined just gives me a blank DataGrid that I cannot do anything with. I would like there to be a blank row in this case.

Any help or tips to make this work and improve my practices is greatly appreciated!

You can try something like this...

First add a extra column in DataGrid..

 <DataGridTemplateColumn Header="Display Order" Width="96" >
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBox Text="{Binding DisplayOrder}" Margin="0" VerticalAlignment="Center" TextAlignment="Right"
                                 HorizontalAlignment="Stretch" x:Name="txtDisplayOrder"  Tag="{Binding}" 
                                 Loaded="txtDisplayOrder_Loaded" MaxLength="1" Background="Transparent" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

The DisplayOrder field should be present in your ItemsSource of type int..

The Loaded event should be like this

    private void txtDisplayOrder_Loaded(object sender, RoutedEventArgs e)
    {
        TextBox txt = sender as TextBox;
        ValidationRuleInteger objDisplayOrder = new ValidationRuleInteger("Display Order", true, false);
        if (txt != null && objDisplayOrder != null)
            txt.GetBindingExpression(TextBox.TextProperty).ParentBinding.ValidationRules.Add(objDisplayOrder);

    }

And finally the class ValidationRuleInteger should be as follows:

 public class clsValidationRuleInteger :ValidationRule
{
    public string strmsg;
    public bool isRequired;
    public bool? isRegex;
    bool AllowNegativeValues;

    public clsValidationRuleInteger(string strmsg, bool isRequired, bool _AllowNegativeValues)
    {
        this.strmsg = strmsg;
        this.isRequired = isRequired;
        AllowNegativeValues = _AllowNegativeValues;
    }

   public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        throw new NotImplementedException();
    }
}

This should work fine as per your requirement...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM