(效果圖,如見最下面)ide
需求:根據設置的行數列數,控制展現控件個數,而且填充的控件們大小剛恰好自適應填充滿固定的區域,而且調整窗體大小的時候控件動態自適應窗體大小,即自適應大小並不顯示滾動條(好比,設置了1行1列,則第一頁顯示一個控件,如設置了2行2列,則第一頁顯示第一行2個控件,第二行2個控件)。spa
解決方案,我總結有3code
1.在cs代碼裏面動態生成Grid控件,根據設定的行列動態生成行列,將控件自適應寬高填充進去orm
2.固定Grid。使用WrapPanel排序,當Grid實際寬高發生改變時,動態計算每個格子控件的寬高,經過綁定每個控件的寬高實現blog
3.使用MVVM方式,利用Converter實現排序
其實第一第二種都特別winform寫法,當年作MVC的時候,已經被MVC的模式洗腦,本身萬不得已的時候纔會使用這兩種方式去實現,因此不推薦你們使用get
當接手這個功能的時候已經有人使用方法2實現,在綁定的實體裏面加了三個屬性,FontSize、Width、Height,並且計算也不許確,忽略了margin,最小值設定等東西。(耦合性強,代碼錯亂,很差維護等缺點不一一列舉),如今改爲方式3去實現,特別簡單,咱們只須要使用Converter實現就好,由於ConverterParameter並不支持Binding寫法,這裏需用用到了多綁定方式去實現it
(代碼僅作參考,異常處理未寫)io
<ItemsControl Grid.Row="1" x:Name="list" ItemsSource="{Binding DefectCodeInfoPage}" > <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel IsItemsHost="True"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <!--高度應設最小值--> <Grid Margin="0 5 5 5" MinHeight="30"> <Grid.Width> <MultiBinding Converter="{StaticResource WidthConverter}"> <Binding ElementName="list" Path="ActualWidth" /> <Binding Path="DataContext.Colunm" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type local:ModPqcHeaderAdd}}"/> <Binding Path="Margin" RelativeSource="{RelativeSource Mode=Self}" /> </MultiBinding> </Grid.Width> <Grid.Height> <MultiBinding Converter="{StaticResource HeightConverter}"> <Binding ElementName="list" Path="ActualHeight" /> <Binding Path="DataContext.Row" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type local:ModPqcHeaderAdd}}"/> <Binding Path="Margin" RelativeSource="{RelativeSource Mode=Self}" /> </MultiBinding> </Grid.Height> <Grid.ColumnDefinitions> <ColumnDefinition Width="7*" /> <ColumnDefinition Width="3*" /> </Grid.ColumnDefinitions> <Button Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="auto" Height="auto" Click="Button_MouseDown" Content="{Binding DEFECT_CODE_NAME, Mode=TwoWay}" FontFamily="Microsoft YaHei" FontSize="{Binding FontSize}" Foreground="Black" FontWeight="Bold" Tag="{Binding DEFECT_CODE, Mode=TwoWay}" /> <TextBox Grid.Column="1" Width="auto" Height="auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="Microsoft YaHei" FontSize="{Binding FontSize}" Text="{Binding QTY, Mode=TwoWay}" TextAlignment="Center" /> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
多綁定的Converter實現以下event
1 [ValueConversion(typeof(double), typeof(double))] 2 public class WidthConverter : IMultiValueConverter 3 { 4 public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture) 5 { 6 double intWidth = 100; 7 try 8 { 9 10 double actualWidth = (double)value[0]; 11 int cols = System.Convert.ToInt32(value[1]); 12 Thickness margin = (Thickness)(value[2]); 13 double lmargin = margin.Left; 14 double rmargin = margin.Right; 15 16 if (cols == 0) 17 return cols = 1; 18 19 intWidth = actualWidth / cols - cols * (lmargin + rmargin); 20 } 21 catch(Exception ex) 22 { 23 } 24 return intWidth; 25 26 } 27 public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture) 28 { 29 return null; 30 31 } 32 33 } 34 35 [ValueConversion(typeof(double), typeof(double))] 36 public class HeightConverter : IMultiValueConverter 37 { 38 39 public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture) 40 { 41 double intHeight = 30; 42 try 43 { 44 45 double actualHeight = (double)value[0]; 46 int rows = System.Convert.ToInt32(value[1]); 47 Thickness margin = (Thickness)(value[2]); 48 double tmargin = margin.Top; 49 double bmargin = margin.Bottom; 50 if (rows == 0) 51 rows = 1; 52 intHeight = actualHeight / rows - rows * (tmargin + bmargin); 53 } 54 catch 55 { 56 } 57 return intHeight; 58 59 } 60 public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture) 61 { 62 return null; 63 64 } 65 66 }
噹噹噹當~~~~ 是否是超簡單,超簡潔的。這樣根本不用寫一堆屬性,還在各處去控制它們,總而言之一句話,「術業有專攻」,前臺的東西莫要帶走
設置一列一行時
設置兩行一列時
設置一行兩列時
設置N行N列時(忽略不截圖了)