0

我已经成功地应用了这里解释的技巧。但我还有一个问题。

快速回顾:我在 ListView 中显示用户。用户按国家/地区重新分组,在 GroupStyle DataTemplate 中,我使用转换器显示所有与组相关的 Users.Total 的总和。但 UI 用户可以通过模式窗口更改用户的“总计”属性值。

当组中只有一项时,显示的用户总数和总和都会正确更新。但是当组中有多个项目时,仅更新用户总数(通过绑定),但甚至不调用应该进行总和的转换器(TotalSumConverter)!

你知道它可能来自哪里吗?我应该使用某种触发器来确保在项目中有修改时调用转换器吗?

4

3 回答 3

4

问题是计算组中所有项目总和的值转换器在项目更改时不会运行,因为没有通知更改项目。一种解决方案是绑定到其他东西,您可以控制它如何进行通知并在需要时通知组头。

下面是一个工作示例。您可以在文本框中更改用户的计数,然后重新计算总数。

XAML:

<Window x:Class="UserTotalTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:userTotalTest="clr-namespace:UserTotalTest"
    Title="Window1" Height="300" Width="300"
    Name="this">

    <Window.Resources>

        <userTotalTest:SumConverter x:Key="SumConverter" />

        <CollectionViewSource Source="{Binding Path=Users}" x:Key="cvs">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="Country"/>
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>

    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="10" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <ListView 
            Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
            ItemsSource="{Binding Source={StaticResource cvs}}">
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}" />
                        <GridViewColumn Header="Count" DisplayMemberBinding="{Binding Path=Count}" />
                    </GridView.Columns>
                </GridView>
            </ListView.View>
            <ListView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <StackPanel Margin="10">
                                            <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" />
                                            <ItemsPresenter />
                                            <TextBlock FontWeight="Bold">
                                                <TextBlock.Text>
                                                    <MultiBinding Converter="{StaticResource SumConverter}">
                                                        <MultiBinding.Bindings>
                                                            <Binding Path="DataContext.Users" ElementName="this" />
                                                            <Binding Path="Name" />
                                                        </MultiBinding.Bindings>
                                                    </MultiBinding>
                                                </TextBlock.Text>
                                             </TextBlock>
                                        </StackPanel>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </ListView.GroupStyle>
        </ListView>
        <ComboBox Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" 
            ItemsSource="{Binding Path=Users}"
            DisplayMemberPath="Name" 
            SelectedItem="{Binding Path=SelectedUser}" />
        <TextBlock Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Path=SelectedUser.Country}" />
        <TextBox Grid.Row="4" Grid.Column="1" Text="{Binding Path=SelectedUser.Count}" />
    </Grid>
</Window>

后面的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;

namespace UserTotalTest
{
    public partial class Window1 : Window
    {
        public Window1() 
        {
            InitializeComponent();

            DataContext = new UsersVM();
        }
    }

    public class UsersVM : INotifyPropertyChanged
    {
        public UsersVM()
        {
            Users = new List<User>();
            Countries = new string[] { "Sweden", "Norway", "Denmark" };
            Random random = new Random();
            for (int i = 0; i < 25; i++)
            {
                Users.Add(new User(string.Format("User{0}", i), Countries[random.Next(3)], random.Next(1000)));
            }

            foreach (User user in Users)
            {
                user.PropertyChanged += OnUserPropertyChanged;
            }

            SelectedUser = Users.First();
        }

        private void OnUserPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Count")
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Users"));
            }
        }

        public List<User> Users { get; private set; }

        private User _selectedUser;
        public User SelectedUser
        {
            get { return _selectedUser; }
            set 
            {
                _selectedUser = value; if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("SelectedUser"));
                }
            }
        }

        public string[] Countries { get; private set; }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }

    public class User : INotifyPropertyChanged
    {
        public User(string name, string country, double total)
        {
            Name = name;
            Country = country;
            Count = total;
        }

        public string Name { get; private set; }
        private string _country;
        public string Country
        {
            get { return _country; }
            set
            {
                _country = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Country"));
                }
            }
        }

        private double _count;
        public double Count
        {
            get { return _count; }
            set
            {
                _count = value; if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Count"));
                }
            }
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }

    public class SumConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            IEnumerable<User> users = values[0] as IEnumerable<User>;
            string country = values[1] as string;
            double sum = users.Cast<User>().Where(u =>u.Country == country).Sum(u => u.Count);
            return "Count: " + sum;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
于 2010-02-11T16:28:16.917 回答
0

您使用的技巧将组页脚数据绑定到 ListView.Items 不会自动更新您的视图,例如 DependencyObject 所做的那样。而是在每次更新 Total 后强制刷新,如下所示:

CollectionViewSource viewSource = FindResource("ViewSource") as CollectionViewSource;
viewSource.View.Refresh();
于 2009-05-12T17:10:01.423 回答
0

刷新视图的问题在于它完全刷新了它,并且我的分组有扩展器,即使用户关闭它们,它们也会扩展回原来的状态。所以是的,这是一种可能的解决方法,但并不完全令人满意。

您的 DependencyObject 解释也很有趣,但是,为什么当我的组中只有一个项目时它会起作用?

于 2009-05-17T11:07:01.363 回答