【问题标题】:Restrict column in listview from being greater than X (NotifyPropertyChanged not working)限制列表视图中的列大于 X(NotifyPropertyChanged 不起作用)
【发布时间】:2012-04-27 09:37:08
【问题描述】:

以下是我输入数字时程序的行为:

我有一个绑定到可观察集合的列表视图。这是我的代码:(你可以忽略这部分,类很简单)

类项:

/// <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;
        }
    }
}

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,它就会停止工作......

【问题讨论】:

  • 你不应该将财产更改两次,最后一个就足够了。
  • 这应该对你没有帮助,但在 Col1 的设置器中,将 if(value &gt; 100){ Col1=100; ... 更改为 if(value &gt; 100){ _Col1=100; ...

标签: c# wpf data-binding observablecollection inotifypropertychanged


【解决方案1】:

基本上,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>

【讨论】:

  • 我用你发布的那个替换了我的 Item 类。我还将 xaml 中的 TextBox 替换为您在此处发布的文本框。我仍然得到相同的行为。也许是因为我的文本框在网格视图内?
【解决方案2】:

基本上,您是在尝试在 DataBinding 期间更改属性值。问题是 WPF 试图变得聪明,而不是监听 DataBinding 期间引发的属性更改。 这是一个众所周知的问题,有许多解决方法:

虽然 MS 在 WPF4.0 中做了一些修复,请参阅:WPF 4.0 Data Binding Change (great feature)

但我做了一些快速测试,但由于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 事件手动进行绑定...但恐怕您的问题没有干净的解决方案。

【讨论】:

  • 我应该将//HACK: Cancel the bindig based on condition if (value &gt; 100) throw new Exception(); 包装在try catch 块中吗?如果我这样做,我会得到相同的行为......也许我做错了什么......
  • 理论上你不需要try catch。我只使用您的示例代码创建了我的复制品。而且我只更改了Col1 属性...我使用了.net 4.0 客户端配置文件...
【解决方案3】:

我成功了!!!我改变了:

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

为:

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

但我需要在文本框更改时更新属性,所以这可能是其他人的解决方案......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    相关资源
    最近更新 更多