avoiding copy-and-paste when using XAML
Microsoft's unit converter starter kit for its Windows 7 phone generates the keyboard with the XAML reproduced below. Obviously tons of copy and paste.
Questions:
1) Is MSFT serious about writing it that way?
2) Really????? 3) Is there a sane way to write something like that? 4) Does anyone know of a code sample that illustrates said sane way? <StackPanel Orientation="Vertical">
<TextBlock x:Name="textBlockCategory"
Text="{Binding Path=UppercasedCategory}"
Margin="23,24,0,0"
FontSize="{StaticResource PhoneFontSizeMedium}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Foreground="{StaticResource PhoneForegroundBrush}" />
<StackPanel x:Name="spInput"
Orientation="Vertical"
Margin="0,0,24,0" >
<TextBlock x:Name="textBlockInputValue"
Text="{Binding Path=UpperUnitValue}"
Height="80" Margin="0,2,0,0"
TextAlignment="Right"
FontSize="{StaticResource PhoneFontSizeExtraExtraLarge}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Foreground="{StaticResource PhoneForegroundBrush}" />
<TextBlock x:Name="textBlockInputUnit"
Text="{Binding Path=UpperUnitName}"
Height="34" TextAlignment="Right" Margin="0,2,0,0"
FontSize="{StaticResource PhoneFontSizeMediumLarge}"
Foreground="{StaticResource PhoneAccentBrush}"
FontFamily="{StaticResource PhoneFontFamilySemiBold}" />
</StackPanel>
<StackPanel x:Name="spResult"
Orientation="Vertical"
Margin="0,-4,24,0" >
<TextBlock x:Name="textBlockResultValue"
Text="{Binding Path=LowerUnitValue}"
开发者_运维问答 Height="80" TextAlignment="Right" Margin="0,-4,0,0"
FontSize="{StaticResource PhoneFontSizeExtraExtraLarge}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Foreground="{StaticResource PhoneSubtleBrush}"/>
<TextBlock x:Name="textBlockResultUnit"
Text="{Binding Path=LowerUnitName}"
Height="34" TextAlignment="Right" Margin="0,2,0,0"
FontSize="{StaticResource PhoneFontSizeMediumLarge}"
Foreground="{StaticResource PhoneAccentBrush}"
FontFamily="{StaticResource PhoneFontFamilySemiBold}" />
</StackPanel>
<StackPanel x:Name="spSummary" >
<TextBlock x:Name="textBlockSummary"
Text="{Binding Path=Summary}"
Height="30" TextAlignment="Center" Margin="0,18,0,0"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneSubtleBrush}"
FontFamily="{StaticResource PhoneFontFamilyNormal}" />
</StackPanel>
<StackPanel x:Name="spKeypad" Orientation="Vertical" HorizontalAlignment="Right">
<StackPanel x:Name="spKeypadRow1" Orientation="Horizontal">
<Button x:Name="btnKeypadKey7"
Content="7"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Style="{StaticResource KeypadButtonStyle}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource KeypadButtonFontSize}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKey8"
Content="8"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Style="{StaticResource KeypadButtonStyle}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource KeypadButtonFontSize}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKey9"
Content="9"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Style="{StaticResource KeypadButtonStyle}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource KeypadButtonFontSize}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKeyCancel"
Height="84" Margin="6" Width="108"
Style="{StaticResource btnKeypadKeyCancelStyle}"
Background="{StaticResource PhoneDisabledBrush}"
FontSize="{StaticResource PhoneFontSizeExtraLarge}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickClear" />
</StackPanel>
<StackPanel x:Name="spKeypadRow2" Orientation="Horizontal">
<Button x:Name="btnKeypadKey4"
Content="4"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Style="{StaticResource KeypadButtonStyle}"
FontSize="{StaticResource KeypadButtonFontSize}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKey5"
Content="5"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Style="{StaticResource KeypadButtonStyle}"
FontSize="{StaticResource KeypadButtonFontSize}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKey6"
Content="6"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Style="{StaticResource KeypadButtonStyle}"
FontSize="{StaticResource KeypadButtonFontSize}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKeyBack"
Height="84" Margin="6" Width="108"
Style="{StaticResource btnKeypadKeyBackStyle}"
Background="{StaticResource PhoneDisabledBrush}"
FontSize="{StaticResource PhoneFontSizeExtraLarge}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickBack" />
</StackPanel>
<StackPanel x:Name="spKeypadRow3" Orientation="Horizontal">
<Button x:Name="btnKeypadKey1"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Content="1"
Style="{StaticResource KeypadButtonStyle}"
FontSize="{StaticResource KeypadButtonFontSize}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKey2"
Content="2"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Style="{StaticResource KeypadButtonStyle}"
FontSize="{StaticResource KeypadButtonFontSize}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKey3"
Content="3"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Style="{StaticResource KeypadButtonStyle}"
FontSize="{StaticResource KeypadButtonFontSize}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKeyPlusMinus"
Height="84" Margin="6" Width="108"
Style="{StaticResource btnKeypadPlusMinusStyle}"
Background="{StaticResource PhoneDisabledBrush}"
FontSize="{StaticResource PhoneFontSizeExtraLarge}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickSign" />
</StackPanel>
<StackPanel x:Name="spKeypadRow4" Orientation="Horizontal">
<Button x:Name="btnKeypadKey0"
Content="0"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="228"
Style="{StaticResource KeypadButtonStyle}"
FontSize="{StaticResource KeypadButtonFontSize}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadKeyPoint"
Content="{Binding Path=CurrentCulture.NumberFormat.NumberDecimalSeparator, Source={StaticResource Resources}}"
Background="{StaticResource PhoneInactiveBrush}"
Foreground="{StaticResource PhoneForegroundBrush}"
Height="84" Margin="6" Width="108"
Style="{StaticResource btnKeypadPointStyle}"
FontSize="{StaticResource KeypadButtonFontSize}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickNumber" />
<Button x:Name="btnKeypadSwitchSourceTargetUnit"
Height="84" Margin="6" Width="108"
Style="{StaticResource KeypadButtonStyle}"
Background="{StaticResource PhoneDisabledBrush}"
FontSize="{StaticResource PhoneFontSizeExtraLarge}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
Click="OnClickSourceTargetUnit">
<Image Source= "{Binding ConversionImageSource}"/>
</Button>
</StackPanel>
</StackPanel>
</StackPanel>
XAML is a very powerful language, but as you correctly note, it's inherently verbose and ugly. And it's the worst language I've ever seen when it comes to DRY (Don't Repeat Yourself). That said, all the comments other folks have made are also true. Styles help a lot. Blend helps even more.
My first impression was the same as yours, and while I've since come to realize that it is indeed an incredibly powerful and useful language, I've never stopped thinking that parts of it are very poorly designed indeed. This is one example; the fact that you can't specify the datatype of the object you're databinding to is another.
All that said, it really is worthwhile to learn XAML. You can do stuff with XAML that's bloody well impossible in HTML or WinForms or Java. It's a very, very powerful UI description language. Just take it for what it is, swallow hard, and forget everything you ever learned about good coding style, and you'll be able to create some amazing UI's.
If you're going to mimic the same sort of design I would definitely make use of Styles to reduce the repetition on all those Buttons. It looks like they've started down that path by creating KeypadButtonStyle but there's more you could build on, especially if you make use of Styles based on other Styles.
You could also use a Grid rather than Stack Panels full of Stack Panels for layout.
In terms of building this xaml with code and loops you could do it, but I'd highly recommend learning Expression Blend where it wouldn't take you long to create the xaml you need (including the Style refinements).
No, you don't have to copy and paste XAML code if you don't want to. XAML is just an object graph that creates objects and sets properties. Any code you write in XAML you can also write procedurally (in a for loop, if you'd like).
One very powerful element in XAML is the ItemsControl. With that you can avoid many repetetive markup constructs by simply making your UI data-driven and flexible. At runtime you assign the data source and the ItemsControl will then expand the templates dynamically to build your UI based on the data that is being assigned.
http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol(VS.95).aspx
精彩评论