ListView не обновляется, если базовые данные обновляются с помощью ListView

#c# #wpf #listview

#c# #wpf #listview

Вопрос:

Проблема, с которой я сталкиваюсь, заключается в следующем: у меня есть WPF ListView, который привязан к ObservableCollection объектов, которые реализуют интерфейс INotifyPropertyChanged. В установщиках для моих свойств я выполняю некоторую проверку данных, и в случае, когда пользователь вводит неверные данные, я выведу окно сообщения и установлю для свойства значение по умолчанию. В настоящее время все это работает. Проблема в том, что если свойство обновляется с помощью пользовательского ввода в ListView, если пользователь вводит «недопустимые» данные, в то время как свойство обновляется до значения по умолчанию, ListView не обновляется, чтобы отразить это

Например, учитывая приведенный ниже код, если пользователь введет букву «a» для столбца идентификатора устройства, он получит всплывающее окно, и свойство будет установлено в -1, но ListView продолжит показывать «a».

XAML для ListView:

 <ListView Margin="0,0,0,0" Name="configListView" SelectionMode="Single" ItemsSource="{Binding Path=''}" IsSynchronizedWithCurrentItem="True">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <EventSetter Event="GotFocus" Handler="EditItemGotFocusDelegate"/>
         </Style>
    </ListView.ItemContainerStyle>
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Device ID" Width="75">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBox Text="{Binding Path=DeviceID}" Margin="-6,0,-6,0"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>

            <!-- More Columns declared just like above -->

        </GridView>
    </ListView.View>
</ListView>
  

Код для свойства выглядит следующим образом:

 class ConfigItem : INotifyPropertyChanged
{
    private int _DeviceID = -1;
    /* More variables...*/

    /* Implementation of INotifyPropertyChanged */
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string p)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(p));
        }
    }

    /* Property definition */
    public string DeviceID
    {
        get
        {
            if (_DeviceID == -1)
            {
                return "<Default>";
            }
            else
            {
                return _DeviceID.ToString();
            }
        }

        set
        {
            if (value == "")
            {
                _DeviceID = -1;
            }
            else if(int.TryParse(value, out _DeviceID) == false || _DeviceID > 1023 || _DeviceID < 0)
            {
                System.Windows.MessageBox.Show("Device ID must be a number greater than 0 and less than 1024");
                _DeviceID = -1;
            }
            NotifyPropertyChanged("DeviceID");
        }
    }

    /* More Properties definitions exactly as above */
}
  

Комментарии:

1. На первый взгляд все выглядит довольно хорошо. Что происходит, когда вы вызываете NotifyPropertyChanged с null ? Это должно обновить полный экземпляр объекта. И поставьте точку останова в получателе и посмотрите, вызывается ли она в определенные моменты. Загрузка страницы, редактирование свойства и т. Д.

2. Я рекомендую вам ознакомиться с интерфейсом IDataErrorInfo и как его использовать для проверки данных WPF. Вот хороший учебник: tarundotnet.wordpress.com/2011/03/03 /…

3. Какая версия .NET? У меня была эта проблема с простым текстовым полем. Переход на .NET 4.5 исправил это. Но в настоящее время у меня возникла проблема с ComboBox SelectedIndex. Это похоже на то, что элемент пользовательского интерфейса решает, что он знает лучше, и игнорирует get .

4. Средство получения вызывается при загрузке страницы или при добавлении новых объектов в коллекцию, но НЕ в том случае, если средство установки вызывается из пользовательского интерфейса (т. Е. Средство получения вызывается, если я пишу некоторый код для установки свойства). По ряду причин я вынужден использовать VS2008 для этого проекта, поэтому я использую .NET 3.5

5. @Blam — именно так выглядит эта проблема. Кажется, что пользовательский интерфейс думает, что, поскольку он вызывает установщик, он должен затем игнорировать любые уведомления, сгенерированные в результате этого. На первый взгляд это кажется разумным (чтобы избежать потенциальных бесконечных циклов уведомлений), но если это так, было бы неплохо переопределить это поведение

Ответ №1:

Я не уверен, правильно ли я понимаю ваш вопрос, но _DeviceID должен быть общедоступным свойством и реализовывать PropertyChanged, чтобы пользовательский интерфейс отражал любые внесенные в него изменения.

Поэтому измените свойство на

 private int _DeviceID;
public int DeviceID
    {
        get
        {

          return _DeviceID;

        }

        set
        {
          _DeviceID = value;
          OnPropertyChanged("DeviceID");
        }
  

Комментарии:

1. Кришна, это то, что у меня есть. Базовый тип данных (_DeviceID) является частным, а свойство (DeviceID) является общедоступным. В моем случае, однако, я предоставляю DeviceID в виде строки (и делаю соответствующий корпус). Просто для удовольствия я изменил свой код, чтобы отобразить свойство как int, и не было никакой разницы в поведении. К сожалению, это не решение: (