Управляйте ItemsSource, но сохраняйте выбранное значение - PullRequest
1 голос
/ 05 июля 2019

В моем приложении у меня есть DataGrid, где пользователь может добавлять строки, нажимая Button. При нажатии на кнопку новый экземпляр PlaceholderItem будет добавлен к ObservableCollection<PlaceholderItem>, к которому привязан DataGrid.

Определение DataGrid в представлении выглядит следующим образом:

<DataGrid ItemsSource="{Binding PlaceholderItems}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False"
          Background="White" Grid.Row="1" MinHeight="70" MaxHeight="200" Margin="7,0"         > 
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Placeholder-Name" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ComboBox IsEditable="True" VerticalAlignment="Center" Margin="2"
                              ItemsSource="{Binding DataContext.AvailablePlaceholders, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                              DisplayMemberPath="PlaceholderName"
                              Validation.ErrorTemplate="{StaticResource ComboBoxErrorTemplate}">
                        <ComboBox.Text>
                            <Binding Path="PlaceholderName" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" >
                                <Binding.ValidationRules>
                                    <local:PlaceholderValidationRule ValidationStep="UpdatedValue">
                                        <local:PlaceholderValidationRule.PlaceholderValidationRuleParamData>
                                            <local:PlaceholderValidationRuleParamData 
                                                UsedPlaceholders="{Binding Source={StaticResource proxy}, Path=Data.PlaceholderItems}"
                                                AvailablePlaceholders="{Binding Source={StaticResource proxy}, Path=Data.AvailablePlaceholders}"/>
                                        </local:PlaceholderValidationRule.PlaceholderValidationRuleParamData>
                                    </local:PlaceholderValidationRule>
                                </Binding.ValidationRules>
                            </Binding>
                        </ComboBox.Text>
                    </ComboBox>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Placeholder-Value" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBox VerticalAlignment="Center" Validation.ErrorTemplate="{StaticResource PlaceholderItemValueErrorTemplate}">
                        <TextBox.Text>
                            <Binding Path="PlaceholderValue" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
                                <!--<Binding.ValidationRules>
                                    <local:PlaceholderValueValidationRule/>
                                </Binding.ValidationRules>-->
                            </Binding>
                        </TextBox.Text>
                    </TextBox>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>           
    </DataGrid.Columns>
</DataGrid>

Таким образом, ItemSource DataGrid называется PlaceholderItems. Каждая строка DataGrid состоит из двух столбцов. Первый столбец - ComboBox, где можно выбрать имя PlaceholderItem. А во втором столбце значение PlaceholderItem

Класс PlaceholderItem имеет только два строковых свойства, которые реализуют INotifyPropertyChanged.

ComboBox в первом столбце каждой строки связан с ObservableCollection<PlaceholderItem>. Таким образом, пользователь может выбрать элемент из ComboBox, а значение PlaceholderItem будет записано в TextBox во втором столбце.

Для этого я использую следующий код в ViewModel:

public ObservableCollection<PlaceholderItem> PlaceholderItems
{
    get
    {
        if (placeholderItems == null)
        {
            placeholderItems = new ObservableCollection<PlaceholderItem>();
            placeholderItems.CollectionChanged += PlaceholderItemsOnCollectionChanged;
        }
        return placeholderItems;
    }
}



private void PlaceholderItemsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.NewItems != null)
    {
        foreach (PlaceholderItem placeholderItem in e.NewItems.OfType<PlaceholderItem>())
        {
            placeholderItem.PropertyChanged += PlaceholderItemOnPropertyChanged;
        }
    }

    if (e.OldItems != null)
    {
        foreach (PlaceholderItem placeholderItem in e.OldItems.OfType<PlaceholderItem>())
        {
            placeholderItem.PropertyChanged -= PlaceholderItemOnPropertyChanged;
        }
    }
}

private void PlaceholderItemOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "PlaceholderName")
    {
        PlaceholderItem targetAvailablePlaceholderItem =
            AvailablePlaceholders.FirstOrDefault(p =>
                p.PlaceholderName == ((PlaceholderItem)sender).PlaceholderName);

        if (targetAvailablePlaceholderItem != null)
        {
            ((PlaceholderItem)sender).PlaceholderValue = targetAvailablePlaceholderItem.PlaceholderValue;
        }
    }
}

Все просто отлично работает.

Проблема сейчас:

Если пользователь добавил новую строку и выбрал элемент из ComboBox, я хочу удалить выбранный элемент из коллекции AvailablePlaceholder-Collection. Так что пользователь больше не может выбирать его в других строках.

Я пробовал следующее в PlaceholderItemOnProertyChanged-Method:

        if (e.PropertyName == "PlaceholderName")
        {
            PlaceholderItem targetAvailablePlaceholderItem =
                AvailablePlaceholders.FirstOrDefault(p =>
                    p.PlaceholderName == ((PlaceholderItem)sender).PlaceholderName);

            if (targetAvailablePlaceholderItem != null)
            {
                ((PlaceholderItem)sender).PlaceholderValue = targetAvailablePlaceholderItem.PlaceholderValue;

                AvailablePlaceholders.Remove(targetAvailablePlaceholderItem);

            }
            ((PlaceholderItem)sender).ForcePropertyChanged();
        }

Элемент удален из коллекции, но значение в ComboBox теперь пусто.

Есть ли возможность удалить элемент из ItemsSource ComboBox, но свойство Text ComboBox сохраняет значение?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...