2009-05-12 8 views
0

Ich habe den Trick erfolgreich angewendet here erklärt. Aber ich habe immer noch ein Problem.GroupStyle Summe nicht aktualisiert, wenn mehrere Elemente

Kurzer Rückblick: Ich zeige Benutzer in einem ListView an. Die Benutzer werden nach Land gruppiert, und in GroupStyle DataTemplate wird die Summe aller gruppenbezogenen Benutzer angezeigt. Insgesamt wird ein Konverter verwendet. UI-Benutzer können jedoch den Eigenschaftswert "Total" von Benutzern über ein modales Fenster ändern.

Wenn nur ein Element in der Gruppe vorhanden ist, werden sowohl die angezeigte Benutzergesamtmenge als auch die Summe ordnungsgemäß aktualisiert. Wenn jedoch mehrere Elemente in der Gruppe vorhanden sind, wird nur die Benutzergesamtmenge aktualisiert (durch Bindung), aber der Konverter, der die Summe bilden soll (TotalSumConverter), wird nicht einmal aufgerufen!

Haben Sie eine Idee, wo es herkommen könnte? Sollte ich einen Trigger verwenden, um sicherzustellen, dass der Konverter aufgerufen wird, wenn eine Änderung an den Elementen vorgenommen wird?

Antwort

0

Der Trick, den Sie verwenden, bindet die Gruppenfußzeile an ListView.Items, die Ihre Ansicht nicht automatisch aktualisiert, wie beispielsweise ein DependencyObject. zwingen stattdessen eine Aktualisierung nach jedem Update wie folgt Total:

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

Das Problem mit der Ansicht, erfrischend ist, dass sie es komplett erneuert, und ich habe Expandern für meine Gruppierung, die zurück in den ursprünglichen Zustand zu erweitern, selbst wenn der Benutzer sie geschlossen hat. Es ist also eine mögliche Problemumgehung, aber es ist nicht vollständig zufriedenstellend.

Auch Ihre DependencyObject-Erklärung ist interessant, aber warum funktioniert es, wenn ich nur ein Element in meiner Gruppe habe?

3

Das Problem besteht darin, dass der Wertkonverter, der die Summe für alle Elemente in einer Gruppe berechnet, nicht ausgeführt wird, wenn ein Element geändert wird, da keine Benachrichtigung für geänderte Elemente vorhanden ist. Eine Lösung besteht darin, an etwas anderes zu binden, das Sie steuern können, wie es Benachrichtigungen ausführt, und den Gruppenkopf bei Bedarf zu benachrichtigen.

Unten ist ein funktionierendes Beispiel. Sie können die Anzahl für einen Benutzer im Textfeld ändern und die Summe wird neu berechnet.

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> 

-Code hinter:

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