Обновить содержимое поля со списком обновленного словаря, к которому привязаны данные - PullRequest
0 голосов
/ 05 января 2019

У меня есть поле со списком, в котором отображаются пути и значения, которые я успешно связал со словарем.

Единственная проблема заключается в том, что фактический словарь не заполняется XAML до тех пор, пока эти поля не будут размещены в xaml выше.

Таким образом, поля со списком не показывают никакого содержимого, потому что словари даже не существовали, когда были созданы поля со списком.

Есть ли способ обновить поля со списком после загрузки главного окна, чтобы мне не пришлось так много возиться с макетом, чтобы он выглядел так, как я хочу после того, как я разместил поле со списком xaml после создания объектов словаря?

Я чувствую, что это будет самый простой способ.

1 Ответ

0 голосов
/ 05 января 2019

Было бы здорово увидеть пример того, что вы пытаетесь сделать, но я постараюсь ответить на то, что вы предоставили.

Необходимо, чтобы поле со списком знало, что коллекция, с которой он связан, было обновлено, и обновляет свое визуальное представление, когда это происходит. Сама коллекция отвечает за уведомление элементов управления, которые к ней привязаны, об изменении коллекции. Словари не имеют возможности уведомлять элементы управления, которые к ним привязаны.

Вы должны рассмотреть возможность использования ObservableCollection. Предполагая, что вы используете модель представления, это будет выглядеть примерно так:

public class MyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private ObservableCollection<MyComboBoxItem> _myItems;
    public ObservableCollection<MyComboBoxItem> MyItems
    {
        get => _myItems;
        set { _myItems = value; OnPropertyChanged(); }
    }
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public void InitializeCollection()
    {
        MyItems = new ObservableCollection<MyComboBoxItem>();
        MyItems.Add(new MyComboBoxItem() { Text = "Hello" });
    }
}

В вашем XAML вы бы указали MyItems в вашей привязке. ComboBox будет обновляться как при создании коллекции, так и при изменении членов коллекции.

<ComboBox ItemsSource="{Binding MyItems}"/>

Предполагается, что контекст данных представления был установлен для экземпляра MyViewModel.

Обновлено для поддержки связывания составного набора

Вот пример использования составной коллекции со списком. Сначала мнение. Здесь я создал ComboBox, который связывается с составной коллекцией. У меня также есть текстовое поле, которое показывает выбранный элемент в поле со списком и два списка, показывающие содержимое двух ObservableCollections на модели представления. Наконец, есть кнопка, которая добавит новый элемент в одну из коллекций в комбинированном представлении.

<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">

    <Window.Resources>
        <DataTemplate x:Key="ComboBoxItemDataTemplate"
                      DataType="local:MyComboBoxItem">

                <TextBlock Margin="4"
                           Text="{Binding Text}" />
        </DataTemplate>

    </Window.Resources>
    <Grid>
        <StackPanel VerticalAlignment="Center"
                    HorizontalAlignment="Center">
            <StackPanel Margin="4"
                        Orientation="Horizontal"
                        VerticalAlignment="Center"
                        HorizontalAlignment="Center">
                <ComboBox Margin="4"
                          Width="220"
                          Height="28"
                          ItemsSource="{Binding ComboBoxItems}"
                          SelectedItem="{Binding SelectedComboBoxItem, Mode=TwoWay}"
                          ItemTemplate="{StaticResource ComboBoxDataTemplate}" />
                <TextBlock Margin="4"
                           Width="220"
                           Text="{Binding SelectedComboBoxItem.Text}" />
            </StackPanel>

            <TextBlock Margin="4"
                       Text="Invariable Items" />
            <ListBox Margin="4"
                     ItemsSource="{Binding InvariableItems}"
                     ItemTemplate="{StaticResource ComboBoxDataTemplate}" />
            <TextBlock Margin="4"
                       Text="Variable Items" />
            <ListBox Margin="4"
                     ItemsSource="{Binding VariableItems}"
                     ItemTemplate="{StaticResource ComboBoxDataTemplate}" />
            <Button Width="80"
                    Click="OnAddVariableItem">Add</Button>
        </StackPanel>
    </Grid>
</Window>

Вот код для представления. Он инициализирует DataContext представления в конструкторе и имеет обработчик события щелчка для кнопки.

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        var dc = new MyViewModel();
        DataContext = dc;

    }

    private void OnAddVariableItem(object sender, RoutedEventArgs e)
    {
        if (DataContext is MyViewModel viewModel)
        {
            viewModel.AddVariableItem();
        }
    }
}

Теперь вид модели. Во-первых, класс, содержащий предметы:

public class MyComboBoxItem
{
    public string Color { get; set; }
    public string Text { get; set; }
}

Далее сама модель просмотра. Мы определяем две наблюдаемые коллекции: одну для вещей, которые никогда не меняются, и одну для вещей, которые часто меняются. Затем мы создаем составную коллекцию для представлений. Когда мы добавляем новый элемент в коллекцию переменных, мы просто воссоздаем составную коллекцию.

public class MyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private ObservableCollection<MyComboBoxItem> _variableItems;
    public ObservableCollection<MyComboBoxItem> VariableItems
    {
        get => _variableItems;
        set { _variableItems = value; OnPropertyChanged(); }
    }

    private ObservableCollection<MyComboBoxItem> _invariableItems;
    public ObservableCollection<MyComboBoxItem> InvariableItems
    {
        get => _invariableItems;
        set { _invariableItems = value; OnPropertyChanged(); }
    }

    private CompositeCollection _comboBoxItems;

    public CompositeCollection ComboBoxItems
    {
        get => _comboBoxItems;
        set { _comboBoxItems = value; OnPropertyChanged(); }
    }

    private MyComboBoxItem _selectedComboBoxItem;
    public MyComboBoxItem SelectedComboBoxItem
    {
        get => _selectedComboBoxItem;
        set { _selectedComboBoxItem = value; OnPropertyChanged(); }
    }

    public MyViewModel()
    {
        Init();
    }

    private void Init()
    {
        InvariableItems = new ObservableCollection<MyComboBoxItem>()
        {
            new MyComboBoxItem() {Text = "(Select One)"},
            new MyComboBoxItem() {Text = "(Default)"},
        };

        VariableItems = new ObservableCollection<MyComboBoxItem>()
        {
            new MyComboBoxItem() {Text = "Shoes"},
            new MyComboBoxItem() {Text = "Hat"},
            new MyComboBoxItem() {Text = "Gloves"}
        };

        ComboBoxItems = Create(new List<IEnumerable<MyComboBoxItem>>()
        {
            InvariableItems,
            VariableItems
        });

        SelectedComboBoxItem = InvariableItems[0];
    }

    private CompositeCollection Create(List<IEnumerable<MyComboBoxItem>> collections)
    {
        var compColl = new CompositeCollection();
        foreach (var coll in collections)
        {
            var container = new CollectionContainer()
            {
                Collection = coll
            };
            compColl.Add(container);
        }

        return compColl;
    }

    public void AddVariableItem()
    {
        VariableItems.Add(new MyComboBoxItem() { Text = "Another item" });
        ComboBoxItems = Create(new List<IEnumerable<MyComboBoxItem>>()
        {
            InvariableItems,
            VariableItems
        });
    }
}
...