Ограничить столбец в списке просмотра больше, чем X (NotifyPropertyChanged не работает)

Вот как моя программа ведет себя, когда я набираю цифры:

У меня есть список, который привязан к наблюдаемой коллекции. Вот мой код: (вы можете следить за этой частью, классы очень просты)

Элемент класса:

/// <summary>
/// Represent each row in listview
/// </summary>
public class Item : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

    void UpdateSum()
    {
        Sum = Col1;// + col2 + col3 etc
    }

    decimal _Col1;
    public decimal Col1 //                                         ||
    {                   //                                         ||
        get             //                                         ||
        {               //                                         ||              
            return _Col1; //                                       ||                              
        }                 //                                       ||              
        set               //                                       ||                
        {                 //                                    \  ||   /                        
            if (value > 100)  //                                 \ || /                                
            {                 //                                   \/                  
                Col1 = 100;  // !!!!!!!!!!!!!!!!!!!!!  HERE why does the listview does't update!!!!!!!!
                NotifyPropertyChanged("Col1");
            }else
            {
                _Col1 = value;
            }
            UpdateSum();
            NotifyPropertyChanged("Col1");
        }
    }

    decimal _Sum;
    public decimal Sum
    {
        get
        {
            return _Sum;
        }
        set
        {
            _Sum = value;

            NotifyPropertyChanged("Sum");
        }
    }
}

Код позади

using System;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace WpfApplication3
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public ObservableCollection<Item> Collection = new ObservableCollection<Item>();

        public MainWindow()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {

            Collection.Add(new Item());
            listView2.DataContext = Collection;
            listView2.ItemsSource = Collection;
            listView2.IsSynchronizedWithCurrentItem = true;
        }
    }
}

Listview в xaml:

 <ListView Name="listView2" >
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Column1" Width="200">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox Width="200" Text="{Binding Col1, UpdateSourceTrigger=PropertyChanged}"></TextBox>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="Sum" Width="200">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox Width="200" Text="{Binding Sum, UpdateSourceTrigger=PropertyChanged}"></TextBox>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

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

В любом случае, почему, когда я обновляю Col1=100 он не обновляется в списке! Также обратите внимание, что сумма составляет 100, а не 1000.

Я не хочу, чтобы column1 было больше некоторого числа x. В моей реальной программе это число изменяется динамически, и я вычисляю его внутри класса Item.

Как я могу это исправить?



редактировать

Я нашел кое-что интересное... Если я начну печатать разные цифры, взглянем на то, что происходит: я просто наберу 5 в этом примере:

Работает на шаге 3!!!

как только он становится равным 100, он перестает работать...

3 ответа

Я заставил это работать!!! Я изменился:

 Text="{Binding Col1, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"

за:

 Text="{Binding Col1, Mode=TwoWay}"

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

В основном вы пытаетесь изменить значение свойства во время привязки данных. Проблема в том, что WPF старается быть умным и не прислушиваться к изменениям свойств, возникающих во время привязки данных. Это хорошо известная проблема с многочисленными обходными путями:

Хотя MS сделала некоторые исправления в WPF4.0, см.: WPF 4.0 Изменение привязки данных (отличная функция)

Но я сделал небольшое быстрое тестирование, и ни один из них не работает в вашем случае из-за UpdateSourceTrigger=PropertyChanged,

Однако я могу найти очень грязный обходной путь, который "работает":

public decimal Col1
{
    get { return _Col1; }
    set
    {
        //Change the property value based on condition
        _Col1 = value > 100 ? 100 : value;
        UpdateSum();
        //HACK: Simulate that the property change not fired from the setter
        Dispatcher.CurrentDispatcher
            .BeginInvoke(new Action(() => NotifyPropertyChanged("Col1")));
        //HACK: Cancel the bindig based on condition
        if (value > 100)
            throw new Exception();
    }
}

Смотрите это действие:

Обратите внимание: после ввода третьего 5 курсор перемещает начало TextBox и остается там, если вы введете следующие 5.

Я не думаю, что вышеупомянутый код должен быть решением, я просто немного поиграл. Я думаю, что вы должны пойти с UpdateSourceTrigger=LostFocus и сделайте привязку вручную из текстового поля TextChanged событие... Но я боюсь, что нет чистого решения для вашей проблемы.

По сути, в TextBox есть ошибка, из-за которой, если вы измените связанное значение таким образом, обновятся только первые символы TextBox. Например, если вы ввели 1005, он обновляет первые 3 символа до 100 (но игнорирует 5).

Исправить это просто, я добавил еще одно свойство в ваш класс Item и немного изменил привязку TextBox:

public class Item : INotifyPropertyChanged
{
    private int maxValue = 100;
    public event PropertyChangedEventHandler PropertyChanged;

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

    void UpdateSum()
    {
        Sum = Col1;// + col2 + col3 etc
    }

    decimal _Col1;
    public decimal Col1 
    {                  
        get            
        {                         
            return _Col1;                             
        }                          
        set                       
        {                       
            if (value > maxValue)                                
            {                                
                Col1 = maxValue; 
                NotifyPropertyChanged("Col1");
            }
            else
            {
                _Col1 = value;
            }
            UpdateSum();
            NotifyPropertyChanged("Col1");
        }
    }

    public int MaxValueWidth
    {
        get
        {
            var tmp = (int)Math.Log10(maxValue) + 1;
            return tmp;
        }
    }

    decimal _Sum;
    public decimal Sum
    {
        get
        {
            return _Sum;
        }
        set
        {
            _Sum = value;
            NotifyPropertyChanged("Sum");
        }
    }
}

Обратите внимание, что я добавил свойство, которое вычисляет максимальные символы для базы TextBox на основе максимального значения.

Нет, все, что я делаю, это добавляю привязку

<DataTemplate>
    <TextBox Width="200" Text="{Binding Col1, UpdateSourceTrigger=PropertyChanged}" MaxLength="{Binding MaxValueWidth}"></TextBox>
</DataTemplate>
Другие вопросы по тегам