איך אתם מעצבים טופס בWPF?
-
מעניין לשמוע אם יש למישהו עצות איך לעצב טופס בWPF בקלות ובפשטות,
בצורה כזאת שכאשר מרחיבים את הטופס לא כל הפקדים מתפזרים לכל עבר..
יש אפשרות אחת לנעול ולא לתת למשתמש להרחיב את הטופס, נכון? האם פשוט זה מה שעושים?
אך אם אני רוצה שזה יתאים למסך שלו, ושהוא יוכל לשחק בגודל כאוות נפשו, אז איך כדאי להגדיר את כל הפקדים כדי שהם יתרחבו / יקטנו לפי הצורך?
אני חשבתי לעבוד עם הGrid ולחלק אותו למספר העמודות והשורות שאני צריך, אך לא להגדיר את הגודל שלהם אלא גודל אוטו' (עם כוכביות, כך שאם אני צריך שעמודה/שורה אחת תהיה יותר גדולה יחסית אני אתן לה כמה כוכביות). ואת הפקדים (תיבות טקסט/label/ כפתורים וכדו') אני מגדיר כל אחד בתא אחר בתוך הטבלה, כך שאם המשתמש מגדיל או מקטין תמיד היחס ביניהם נשמר.
השאלה אם יש יכולת להגדיר שגם הפקדים יגדלו בהתאם לגודל החלון בצורה אוט'?
כמו כן, האם זה לא מסורבל מדי? האם יש דרך פשוטה יותר לעשות זאת? או שפשוט עדיף לנעול ולמנוע מהמשתמש לשחק עם הגודל של הטופס (הבנתי שיש אפשרות לעשות זאת..)
כמו כן, אם יש לכם עצות נוספות לגבי עיצוב טפסים בWPF אשמח לשמוע!!
תודה רבה!פורסם במקור בפורום CODE613 ב28/06/2015 15:23 (+03:00)
-
העצה היא ללמוד
בWPF יש מחלקה ששמה Panel. היא ורק היא מספקת את היכולת להכיל יותר מאלמנט אחד, ולסדר אותם.
המחלקה הזו אבסטרקטית - היא אפשר להשתמש בה ישירות ללא ירושה. המחלקות שיורשות ממנה הם:
Canavas
Grid
StackPanel
WrapPanel
DockPanel
יש עוד כמה אבל אלו העיקריים.הפאנלים הללו יכולים להכיל כמה אלמנטיo שרוצים, כצורת הסידור שלהם היא באחריות הפאנל. לכל אחד מהם יש צורה אחרת האופיינית לו. בשביל לתת הוראות סדר ברמת אלמנט ולא ברמת הפאנל, יש לכל אלמנט את מאפייני הסידור הבאים:
- Width Height - קביעת גובה ורוחב. מקבלים ערך "אין סוף" שכוונתו אוטומטי, ואז הסידור הוא בהתאם למאפיינים ב3.
- ActualWidth ActualHeight - מאפיינים לקריאה בלבד שהאלמנט מחזיר אחרי שהפאנל "אמר לו" איפה ואיך להתמקם. זה יכול להיות שונה ממה שהוא היה רוצה, נכול להמליץ על כך שזה הפער בין הרצוי למצוי או התנגשות קלה בין רצון האזרח לרצון הממשלה...
- HorizontalAlignment VerticalAlignment - יישור: מינימום (לפי התוכן)-אמצע או קצה, או מקסימום. אפקטיבי במידה ויש ערך אוטומטי לגובה או לרוחב.
- MaxWidth MaxHeight MinWidth MinHeight - קביעת מקסימום ומינימום.
- Visibilty - מקבל מלבד גלוי ונסתר ערך Collapsed שזה גורם שהאלמנט לא תופס מקום.
כל פאנל יכול לכבד את המאפיינים הללו אך יכול להתעלם מהוראות שלא רלוונטיות לאופי הסידור שלו. למשל, StackPanel אנוכי, תמיד מכווץ את הפקדים לפי תוכנם אפי' אם הHorizontalAlignment שלהם מוגד לStretc - מתיחה לגודל מקסימלי. אתה יכול ליצור גם panel משלך ושם תהיה דיקטטור בקטע הזה :).
אני יודע שלא עניתי לך כלום, אך מאידך השאלה המעורפלת זעקה לסדר ולא לתשובה
פורסם במקור בפורום CODE613 ב30/06/2015 14:01 (+03:00)
-
@דוד ל.ט.
אני יודע שלא עניתי לך כלום, אך מאידך השאלה המעורפלת זעקה לסדר ולא לתשובה
קודם כל, תודה על התשובה המורחבת שאכן עושה סדר.. אם כי את עיקרי הדברים ידעתי..
אכן, השאלה קצת מעורפלת, אבהיר אותה:אני כותב טופס שבו המשתמש אמור להזין הרבה פרטים(שם פרטי/משפחה, כתובת, טלפון, מייל וכו')
לשם כך אני אמור להשתמש בהרבה labelים ותיבות טקסט..
כמו כן, אני לא רוצה לקבע אותם לנקודה מסוימת בחלון כדי שכל משתמש יוכל להתאים אותו למסך שלו.
לכן, נראה לי שstackpanel לא רלבנטי, כיון שהוא מגדיר שכל הפקדים בערימה אחד אחרי השני (מאוזן או מאונך..). וכן הdockpanel לא לרבנטי כי למיטב הבנתי הוא מיישר את הפקדים לקצוות החלון.. והcanvas ג"כ לא יודע לשנות את הפקד בהתאם לגודל החלון, אלא רק בנקודה המסוימת שאני מגדיר.אם כן יש שתי אפשרויות: wrapPanel שהוא מסדר לי את הפקדים אחד אחרי השני. (אלא שכאן לחסרון ידיעתי הפקד מחליט מתי להתחיל שורה חדשה לפי גודל החלון, ולפעמים אני רוצה שפקד מסוים יהיה בשורה חדשה, כך שהוא פחות שימושי).
או grid שאיתו אני יכול לעשות ככל העולה על רוחי, בלי להצמיד את הפקד לנקודה מסוימת, אלא אני מצמיד אותו לעמודה/שורה והוא מתרחב/מתכווץ לפי החלון (שוב, גם פה אני יכול להגדיר נקודה מסוימת אם אני רוצה..).
עד עכשיו (4 חלונות שעיצבתי :lol: ) השתמשתי בgrid, (פעם אחת שילבתי בתוך הגריד בתא מסוים wrap panel ובו הצבתי חלק מהפקדים..)לכן שאלתי היא: א. האם זוהי הדרך המומלצת כאשר יוצרים חלון כזה? (grid וקביעת הפקדים בתאים, כאשר רוחב העמודות והשורות מוגדר אוט').
ב. האם ישנה אפשרות שכאשר החלון גדל גם גודל הכתב של התוויות ופקדים גדל, או שרק הפקד עצמו גדל?
מקווה שעכשיו זה קצת יותר ממוקד ובהיר.פורסם במקור בפורום CODE613 ב01/07/2015 12:50 (+03:00)
-
תודה!!
כרגע זה מה שעצבתי:
אבל כשמגדילים את החלון זה נראה כך:
השתמשתי בקוד הxaml הבא:<Grid> <Grid.RowDefinitions> <RowDefinition Height="20"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="20"/> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/> <ColumnDefinition Width="auto"/> </Grid.ColumnDefinitions> <Label Grid.ColumnSpan="3" Content="הוסף תורם חדש" Grid.Column="2" HorizontalAlignment="Center" Height="30" Grid.Row="1" VerticalAlignment="Center" Width="132" HorizontalContentAlignment="Center" FlowDirection="RightToLeft" FontWeight="Bold" FontSize="14" Margin="0,0,1,0"/> <Label Content="מס' סידורי" Grid.Column="5" Grid.Row="2" FlowDirection="RightToLeft"/> <Label x:Name="idNumber" MinWidth="20" Grid.Column="4" Grid.Row="2" Padding="0" FontWeight="Bold" FlowDirection="RightToLeft" FontSize="14"/> <Label Content="שם פרטי" Grid.Column="5" Grid.Row="3" FlowDirection="RightToLeft" MaxHeight="Infinity" MaxWidth="Infinity" /> <Label Content="שם משפחה" Grid.Column="5" Grid.Row="4" FlowDirection="RightToLeft" MaxHeight="Infinity" MaxWidth="Infinity" /> <TextBox x:Name="firstName" Grid.Column="4" Grid.Row="3" MinWidth="90" FlowDirection="RightToLeft" /> <TextBox x:Name="lastName" Grid.Column="4" Grid.Row="4" MinWidth="90" FlowDirection="RightToLeft" /> <Label Content="מספר טלפון" Grid.Column="5" Grid.Row="5" FlowDirection="RightToLeft"/> <Label Grid.Column="5" Grid.Row="6" FlowDirection="RightToLeft" Content="כתובת" /> <TextBox x:Name="telefon" Grid.Row="5" Grid.Column="4" MinWidth="30" FlowDirection="RightToLeft"/> <TextBox x:Name="adress" Grid.Row="6" Grid.Column="4" MinWidth="170" FlowDirection="RightToLeft"/> <Label Content="מייל" Grid.Column="5" Grid.Row="7" FlowDirection="RightToLeft" /> <TextBox x:Name="eMail" Grid.Column="4" Grid.Row="7" MinWidth="170" Text="Email:"/> <Button x:Name="addButton" Content="הוסף תורם" Grid.Column="4" Grid.Row="8" Click="addButton_Click"/> <Label Grid.Row="2" Grid.Column="2" Content="סכום התרומה" MinWidth="50" FlowDirection="RightToLeft" /> <TextBox Grid.Column="1" Grid.Row="2" MinWidth="80" x:Name="sum" FlowDirection="RightToLeft"/> <RadioButton x:Name="frequenci" Grid.Row="3" Grid.Column="2" Content="תרומה חד פעמית" FlowDirection="RightToLeft" IsChecked="True"/> <RadioButton x:Name="monthly" Grid.Row="4" Grid.Column="2" Content="תרומה חודשית" FlowDirection="RightToLeft"/> <Label Content="אופן התשלום" Grid.Row="5" Grid.Column="2" FlowDirection="RightToLeft"/> <ComboBox Grid.Row="5" Grid.Column="1" FlowDirection="RightToLeft" IsEnabled="{Binding ElementName=monthly, Path=IsChecked}"> <ComboBoxItem x:Name="creditCard" Content="כרטיס אשראי" /> <ComboBoxItem x:Name="directDebit" Content="הוראת קבע"/> </ComboBox> <Label Content="תאריך חיוב" Grid.Column="2" Grid.Row="6" FlowDirection="RightToLeft"/> <TextBox x:Name="datePayBox" Grid.Row="6" Grid.Column="1" FlowDirection="RightToLeft" IsEnabled="{Binding ElementName=monthly, Path=IsChecked}"/> <Button Content="חזור למסך הראשי" Grid.Column="1" Grid.Row="8" Click="BackClick" /> </Grid>
פורסם במקור בפורום CODE613 ב02/07/2015 12:35 (+03:00)
-
טוב. אז מצד אחד אתה מתחיל, ולWPF יש עקומת לימוד רצינית: אני כבר שלוש שנים מתעסק כמעט רק בה,ויש לי פערים רציניים.
אז קשה לבוא עם פרקטיקות בבת אחת.
קודם אנסה לזרום עם הדוגמה שלך ולשפר מעט:<Grid FlowDirection="RightToLeft" Margin="8"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="0"/> <!-- מיותר --> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition /> <ColumnDefinition Width="Auto" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Label Grid.ColumnSpan="4" Content="הוסף תורם חדש" HorizontalAlignment="Center" Margin="0,22,0,5" VerticalAlignment="Center" HorizontalContentAlignment="Center" FontWeight="Bold" FontSize="14"/> <Label Content="מס' סידורי" Grid.Column="2" Grid.Row="2" /> <Label x:Name="idNumber" Grid.Column="3" Grid.Row="2" FontWeight="Bold" FontSize="14"/> <Label Content="שם פרטי" Grid.Column="2" Grid.Row="3" /> <Label Content="שם משפחה" Grid.Column="2" Grid.Row="4" /> <TextBox x:Name="firstName" Grid.Column="3" Grid.Row="3" /> <TextBox x:Name="lastName" Grid.Column="3" Grid.Row="4" /> <Label Content="מספר טלפון" Grid.Column="2" Grid.Row="5" /> <Label Grid.Column="2" Grid.Row="6" Content="כתובת" /> <TextBox x:Name="telefon" Grid.Row="5" Grid.Column="3" /> <TextBox x:Name="adress" Grid.Row="6" Grid.Column="3" /> <Label Content="מייל" Grid.Column="2" Grid.Row="7" /> <TextBox x:Name="eMail" Grid.Column="3" Grid.Row="7" Text="Email:"/> <Label Grid.Row="2" Content="סכום התרומה" MinWidth="50" /> <TextBox Grid.Column="1" Grid.Row="2" x:Name="sum" /> <RadioButton x:Name="frequenci" Grid.Row="3" Content="תרומה חד פעמית" IsChecked="True"/> <RadioButton x:Name="monthly" Grid.Row="4" Content="תרומה חודשית" /> <Label Content="אופן התשלום" Grid.Row="5" /> <ComboBox Grid.Row="5" Grid.Column="1" IsEnabled="{Binding ElementName=monthly, Path=IsChecked}"> <ComboBoxItem x:Name="creditCard" Content="כרטיס אשראי" /> <ComboBoxItem x:Name="directDebit" Content="הוראת קבע"/> </ComboBox> <Label Content="תאריך חיוב" Grid.Row="6" /> <TextBox x:Name="datePayBox" Grid.Row="6" Grid.Column="1" IsEnabled="{Binding ElementName=monthly, Path=IsChecked}"/> <Grid Grid.Row="8" Grid.ColumnSpan="4" VerticalAlignment="Bottom" MinHeight="90"> <Button x:Name="addButton" Content="הוסף תורם" Click="addButton_Click" HorizontalAlignment="Left" Margin="25" Width="125" Padding="8"/> <Button Content="חזור למסך הראשי" Click="BackClick" HorizontalAlignment="Right" Margin="25" Width="125" Padding="8"/> </Grid> </Grid>
בשביל ליצור שוליים לתיבות ולטקסט השתמשת בעמודות, ואני לא שמתי בכלל. הגישה שלי זה להגדיר margin לכולם באופן גורף ע" סטייל. אפשר גם להחיל את הסטייל דוקא על עמודה מסויימת של גריד (http://stackoverflow.com/a/853082/1271037). אבל אם כבר מה אני הייתי עושה, לא הייתי עובד עם שורות של גריד.
כי מאוד מצוי שאתה רוצה לשנות (להוסיף עמודה או שורה באמצע), ואז צריך לעבוד ידנית.
תראה דוגמה איך אני הייתי עושה עד לא מזמן (את ההגדרה FlowDirection תשמור לאלמנט השורש (window) זה הגדרה נורשת ולא צריך להגדירה שוב ושוב בצאצאים):<Grid> <Grid.RowDefinitions> <RowDefinition Height="80"/> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="21.333" FontWeight="Bold">כותרת</TextBlock> <WrapPanel Grid.Row="1" Orientation="Vertical" Margin="10,0" Grid.IsSharedSizeScope="True"> <WrapPanel.Resources> <Style TargetType="TextBlock" x:Key="captions"> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="Foreground" Value="Indigo" /> <Setter Property="Margin" Value="0,0,5,0" /> </Style> <Style TargetType="TextBox" > <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="Width" Value="120" /> </Style> <Style TargetType="Grid"> <Setter Property="Height" Value="25" /> </Style> </WrapPanel.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition SharedSizeGroup="cols"/> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Style="{StaticResource captions}" >שם פרטי</TextBlock> <TextBox Grid.Column="1">שם פרטי</TextBox> </Grid> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition SharedSizeGroup="cols"/> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Style="{StaticResource captions}" >שם פרטי</TextBlock> <TextBox Grid.Column="1">שם פרטי</TextBox> </Grid> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition SharedSizeGroup="cols"/> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Style="{StaticResource captions}" >שם פרטי</TextBlock> <TextBox Grid.Column="1">שם פרטי</TextBox> </Grid> </WrapPanel> </Grid>
תנסה להקטין את הטופס בשביל לראות את הגלישה לטורים (אולי אתה לא רוה זאת, אבל מצד שני לא נתת הגדרה מה יקרה כשהטופס יגדל/יקטן, וכמובן גם אני לא כיסיתי כל אפשרות).
אבל קל לראות שיש מסורבלות רבה בקוד הזה.
אחרי הרבה נסיונות מצאתי פתאום פקד פשוט בWPF ששמו HeaderedContentControl, ועיצוב שלו פשוט מאפשר לי לרכב על פקד מותאם אישית לכותרת ופקד. הנה איך שאני עושה היום:<Grid> <Grid.RowDefinitions> <RowDefinition Height="80"/> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="21.333" FontWeight="Bold">כותרת</TextBlock> <WrapPanel Grid.Row="1" Orientation="Vertical" Margin="10,0" Grid.IsSharedSizeScope="True"> <WrapPanel.Resources> <Style TargetType="HeaderedContentControl"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="HeaderedContentControl"> <Grid Margin="5,2"> <Grid.ColumnDefinitions> <ColumnDefinition SharedSizeGroup="cols"/> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Text="{TemplateBinding Header}" Foreground="Indigo" Margin="10,0"/> <ContentPresenter Grid.Column="1"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="TextBox" > <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="Width" Value="120" /> </Style> </WrapPanel.Resources> <HeaderedContentControl Header="מס' תורם" Content="12569" /> <HeaderedContentControl Header="שם פרטי" > <TextBox /> </HeaderedContentControl> <HeaderedContentControl Header="שם משפחה" > <TextBox /> </HeaderedContentControl> <HeaderedContentControl Header="טלפון" > <TextBox /> </HeaderedContentControl> </WrapPanel> </Grid>
הנה לינקים לעימוד נכון בWPF:
http://blogs.msdn.com/b/wpfsldesigner/archive/2010/06/03/layout-techniques-for-windows-forms-developers.aspx
http://www.codeproject.com/Articles/203946/WPF-Layout-by-Contentאבל שוב, אני נחשב מתחיל, וWPF לא בנוי טוב למתחילים :). תראה למשל דוגמה מהאינטרנט שבנויה חזק ו"גנרי":
https://karlshifflett.wordpress.com/2008/10/23/wpf-silverlight-lob-form-layout-searching-for-a-better-solution/פורסם במקור בפורום CODE613 ב03/07/2015 12:28 (+03:00)
-
מחוסר זמן רק נתתי דוגמה ולא כיסיתי את בעיות הפריסה, ת הפקדים המיוחדים (הרדיו והקומבו) ואת כפתורי האישו והביטול למטה, מקוה להרחיב פעם הבאה.
בהצלחה!
אני ממש שמח שאתה נכנס בכל הכח לכל התחומים הללו. אני בטוח שלא תתחרט.פורסם במקור בפורום CODE613 ב03/07/2015 12:34 (+03:00)
-
תודה רבה על הדוגמאות המצויינות!! ישבתי ללמוד אותם בעיון רב והתחדשו לי הרבה דברים!! תודה גם על הקישורים המצויינים שצירפת!!
ובטוחני שעוד אשתמש בדוגמאות הללו כדי להבין יותר..
ברשותך שאלה קטנה:
אם הגדרת בresources סטייל של עיצוב ונתת לו שם, מדוע אח"כ כתבת: Style="{StaticResource captions} ולא מספיק לכתוב style=caption?פורסם במקור בפורום CODE613 ב04/07/2015 22:52 (+03:00)
-
לכל מי שרוצה מצריכים וחומר מעולה בכל תחום שהו במחשבים:
יש אתר מדהים שקוראים לו קלאודנטס
הוא למעשה שיתופיה של חומרים של סטודנטים במכללה\אונברסיטה
כאשר למעשה כל אחד יכול להרשם להחליט שהוא שייך לאיזה מוסד לימודים שבא לו
ולהרשם לקורסים שהוא מתעניין ויש לו את כל החומר מצגות מבחנים תרגילים סיכומים
לכל מי שרוצה חומר בעניני תכנות מומלץ להרשם למרכז האקדמי לב (מכון טל)
יש שם חומר עצום בכל מקצוע מסודר לפי מחלקות ולפי שנים
כל מי שיחפור שם קצת יגלה מהר את האוצר שמקימי האתר חשפו
מצורף קישור
https://www.cloudents.com
ושוב אם לא מוצאים חומר בנושא מסוים תמיד ניתן ללכת להגדרות להחליט שאתם לומדים בטכניון או כל מקום אחר ולראות אם שמם יש יותר חומר בנושא המבוקש
מומלץ מאדפורסם במקור בפורום CODE613 ב05/07/2015 09:40 (+03:00)
-
אם הגדרת בresources סטייל של עיצוב ונתת לו שם, מדוע אח"כ כתבת: Style="{StaticResource captions} ולא מספיק לכתוב style=caption?
כי המילה caption לא מתפרשת בשום דרך כסטייל, אלא משמשת כביטוי שהריסורס בשם זה ישמש כסטייל. אז ביטיים בXAML כותבים בתוך סוגריים כאלו, והסטטיק ריסורס מציין איזה סוג ביטוי כי יש הרבה סוגים.
פורסם במקור בפורום CODE613 ב05/07/2015 11:32 (+03:00)