Привязать элемент управления к одному значению в коллекции / массиве в WPF - PullRequest
4 голосов
/ 17 января 2010

В WPF у меня есть коллекция bool? значения, и я хочу связать каждый из них с отдельным флажком программно. Я хочу, чтобы привязки были двухсторонними, чтобы изменение значения отдельного элемента в коллекции в коде обновляло флажок и наоборот.

Я потратил целую вечность, пытаясь понять, как это сделать, и я полностью застрял. С помощью следующего кода флажок получает правильное значение только тогда, когда окно загружено и все. Изменение флажка даже не обновляет значение в коллекции. (ОБНОВЛЕНИЕ: это похоже на ошибку в .NET4, поскольку коллекция обновляется в идентичном проекте .NET3.5. ОБНОВЛЕНИЕ: Microsoft подтвердила ошибку и исправит ее в выпуске .NET4.)

Заранее большое спасибо за помощь!

C #:

namespace MyNamespace
{
    public partial class MyWindow : Window, INotifyPropertyChanged
    {
        public MyWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
               PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }

        public List<bool?> myCollection = new List<bool?>
            { true, false, true, false, true, false };

        public List<bool?> MyCollection
        {
            get { return myCollection; }
            set { myCollection = value; }
        }
    }
}

XAML:

<CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}">

Ответы [ 3 ]

5 голосов
/ 17 января 2010

Есть несколько вещей, которые нужно изменить здесь, чтобы это заработало.Во-первых, вам нужно обернуть ваше логическое значение в объект, который реализует интерфейс INotifyPropertyChanged, чтобы получить уведомление об изменении, которое вы ищете.В настоящее время вы привязываетесь к логическим значениям в вашей коллекции, которые не реализуют интерфейс.Для этого вы можете создать класс-оболочку следующим образом:

  public class Wrapper: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private bool val = false;

        public bool Val
        {
            get { return val; }
            set
            {
                val = value;
                this.OnPropertyChanged("Val");
            }
        }

        public Wrapper(bool val)
        {
            this.val = val;
        }

    }

Затем вы захотите создать эти объекты в своей форме вместо списка логических значений.Вы также можете использовать наблюдаемую коллекцию вместо списка, чтобы отправлять уведомления о добавляемых и удаляемых элементах.Это показано ниже:

public Window1()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    private ObservableCollection<Wrapper> myCollection = new ObservableCollection<Wrapper>()
        {new Wrapper(true), new Wrapper(false), new Wrapper(true)};


    public ObservableCollection<Wrapper> MyCollection
    {
        get { return myCollection; }
    }

Следующее, что нужно сделать, это отобразить список флажков в вашем пользовательском интерфейсе.Для этого WPF предоставляет элементы управления.ListBox - это itemcontrol, поэтому мы можем использовать его как отправную точку.Установите для элемента источника списка значение MyCollection.Затем нам нужно определить, как каждый объект Wrapper будет отображаться в списке, и это можно сделать с помощью таблицы данных, которая создается в ресурсах Windows.Это показано ниже:

<Window.Resources>
    <DataTemplate x:Key="myCollectionItems">
        <CheckBox IsChecked="{Binding Path=Val, Mode=TwoWay}"></CheckBox>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Path=MyCollection}" ItemTemplate="{StaticResource myCollectionItems}"></ListBox>
</Grid>

Это должно заставить вас работать с простой демонстрацией флажков, значения которых связаны со списком логических значений.

0 голосов
/ 17 января 2010

Измените List<bool?> на ObservableCollection<bool?>. Список не генерирует уведомления об изменениях, необходимые WPF для обновления пользовательского интерфейса. ObservableCollection делает. Это обрабатывает случай, когда запись списка изменяется, и CheckBox должен обновляться соответствующим образом.

В другом направлении это работает для меня даже с List<bool?> - т.е. переключение флажка изменяет значение в коллекции. Ваш синтаксис привязки, безусловно, правильный.

0 голосов
/ 17 января 2010

Что заставляет вас думать, что это не работает? Это работает для меня:)

Вот мой тестовый XAML:

<UniformGrid>
    <CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}"/>
    <ListBox ItemsSource="{Binding MyCollection}"/>
    <Button Content="Test" Click="Button_Click"/>
</UniformGrid>

Вот мой код:

private void Button_Click(object sender, RoutedEventArgs e)
{

}

(остальное такое же как у вас)

Я установил точку останова на Button_Click и проверил MyCollection[0], что она обновлена ​​в соответствии со значением IsChecked CheckBox.

Попробуйте изменить тип вашей коллекции с List<bool?> на ObservableCollection<bool?>. Возможно, именно по этой причине вы считаете, что она не работает для вас (тот факт, что изменения в коллекции нигде не отражены в вашем представлении).

...