2009-05-12 2 views
0

Я успешно применил трюк, поясненный here. Но у меня все еще есть одна проблема.GroupStyle сумма не обновляется, когда несколько элементов

Краткое описание: Я показываю пользователей в ListView. Пользователи перегруппированы по странам, а в GroupStyle DataTemplate отображает сумму всех связанных с Группой пользователей. Всего, используя конвертер. Но пользователи пользовательского интерфейса могут изменять значение «Всего» для пользователей через модальное окно.

Если в группе имеется только один элемент, отображаются как отображаемые пользователем, так и сумма. Но когда в группе есть несколько элементов, обновляется только User Total (через привязку), но конвертер, который должен сделать сумму (TotalSumConverter), даже не называется!

У вас есть идеи, откуда оно взялось? Должен ли я использовать какой-то триггер, чтобы убедиться, что конвертер вызывается, когда есть изменения в элементах?

ответ

0

Уловка, которую вы используете, привязывает нижний колонтитул группы к элементу ListView.Items, который не будет автоматически обновлять ваш вид, например, например, DependencyObject. Вместо принудительного обновления после каждого обновления к совокупным так:

CollectionViewSource viewSource = FindResource("ViewSource") as CollectionViewSource; 
viewSource.View.Refresh(); 
0

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

Также интересно ваше объяснение DependencyObject, но тогда почему он работает, когда у меня есть только один элемент в моей группе?

3

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

Ниже приведен рабочий пример. Вы можете изменить счетчик для пользователя в текстовом поле, а итоговые значения пересчитываются.

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(); 
     } 
    } 
}