WPF סיכום עמודה בדטה-גריד
-
יש לי דטה-גריד שבו המשתמש מזין סכומים, אני רוצה שאחר הזנת סכום או שינוי סכום קיים יופיע הסכום הכולל של כל העמודה באיזה תוית למשל.
ניסיתי להשתמש בארוע CellEditEnding וכאשר הארוע קורה לעבור בלולאה על ה DataContext של הדטה-גריד שהוא בעצם ObservableCollection ולחבר את כל המאפיינים של הסכום שמשתמש בעצם הזין, אלא שהתברר לי שהארוע הנ''ל קופץ לפני שה DataContext מתעדכן אלא מיד בעריכת התא הוא קופץ ואז יוצא שבתוית הסיכום תמיד חסר את העדכון האחרון.מה עושים?
תודה רבה לכולם ושבת שלום!
פורסם במקור בפורום CODE613 ב01/11/2013 09:51 (+02:00)
-
לדעתי זאת טעות להשתמש באירוע, אחת הבשורות של WPF הוא הנתונים המקושרים באמצעות Data Binding למד אותו היטיב וחייך יהפכו לטובים יותר, בכל כה"ג של הצגת מידע על המסך אין להשתמש אלא בדטה בינדינג כמו"כ בעוד הרבה מאוד מוניפולציות שאנשים היו רגילים לעדכן אותם בגסות, כדאי מאוד לאמץ את הרעיון של דטה בינדיג שאגב תפס מאוד בעולם התיכנות זאת המצאה של מייקרוסופט, שהרבה בקוד הפתוח מנסים לחקות אותה אחריהם, ואפילו גוגל באנגולר שלהם.
אגב אם תוכל להשלים לי את התשובה לשאלה הזאת
פורסם במקור בפורום CODE613 ב02/11/2013 19:09 (+02:00)
-
אפשרי גם אפשרי
אתה צריך ללמוד את העיקרון של דטה בינדינג, בגדול מה שאמור להיות זה ככה:
יש מאפיין שמשתנה
בשעה שהוא משתנה הוא מציף אירוע שמדווח לכל המחלקות שהמאפיין הזה השתנה (וזה על ידי אירוע בשם PropertyChanged הממומש ב INotifyPropertyChange עיין כאןהסבר)
כל מה שקשור איכשהו למשתנה הזה, מקבל את הדיווח
ממילא גם התצוגה שקשורה בדטה בינדינג לאותו מאפיין מעדכנת את עצמה ומבקשת את הערך מיידית מהמאפיין ומרעננת את התצוגה.עכשיו לענינך, הדטה גריד שלך סביר להניח שעומד מאחוריו אובייקט (דומני שזה הכרחי) האובייקט הזה הוא אוסף בדרך כלל אחד ממיני האוספים הרבים של דוט נט.
כעת האוסף הזה צריך להיות מאפיין, ולא שדה (בכל מקרה אין אפשרות לכריכת נתונים אלא על ידי מאפיין).
במקביל אתה עושה מאפיין (get בלבד, אין טעם ל set) שתפקידו יהיה להחזיר את הסכום מהאוסף הנ"ל.
הפקד שמכיל את הסכום יהיה כרוך למאפיין שנותן לו את המידע אודות הסכום.
עכשיו, אתה צריך אירוע שברגע שאותו אוסף משתנה (כלומר מתווסף לו איבר או משתנה ערך של אחד האיברים) כלומר ב set של אותו מאפיין שבעצם מכיל את המידע של הדטה גריד שלך, לעשות PropertyChanged שיכריז על [u:1l0zqa23]המאפיין שמחזיר את הסכום[/u:1l0zqa23], שהוא השתנה, כך, שהפקד התצוגתי יבצע מיידית ריענון וישאל מחדש את המאפיין של הסכום מה המצב??? ואז אותו מאפיין יפעיל את ה get שלו ויודיע לו את המצב לאשורו.כעת אינני זוכר טוב אבל ייתכן שתיתקל בקושי לעקוב אחרי האובייקט שמכיל את המערך, כלומר ייתכן שאין ריצה של set כאשר מוסיפים איבר למערך, אשר על כן מייקרוסופט עשו משהו שנקרא ObservableCollection שאמור לדעת גם מתי מוסיפים לו איבר, ויש שלא הסתפקו גם בזה ופיתחו גם TrulyObservableCollection שאל את רבי נחמן מגוגל ותמצא נחת. ואם לאו אני מניח שדוד ל.ט. יידע לעזור לך.
פורסם במקור בפורום CODE613 ב03/11/2013 19:38 (+02:00)
-
הנה כך עושים בדטה גריד שדה מחושב וגם סיכום עמודה, בבקשה תהנו:
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="386" Width="525"> <Grid> <StackPanel Margin="12,12,12,44"> <DataGrid AutoGenerateColumns="False" Height="255" Margin="0" Name="datagrid1" ItemsSource="{Binding}" RowDetailsVisibilityMode="Visible"> <DataGrid.Columns> <DataGridTextColumn Width="150" Header="Name" Binding="{Binding Path=Name}" /> <DataGridTextColumn Width="100" Header="Unit Price" Binding="{Binding Path=UnitPrice, UpdateSourceTrigger=PropertyChanged, NotifyOnTargetUpdated=True, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}"/> <DataGridTextColumn Width="100" Header="Amount" Binding="{Binding Path=Amount, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged, BindsDirectlyToSource=True}"/> <DataGridTextColumn Width="100" Header="Total" Binding="{Binding Path=Total, StringFormat=C}" IsReadOnly="True" /> </DataGrid.Columns> </DataGrid> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="{Binding ElementName=datagrid1, Path=RowHeaderActualWidth}"/> <ColumnDefinition Width="{Binding ElementName=datagrid1, Path=Columns[0].ActualWidth}"/> <ColumnDefinition Width="{Binding ElementName=datagrid1, Path=Columns[1].ActualWidth}"/> <ColumnDefinition Width="{Binding ElementName=datagrid1, Path=Columns[2].ActualWidth}"/> </Grid.ColumnDefinitions> <TextBlock /> <TextBlock Grid.Column="2">Count:</TextBlock> <TextBlock Grid.Column="3" >Avg:</TextBlock> </Grid> </StackPanel> <Label Height="28" Name="totalLabel" Width="155" BorderBrush="Black" BorderThickness="2" Margin="74,311,274,8" ContentStringFormat="C" /> <Label Content="total" Height="28" Name="Label1" Margin="7,311,404,8" /> </Grid> </Window> Imports System.Collections.ObjectModel Imports System.ComponentModel Class MainWindow WithEvents DB As New ObservableCollection(Of Product) Public Sub New() ' This call is required by the designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. datagrid1.DataContext = DB End Sub Private Function SumDB() As Single Dim total As Single = 0 For Each product As Product In DB If product.Total IsNot Nothing Then total += product.Total End If Next Return total End Function Private Sub DB_CollectionChanged(sender As Object, e As System.Collections.Specialized.NotifyCollectionChangedEventArgs) Handles DB.CollectionChanged Dim P As Product = DirectCast(e.NewItems(0), Product) AddHandler P.PropertyChanged, AddressOf ProductPropertyChangedHandler End Sub Private Sub ProductPropertyChangedHandler(sender As Object, e As PropertyChangedEventArgs) If e.PropertyName = "Total" Then totalLabel.Content = SumDB() End If End Sub End Class Public Class Product Implements INotifyPropertyChanged Public Property Name As String Private _UnitPrice As Single? Public Property UnitPrice As Single? Get Return _UnitPrice End Get Set(value As Single?) _UnitPrice = value OnPropertyChanged("UnitPrice") OnPropertyChanged("Total") End Set End Property Private _Amount As Single? Public Property Amount As Single? Get Return _Amount End Get Set(value As Single?) _Amount = value OnPropertyChanged("Amount") OnPropertyChanged("Total") End Set End Property Private _Total As Single? Public ReadOnly Property Total As Single? Get _Total = Amount * UnitPrice Return _Total End Get End Property #Region "INotifyPropertyChanged Members" Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged Public Sub OnPropertyChanged(ByVal name As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name)) End Sub #End Region End Class
פורסם במקור בפורום CODE613 ב07/11/2013 11:15 (+02:00)