locked
איך אפשר לערוך DataTemplate של GridView.ItemTemplate בקוד C# ולא בקוד Xml וגם לא בקוד Xml דרך הקוד הרגיל. RRS feed

  • שאלה

  •                     var str = @"<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">" +
                            @"<StackPanel VerticalAlignment=""Stretch"" HorizontalAlignment = ""Stretch"" Background=""Pink"" Orientation=""Vertical"">" +
                            @"<TextBlock Text=""{Binding DayLoaz}"" FontSize=""13"" Foreground=""yellow""/>" +
                            @"<TextBlock Text=""{Binding DayIvri}"" FontSize=""13"" Foreground=""yellow""/>" +
                            @"</StackPanel>" +
                            @"</DataTemplate>";
                        return ((DataTemplate)Windows.UI.Xaml.Markup.XamlReader.Load(str));

    זה דוגמא לעריכה דרך קוד C# במחרוזת XML אבל אני מעונין לערוך את כל המבנה והטקסטבוקסים וכו' הכל בקוד. כמו לדוגמא זאת

                 DataTemplate cardLayout = new DataTemplate();
    
                 StackPanel sp = new StackPanel() { Orientation = Orientation.Vertical };
                
                 // Create the binding description.
                 Binding b = new Binding();
                 b.Mode = BindingMode.OneWay;
                 b.Source = "masad";
    
                 // Attach the binding to the target.
                 TextBlock cardHolder = new TextBlock() { FontSize = 18};
                 cardHolder.SetBinding(TextBlock.TextProperty, b);
                 cardHolder.Foreground = new SolidColorBrush(Windows.UI.Colors.Green);
    
                 sp.Children.Add(cardHolder);

    רק שאת השורה האחרונה איך מוסיפים ל DataTemplate את ה- StackPanel עם כל ילדיו. שים לב!! אין כאן VisualTree או AddChild. כוונתם היתה למשהוא אחר שאין לי מושג. תודה לכל מי שיצליח לענות בבקשה.
    יום רביעי 12 דצמבר 2012 21:09

תשובות

  • הי צבי,

    עם כל כך הרבה מלל טכני בעברית, פספסתי את המטרה.

    אם הבנתי אותך נכון, יש לך DataTemplate ואתה מעוניין לשנות תכונות של רכיבים שמוגדרים בעץ הויזואלי שנבנה, כגון צבע רקע, גודל וכו', אבל לא את מבנה העץ.ב-WPF הייתי ממליץ בחום על Triggers, מנגנון מדהים שלא טרחו להכניס ל- SL. לענייננו:

    1. פתרון יחסית פשוט זה לעבוד עם Value Converters, כך שאתה מבצע Binding מתוך ה- DataTemplate על תכונה בנתונים, וה- Converter מבצע את ההמרה הרלוונטית. צבע, גודל, וכו'.
    2. אפשרות נוספת, להשתמש ב- ContentControl עם ContentTemplate בחלקים מתוך ה- DataTemplate החיצוני שאתה יודע שהולכים להשתנות.
    3. אפשרות נוספת זה לעבוד עם VSM, אבל קיים סירבול מסוים לבחור את ה- State הרלוונטי בתלות ב- Data.

    נב, עניתי על שאלתך בנושא gridview. אשמח אם תיתן קרדיט ותסמן תשובותי כתשובה.

    תומר


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.



    יום ראשון 16 דצמבר 2012 17:34
    מנחה דיון
  •  דבר ראשון תודה רבה על הענות.

     דבר שני סליחה! חשבתי שהסבר בעברית יהיה עדיף.

    דבר שלישי..

    האפשרות 2 שהצגת שהיא על ידי ContentTemplate  בזה בדיוק היתה לי הבעיה כמו שהסברתי שאם עובדים עם DataTemplateSelector  שזה בעצם בורר טמפלטים. ContentTemplate   זה אובייקט של DataTemplate . ואין אפשרות לבנות בקוד לא XML. והאפשרות היחידה במקרה הזה היא לא להשתמש ב-ContentTemplate אלא במאפיין Content בלבד. כמו שהסברת לקחת חלקים מהטמפלט. על ידי DataTemplate.LoadContent.

    וכמו שכבר הבאתי שזה מסרבל קצת להגדיר בקוד את ה-Content כיון שאם משתמשים עם Selector שזה בורר טמפלטים. ( עיין MSDN בפירוט קוד.) זה גורם לבורר לקרא לבירור שוב. דוגמא של קוד. השתמשי באייטם מסוג MyClass שמכיל שני מאפיינים masad ן- name

        public class MyTemplateSelector : DataTemplateSelector
        {
    
            public DataTemplate DefaultTemplate { get; set; }
    
    
            protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
            {
    	    if(!item is MyClass) return null;
                GridViewItem gvi = (GridViewItem)container;
                var itm = item as MyClass;
    
                    if (itm.masad < 21)
                    {
                        var str = @"<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">" +
                            @"<Border Background=""LightGray"" Height=""70"" Width=""200"">" +
                                    @"<StackPanel Orientation=""Vertical"">" +
                                        @"<TextBlock Text=""{Binding masad}"" FontSize=""18"" Foreground=""yellow""/>" +
                                        @"<TextBlock Text=""{Binding name}"" FontSize=""18"" Foreground=""yellow""/>" +
                                    "</StackPanel>" +
                                "</Border>" +
                            "</DataTemplate>";
                        return (DataTemplate)Windows.UI.Xaml.Markup.XamlReader.Load(str);
                    }
                    else
                    {
                        StackPanel sp = new StackPanel() { Orientation = Orientation.Vertical ,Height = 70 ,Width = 200};
    
                        // Create the binding description.
                        Binding b = new Binding();
                        b.Mode = BindingMode.OneWay;
                        b.Source = "masad";
    
                        // Attach the binding to the target.
                        TextBlock cardHolder = new TextBlock() { FontSize = 12 };
                        cardHolder.SetBinding(TextBlock.TextProperty, b);
                        cardHolder.Foreground = new SolidColorBrush(Windows.UI.Colors.Green);
    
                        sp.Children.Add(cardHolder);
                        Binding b1 = new Binding();
                        b1.Mode = BindingMode.OneWay;
                        b1.Source = "name";
    
                        // Attach the binding to the target.
                        TextBlock cardHolder1 = new TextBlock() { FontSize = 12 };
                        cardHolder1.SetBinding(TextBlock.TextProperty, b1);
                        cardHolder1.Foreground = new SolidColorBrush(Windows.UI.Colors.Green);
                                            sp.Children.Add(cardHolder1);
                        
                        gvi.Content = sp;//כאן הוא קורא שוב למתודה הנוכחית                    
                        return null;
                    }
    
                
                return base.SelectTemplateCore(item, container);
            }
        }
    

    לגבי האפשרות השלישית זה לא רלוונטי וזה הרבה יותר מסרבל.

    אבל לגבי האפשרות הראשונה לא חשבתי על זה ובאמת זה נראה לי רעיון הכי טוב בפרט שאני עובד על ניהול טבלאות של נתונים שהעיצוב משתנה בעיקבות נתונים והכל מקושר בבינדינג.

    אבל עדיין לפעמים צריך שינוי בעץ עצמו וחבל... בכל אופן אפשר להגדיר את זה כסיכום העניין. ותודה על הסבלנות.

    נ.ב. אם שמת לב פתחתי שרשור לגבי שוליים ב-גריד ואף אחד לא ענה לי.


    צבי דויטש

    • סומן כתשובה על-ידי צבי דויטש יום ראשון 16 דצמבר 2012 20:53
    יום ראשון 16 דצמבר 2012 20:50

כל התגובות

  • צבי שלום,

    אפשר לדעת מה המוטיבציה לעשות זאת, ולמה לא להגדיר את ה- DataTemplate מ- XAML?

    תומר


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    יום ראשון 16 דצמבר 2012 15:01
    מנחה דיון
  • להוסיף למה שתומר כתב

    1. מנסיוני אין סיבה אמיתית להגדיר בקוד טמפלט ולא בזאמל. 
    2. מנסיון (כואב), זה ממש ממש סיפור להגדיר את זה מקוד


    http://blogs.microsoft.co.il/blogs/eladkatz @ElatKt

    יום ראשון 16 דצמבר 2012 15:09
  •  הסיבה נורא פשוטה.

    אם עובדים עם DataTemplateSelector שהוא דורש להחזיר בדווקא DataTemplate במידה ויש לך הבדל רק בסוג צבע והטמפלט שלך הוא באורך קילומטר. אתה צריך להעתיק פעמיים ולא נדבר על כמה סוגי צבעים שזה כפול כמספר הצבעים,

    ובנוסף על זה אם אתה צריך גם לשנות אורך רוחב על פי נתונים שמתמלאים זה מאד לא נח.

    והוסיף פרט מאד חשוב.

    בשימוש עם DataTemplateSelector המתודה SelectTemplateCore נקראת בזמן מילוי נתונים לדוגמא ב- GridViewItem כשהמאפיין Content משתנה. הוא מקבל את הטמפלט מהמתודה. ואחר כך משתמש במתודה של DataTemplate.LoadContent()  ובזה ממלא ערך בContent של ה-GridViewItem.

    במידה ותתעקש אתה יכול להחזיר NULL במתודה ובמשתנה CONTAINER של המתודה SelectTemplateCore להכניס לבד Content . רק שאז כיון שהכנסת לו באופן ידני לתוך ה-Content  הוא יקרא לעצמו שוב. כיון שכל פעם שמשתנה המאפיין הזה הוא בודק אפשריות של טמפלטים. ואז תצטרך להגדיר לו שאם זה קריאה שנייה אל תעשה כלום ותחזיר NULL. לדוגמא ב-GridViewItem  שמתמלא מתוך מערך בפעם הראשונה המשתנה ITEM של מתודה SelectTemplateCore  הוא הערך של האינדקס הנוכחי של המערך. ובפעם השנייה זה יהיה הCONTENT שהכנסת לבד שזה הטמפלט הפרטי שלך. ואז מגדירים שאם זה לא אייטם מהמערך תחזיר נלל.

    לדעתי זה טעות, או שכחה , שאין אפשרות ליצור טמפלט. וכמובן לכל יודע ASP שהשימוש ברעיון היה אותו דבר. שהיה שם VISUALTREE ו FECTORY וכו'.

     

     

     

     

     

     

     

     

     


    צבי דויטש

    יום ראשון 16 דצמבר 2012 16:36
  • הי צבי,

    עם כל כך הרבה מלל טכני בעברית, פספסתי את המטרה.

    אם הבנתי אותך נכון, יש לך DataTemplate ואתה מעוניין לשנות תכונות של רכיבים שמוגדרים בעץ הויזואלי שנבנה, כגון צבע רקע, גודל וכו', אבל לא את מבנה העץ.ב-WPF הייתי ממליץ בחום על Triggers, מנגנון מדהים שלא טרחו להכניס ל- SL. לענייננו:

    1. פתרון יחסית פשוט זה לעבוד עם Value Converters, כך שאתה מבצע Binding מתוך ה- DataTemplate על תכונה בנתונים, וה- Converter מבצע את ההמרה הרלוונטית. צבע, גודל, וכו'.
    2. אפשרות נוספת, להשתמש ב- ContentControl עם ContentTemplate בחלקים מתוך ה- DataTemplate החיצוני שאתה יודע שהולכים להשתנות.
    3. אפשרות נוספת זה לעבוד עם VSM, אבל קיים סירבול מסוים לבחור את ה- State הרלוונטי בתלות ב- Data.

    נב, עניתי על שאלתך בנושא gridview. אשמח אם תיתן קרדיט ותסמן תשובותי כתשובה.

    תומר


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.



    יום ראשון 16 דצמבר 2012 17:34
    מנחה דיון
  •  דבר ראשון תודה רבה על הענות.

     דבר שני סליחה! חשבתי שהסבר בעברית יהיה עדיף.

    דבר שלישי..

    האפשרות 2 שהצגת שהיא על ידי ContentTemplate  בזה בדיוק היתה לי הבעיה כמו שהסברתי שאם עובדים עם DataTemplateSelector  שזה בעצם בורר טמפלטים. ContentTemplate   זה אובייקט של DataTemplate . ואין אפשרות לבנות בקוד לא XML. והאפשרות היחידה במקרה הזה היא לא להשתמש ב-ContentTemplate אלא במאפיין Content בלבד. כמו שהסברת לקחת חלקים מהטמפלט. על ידי DataTemplate.LoadContent.

    וכמו שכבר הבאתי שזה מסרבל קצת להגדיר בקוד את ה-Content כיון שאם משתמשים עם Selector שזה בורר טמפלטים. ( עיין MSDN בפירוט קוד.) זה גורם לבורר לקרא לבירור שוב. דוגמא של קוד. השתמשי באייטם מסוג MyClass שמכיל שני מאפיינים masad ן- name

        public class MyTemplateSelector : DataTemplateSelector
        {
    
            public DataTemplate DefaultTemplate { get; set; }
    
    
            protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
            {
    	    if(!item is MyClass) return null;
                GridViewItem gvi = (GridViewItem)container;
                var itm = item as MyClass;
    
                    if (itm.masad < 21)
                    {
                        var str = @"<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">" +
                            @"<Border Background=""LightGray"" Height=""70"" Width=""200"">" +
                                    @"<StackPanel Orientation=""Vertical"">" +
                                        @"<TextBlock Text=""{Binding masad}"" FontSize=""18"" Foreground=""yellow""/>" +
                                        @"<TextBlock Text=""{Binding name}"" FontSize=""18"" Foreground=""yellow""/>" +
                                    "</StackPanel>" +
                                "</Border>" +
                            "</DataTemplate>";
                        return (DataTemplate)Windows.UI.Xaml.Markup.XamlReader.Load(str);
                    }
                    else
                    {
                        StackPanel sp = new StackPanel() { Orientation = Orientation.Vertical ,Height = 70 ,Width = 200};
    
                        // Create the binding description.
                        Binding b = new Binding();
                        b.Mode = BindingMode.OneWay;
                        b.Source = "masad";
    
                        // Attach the binding to the target.
                        TextBlock cardHolder = new TextBlock() { FontSize = 12 };
                        cardHolder.SetBinding(TextBlock.TextProperty, b);
                        cardHolder.Foreground = new SolidColorBrush(Windows.UI.Colors.Green);
    
                        sp.Children.Add(cardHolder);
                        Binding b1 = new Binding();
                        b1.Mode = BindingMode.OneWay;
                        b1.Source = "name";
    
                        // Attach the binding to the target.
                        TextBlock cardHolder1 = new TextBlock() { FontSize = 12 };
                        cardHolder1.SetBinding(TextBlock.TextProperty, b1);
                        cardHolder1.Foreground = new SolidColorBrush(Windows.UI.Colors.Green);
                                            sp.Children.Add(cardHolder1);
                        
                        gvi.Content = sp;//כאן הוא קורא שוב למתודה הנוכחית                    
                        return null;
                    }
    
                
                return base.SelectTemplateCore(item, container);
            }
        }
    

    לגבי האפשרות השלישית זה לא רלוונטי וזה הרבה יותר מסרבל.

    אבל לגבי האפשרות הראשונה לא חשבתי על זה ובאמת זה נראה לי רעיון הכי טוב בפרט שאני עובד על ניהול טבלאות של נתונים שהעיצוב משתנה בעיקבות נתונים והכל מקושר בבינדינג.

    אבל עדיין לפעמים צריך שינוי בעץ עצמו וחבל... בכל אופן אפשר להגדיר את זה כסיכום העניין. ותודה על הסבלנות.

    נ.ב. אם שמת לב פתחתי שרשור לגבי שוליים ב-גריד ואף אחד לא ענה לי.


    צבי דויטש

    • סומן כתשובה על-ידי צבי דויטש יום ראשון 16 דצמבר 2012 20:53
    יום ראשון 16 דצמבר 2012 20:50