Column מותאם אישית בהורשה מ DataGridTemplateColumn
-
יצרתי Column מותאם אישית היורש מ DataGridTemplateColumn ואני מקבל שגיאה.
להלן הקוד ב XAML:<DataGridTemplateColumn x:Class="DataGridActiveColumn" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:abc="clr-namespace:abc.Windows;assembly=abc" xmlns:my="clr-namespace:myProject"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Canvas Canvas.Left="0" Canvas.Top="0" Width="512" Height="512"> <Canvas.Resources /> <Path Data="M -1,0 A 1,1 0 1 1 1,0 M -1,0 A 1,1 0 1 0 1,0"> <Path.Style> <Style TargetType="Path"> <Style.Triggers> <DataTrigger Binding="{Binding Binding}" Value="1"> <Setter Property="Fill" Value="Yellow" /> </DataTrigger> <DataTrigger Binding="{Binding Binding}" Value="0"> <Setter Property="Fill" Value="Green" /> </DataTrigger> <DataTrigger Binding="{Binding Binding}" Value="-1"> <Setter Property="Fill" Value="Red" /> </DataTrigger> </Style.Triggers> </Style> </Path.Style> </Path> </Canvas> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
ולהלן הקוד ב class
Public Class DataGridActiveColumn Private Shared ReadOnly BindingProperty = DependencyProperty.Register("Binding", GetType(Integer), GetType(DataGridActiveColumn)) Property Binding As Integer Get Return GetValue(BindingProperty) End Get Set(value As Integer) SetValue(BindingProperty, value) End Set End Property End Class
וכך אני קורא לו בחלון אחר XAML
<my:DataGridActiveColumn Binding="{Binding IsCurrent}"/>
אך אני מקבל את השגיאה:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IsCurrent; DataItem=null; target element is 'DataGridActiveColumn' (HashCode=55555304); target property is 'Binding' (type 'Int32')
מישהו יכול לעזור לי בזה ?
תודה מראש.פורסם במקור בפורום CODE613 ב30/03/2015 13:23 (+03:00)
-
יש לך כמה וכמה טעויות.
דבר ראשון, גם אם היה עובד לך בלי שגיאות, הCellTemplate שטרחת לכתוב לא היה חל על המופע שיצרת בXAML. כלומר בכל פעם שהיית מכריז על הmy:DataGridActiveColumn היית חייב לכתוב בפירוש שוב את כל הטמפלט שכתבת תחת המאפיין CellTemplate. למה? כי הXAML שעשית זה מופע, זה לא חלק מהגדרת האובייקט.
דבר שני - טיפ'לה מסובך: הBinding בגוף העמודה, לא מתייחס לרמת השורה! כלומר אתה מניח שעבור כל שורה הWPF מחפש אחר מאפיין IsCurrent באובייקט הנוכחי - זה של השורה הזו. אבל זו טעות! כי הרי האובייקט DataColumn לא נוצר בכל שורה. הוא קיים רק ברמת הטבלה. אלא שעל פיו נוצרים תאים כפי מה שהוגדר בטמפלט. זהו. כעת הטמפלט חופשיה לקחת מההקשר ברמת השורה, רק שאצלך הטמפלט נשען על ההקשר של כל העמודה (שיש רק אחד בכל הטבלה, לא אחד לכל שורה!).
נשאלת השאלה, אז איך עובד המאפיין Binding שעשו מיקרוסופט לעמודות כמו DataGridTextColumn? אז זהו שזה טריקי, ובעצם הם "מעתיקים" את הבינדינג לטמפלט - רמת השורה. אבל לך הכי פשוט זה לעשות את הבינדינג ישירות ברמת הטמפלט.
דבר שלישי - לכאורה, אתה בכלל לא צריך ליצור קלאס משלך. אולי יש לך סיבה שלא ביטאת באשכול כאן, אבל לפי הנתונים כאן, אתה סה"כ צריך להשתמש בטמפלט.לסיכום:
א. בנוגע לעיצוב, אתה חייב לעבוד עם סטייל/טמפלט. אין כזה דבר (יש אבל עזוב :)) עיצוב ברמת המחלקה. ממילא את כל הCellTemplate שים בResource של האפליקציה/חלון וכדומה, ותאגד לעמודה שלך ע"י StaticReaource.
ב. את הבינדינג לIsCurrent תעשה אך ורק בטמפלט בלי "גשרים". במקום לאגד את הטריגר שלך למאפיין שמאוגד למקור, אגד את הטריגר ישירות לIsCurrent.
ג. שקול אם בכלל ליצור DataColumn משלך. לכאורה זה מיותר. אם יש לך סיבה מאוד כדאי שתתייעץ גם על זה כי אני ב99.99% שאין צורך. במידה וכן, עשה זאת בלי שום XAML. סתם מחלקה רגילה, עם הצהרת ירושה. כל העסק של הסטייל תעשה עם סטיילים/טמפלטים כמבואר.הנה דוגמה קלילה להמחשה. במקום מקור נתונים של שמתי אוסף בItems. השמשתי בButton סתם בתור מחלקה כל שהיא. במקום IsCurrent (שאינו קיים במחלקה Button...) השתמשתי בWidth.
הנה, אתה יכול להדביק אצלך ולראות איך זה:<Grid> <Grid.Resources> <DataTemplate x:Key="MyTemplate"> <Grid Width="50" Height="50"> <Path Data="M -1,0 A 1,1 0 1 1 1,0 M -1,0 A 1,1 0 1 0 1,0" Stretch="Fill" > <Path.Style> <Style TargetType="Path"> <Setter Property="Fill" Value="Blue" /> <Style.Triggers> <DataTrigger Binding="{Binding Width}" Value="1"> <Setter Property="Fill" Value="Yellow" /> </DataTrigger> <DataTrigger Binding="{Binding Width}" Value="0"> <Setter Property="Fill" Value="Green" /> </DataTrigger> <DataTrigger Binding="{Binding Width}" Value="-1"> <Setter Property="Fill" Value="Red" /> </DataTrigger> </Style.Triggers> </Style> </Path.Style> </Path> </Grid> </DataTemplate> </Grid.Resources> <DataGrid > <DataGrid.Items> <Button Width="0"/> <Button Width="1" /> <Button Width="0" /> </DataGrid.Items> <DataGrid.Columns> <DataGridTemplateColumn CellTemplate="{StaticResource MyTemplate }" /> </DataGrid.Columns> </DataGrid> </Grid>
פורסם במקור בפורום CODE613 ב30/03/2015 18:47 (+03:00)
-
אתגרת אותי.
דבר ראשון, טעיתי בנוגע ל"טעויות" שלך. לפחות הראשונה. XAML בטח מגדיר את המחלקה. פשוט טעות גסה שלי.
אז נמחק את הטעות הראשונה ואת המסקנה שבאה בעקבותיה.
גם כן הייתי פזיז בקשר למחלקה, שאכן נצרכת, כדי לעשות שימוש חוזר בסטייל שכל פעם הנתיב שלו שונה.אז בסוף פתחתי את הרפלקטור כדי לראות בדיוק איך נוצרים התאים ובאיזה רמה הקונקסט/בינדינג מוזרקים.
והמסקנה היא כזו מחלקה:Public Class DataGridActiveColumn Inherits DataGridBoundColumn Protected Overrides Function GenerateEditingElement(cell As DataGridCell, dataItem As Object) As FrameworkElement Return Nothing End Function Protected Overrides Function GenerateElement(cell As DataGridCell, dataItem As Object) As FrameworkElement If Binding IsNot Nothing Then BindingOperations.SetBinding(cell, DataGridCell.DataContextProperty, Binding) End If Return Nothing End Function End Class
הנה הדגמה:
<Grid> <Grid.Resources> <Style TargetType="DataGridCell" > <Style.Setters> <Setter Property="Template" > <Setter.Value> <ControlTemplate> <Grid Height="50" Width="50" > <Path Data="M -1,0 A 1,1 0 1 1 1,0 M -1,0 A 1,1 0 1 0 1,0" Stretch="Fill" > <Path.Style> <Style TargetType="Path"> <Style.Triggers> <DataTrigger Binding="{Binding}" Value="1"> <Setter Property="Fill" Value="Yellow" /> </DataTrigger> <DataTrigger Binding="{Binding}" Value="0"> <Setter Property="Fill" Value="Green" /> </DataTrigger> <DataTrigger Binding="{Binding}" Value="2"> <Setter Property="Fill" Value="Red" /> </DataTrigger> </Style.Triggers> </Style> </Path.Style> </Path> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style.Setters> </Style> </Grid.Resources> <DataGrid > <DataGrid.Items> <Button Width="0"/> <Button Width="1" /> <Button Width="2" /> </DataGrid.Items> <DataGrid.Columns> <local:DataGridActiveColumn Binding="{Binding Width}" /> </DataGrid.Columns> </DataGrid> </Grid>
פורסם במקור בפורום CODE613 ב02/04/2015 17:29 (+03:00)