ComboBox в DataGrid очищается только тогда, когда ItemsSource зависит от строки - PullRequest
1 голос
/ 09 мая 2019

Я нахожусь в ситуации, когда вопрос о том, очищается или нет данное ComboBox в DataGridRow, зависит от того, связан ли его ItemsSource со строкой в ​​DataGrid или в родительском элементе.

Конкретно рассмотрим следующий WPF Window:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }

    private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (((ComboBox)sender).Items.Count == 0)
            throw new InvalidOperationException("This seems unlikely!");
    }
}

Тогда следующий пример работает, как я и ожидал; то есть, InvalidOperationException в Selector_OnSelectionChanged никогда не вызывается, что имеет смысл для меня, поскольку здесь нет ни одного пустого ComboBox:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <DataGrid ItemsSource="{Binding Items}">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding SelectedName}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <ComboBox ItemsSource="{Binding DataContext.Names, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"
                                      SelectedItem="{Binding SelectedName}"
                                      SelectionChanged="Selector_OnSelectionChanged">
                                <ComboBox.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding}"/>
                                    </DataTemplate>
                                </ComboBox.ItemTemplate>
                            </ComboBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>
public class ViewModel
{
    public ViewModel()
    {
        Items = new List<Model>
        {
            new Model { SelectedName = "b" },
            new Model { SelectedName = "a" }
        };
    }

    public static List<string> Names { get; set; } = new List<string>
    {
        "a", "b"
    };

    public List<Model> Items { get; set; }
}

public class Model
{
    public string SelectedName { get; set; }
}

Если теперь я переместлю список Names в класс модели вместо этого (что в моем случае и будет тем, что я хочу, поскольку сама строка накладывает ограничения на содержимое ComboBox) и обновлю Binding соответственно, тогда я делаю ударил исключение, хотя, насколько я могу судить, задействованные ComboBox такие же непустые, как в примере выше.

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <DataGrid ItemsSource="{Binding Items}">
            <DataGrid.Columns>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding SelectedName}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <!-- Binding below has changed -->
                            <ComboBox ItemsSource="{Binding Names}"
                                      SelectedItem="{Binding SelectedName}"
                                      SelectionChanged="Selector_OnSelectionChanged">
                                <ComboBox.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding}"/>
                                    </DataTemplate>
                                </ComboBox.ItemTemplate>
                            </ComboBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>
public class ViewModel
{
    public ViewModel()
    {
        Items = new List<Model>
        {
            new Model { SelectedName = "b" },
            new Model { SelectedName = "a" }
        };
    }

    public List<Model> Items { get; set; }
    // Names has been removed here
}

public class Model
{
    public string SelectedName { get; set; }

    // Names moved in here now instead
    public static List<string> Names { get; set; } = new List<string>
    {
        "a", "b"
    };
}

Все привязки работают одинаково, с той лишь разницей, что есть момент времени, когда ComboBox пусто. Поэтому возникает вопрос: что является причиной этого, и есть ли способ избежать этого?

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