我的代码是否表现出良好的WPF实践?
我开始了一个WPF项目,刚刚完成了UI的基础,但它看起来很复杂,所以我不确定我是否已经以正确的方式进行了布局。 我不想开始开发后端,并意识到我已经犯了错误,让自己的生活变得更加艰难。
从<DIV>的CSS和CSS风格的背景来看,这有很大的不同,并且真的想从一开始就把它做好。
基本上这是一个星期的日历(7天,星期日,星期日,默认为本周)。哪个最终会连接到一个数据库,如果我在这一天有预约的东西,它会在相关日期显示它。
我选择了Grid而不是ListView,因为它的工作方式我不会将结果绑定到集合或任何沿着这些行的东西。 相反,我会在画布上为每个事件填充一个组合框(尚未放置在代码中),并在选择时向我显示更多细节。
XAML:
<Window x:Class="WOW_Widget.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:Extensions="clr-namespace:WOW_Widget" DataContext="{Binding RelativeSource={RelativeSource Self}}" Title="Window1" Height="239" Width="831"> <Window.Resources> <LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1"> <GradientBrush.GradientStops> <GradientStopCollection> <GradientStop Offset="1.0" Color="White"/> <GradientStop Offset="0.0" Color="LightSlateGray"/> </GradientStopCollection> </GradientBrush.GradientStops> </LinearGradientBrush> <LinearGradientBrush x:Key="grdDayHeader" StartPoint="0,0" EndPoint="0,1"> <GradientBrush.GradientStops> <GradientStopCollection> <GradientStop Offset="0.0" Color="Peru" /> <GradientStop Offset="1.0" Color="White" /> </GradientStopCollection> </GradientBrush.GradientStops> </LinearGradientBrush> <LinearGradientBrush x:Key="grdToday" StartPoint="0,0" EndPoint="0,1"> <GradientBrush.GradientStops> <GradientStopCollection> <GradientStop Offset="0.0" Color="LimeGreen"/> <GradientStop Offset="1.0" Color="DarkGreen" /> </GradientStopCollection> </GradientBrush.GradientStops> </LinearGradientBrush> <Style TargetType="{x:Type GridViewColumnHeader}"> <Setter Property="Background" Value="Khaki" /> </Style> <Style x:Key="DayHeader" TargetType="{x:Type Label}"> <Setter Property="Background" Value="{StaticResource grdDayHeader}" /> <Setter Property="Width" Value="111" /> <Setter Property="Height" Value="25" /> <Setter Property="HorizontalContentAlignment" Value="Center" /> </Style> <Style x:Key="DayField"> <Setter Property="Canvas.Width" Value="111" /> <Setter Property="Canvas.Height" Value="60" /> <Setter Property="Canvas.Background" Value="White" /> </Style> <Style x:Key="Today"> <Setter Property="Canvas.Background" Value="{StaticResource grdToday}" /> </Style> <Style x:Key="CalendarColSpacer"> <Setter Property="Canvas.Width" Value="1" /> <Setter Property="Canvas.Background" Value="Black" /> </Style> <Style x:Key="CalendarRowSpacer"> <Setter Property="Canvas.Height" Value="1" /> <Setter Property="Canvas.Background" Value="Black" /> </Style> </Window.Resources> <Grid Background="{StaticResource NormalBrush}"> <Border BorderBrush="Black" BorderThickness="1" Width="785" Height="86" Margin="12,12,12,104"> <Canvas Height="86" Width="785" VerticalAlignment="Top"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Label Grid.Column="0" Grid.Row="0" Content="Monday" Style="{StaticResource DayHeader}" /> <Canvas Grid.Column="1" Grid.RowSpan="3" Grid.Row="0" Style="{StaticResource CalendarColSpacer}" /> <Label Grid.Column="2" Grid.Row="0" Content="Tuesday" Style="{StaticResource DayHeader}" /> <Canvas Grid.Column="3" Grid.RowSpan="3" Grid.Row="0" Style="{StaticResource CalendarColSpacer}" /> <Label Grid.Column="4" Grid.Row="0" Content="Wednesday" Style="{StaticResource DayHeader}" /> <Canvas Grid.Column="5" Grid.RowSpan="3" Grid.Row="0" Style="{StaticResource CalendarColSpacer}" /> <Label Grid.Column="6" Grid.Row="0" Content="Thursday" Style="{StaticResource DayHeader}" /> <Canvas Grid.Column="7" Grid.RowSpan="3" Grid.Row="0" Style="{StaticResource CalendarColSpacer}" /> <Label Grid.Column="8" Grid.Row="0" Content="Friday" Style="{StaticResource DayHeader}" /> <Canvas Grid.Column="9" Grid.RowSpan="3" Grid.Row="0" Style="{StaticResource CalendarColSpacer}" /> <Label Grid.Column="10" Grid.Row="0" Content="Saturday" Style="{StaticResource DayHeader}" /> <Canvas Grid.Column="11" Grid.RowSpan="3" Grid.Row="0" Style="{StaticResource CalendarColSpacer}" /> <Label Grid.Column="12" Grid.Row="0" Content="Sunday" Style="{StaticResource DayHeader}" /> <Canvas Grid.Column="0" Grid.ColumnSpan="13" Grid.Row="1" Style="{StaticResource CalendarRowSpacer}" /> <Canvas Grid.Column="0" Grid.Row="2" Margin="0" Style="{StaticResource DayField}"> <Label Name="lblMondayDate" /> </Canvas> <Canvas Grid.Column="2" Grid.Row="2" Margin="0" Style="{StaticResource DayField}"> <Label Name="lblTuesdayDate" /> </Canvas> <Canvas Grid.Column="4" Grid.Row="2" Margin="0" Style="{StaticResource DayField}"> <Label Name="lblWednesdayDate" /> </Canvas> <Canvas Grid.Column="6" Grid.Row="2" Margin="0" Style="{StaticResource DayField}"> <Label Name="lblThursdayDate" /> </Canvas> <Canvas Grid.Column="8" Grid.Row="2" Margin="0" Style="{StaticResource DayField}"> <Label Name="lblFridayDate" /> </Canvas> <Canvas Grid.Column="10" Grid.Row="2" Margin="0" Style="{StaticResource DayField}"> <Label Name="lblSaturdayDate" /> </Canvas> <Canvas Grid.Column="12" Grid.Row="2" Margin="0" Style="{StaticResource DayField}"> <Label Name="lblSundayDate" /> </Canvas> </Grid> </Canvas> </Border> <Canvas Height="86" HorizontalAlignment="Right" Margin="0,0,12,12" Name="canvas1" VerticalAlignment="Bottom" Width="198"></Canvas> </Grid> </Window>
CS:
public partial class Window1 : Window {
private DateTime today = new DateTime();
private Label[] Dates = new Label[7];
public Window1() {
DateTime start = today = DateTime.Now;
int day = (int)today.DayOfWeek;
while (day != 1) {
start = start.Subtract(new TimeSpan(1, 0, 0, 0));
day--;
}
InitializeComponent();
Dates[0] = lblMondayDate;
Dates[1] = lblTuesdayDate;
Dates[2] = lblWednesdayDate;
Dates[3] = lblThursdayDate;
Dates[4] = lblFridayDate;
Dates[5] = lblSaturdayDate;
Dates[6] = lblSundayDate;
FillWeek(start);
}
private void FillWeek(DateTime start) {
for (int d = 0; d < Dates.Length; d++) {
TimeSpan td = new TimeSpan(d, 0, 0, 0);
DateTime _day = start.Add(td);
if (_day.Date == today.Date) {
Canvas dayCanvas = (Canvas)Dates[d].Parent;
dayCanvas.Style = (Style)this.Resources["Today"];
}
Dates[d].Content = (int)start.Add(td).Day;
}
}
}
我会说,不,你不会以正确的方式去做。 你做了太多的工作,并让WPF做得太少。 你应该使用数据绑定和一个ItemsControl
,并让WPF做所有的事情,找出把东西放在哪里以及放什么东西。
在本例中我使用了XmlDataProvider
,因为它是演示如何在不编写代码的情况下使用数据绑定的最简单方法。 您可能会构建一个视图模型类,该类使用Name和Date属性公开了一组对象并绑定到该对象的一个实例。
使用Canvas
和逐像素布局是WPF中的一件坏事,这完全是关于构建独立于分辨率的UI。 让布局引擎完成所有工作要好得多。
并非所有看起来像网格的东西都需要与Grid
一起布置。 如果将此网格放置为水平的StackPanel
,则XAML的数量会减少很多。 这样可以避免使用行号和列号。 我的布局使用Grid
的唯一原因是将边框的大小设置为其内容。
这是我对你提供的东西的返工。 在我看来,结果与您的结果看起来非常相似,但它大约是XAML的一半(不包括笔刷),修改起来更容易。
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="{DynamicResource NormalBrush}">
<Page.Resources>
<XmlDataProvider x:Key="Days" XPath="Days">
<x:XData>
<Days xmlns="">
<Day Name="Sunday" Date="03/14/2010"/>
<Day Name="Monday" Date="03/15/2010"/>
<Day Name="Tuesday" Date="03/16/2010"/>
<Day Name="Wednesday" Date="03/17/2010"/>
<Day Name="Thursday" Date="03/18/2010"/>
<Day Name="Friday" Date="03/19/2010"/>
<Day Name="Saturday" Date="03/20/2010"/>
</Days>
</x:XData>
</XmlDataProvider>
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="1.0" Color="White"/>
<GradientStop Offset="0.0" Color="LightSlateGray"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="DayHeaderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.0" Color="Peru" />
<GradientStop Offset="1.0" Color="White" />
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
</Page.Resources>
<Grid Margin="50">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<ItemsControl ItemsSource="{Binding Source={StaticResource Days}, XPath=Day}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Background="White">
<Border BorderBrush="Black" BorderThickness="1,1,0,0" Background="{StaticResource DayHeaderBrush}">
<TextBlock Margin="30,10" HorizontalAlignment="Center" Text="{Binding XPath=@Name}"/>
</Border>
<Border BorderBrush="Black" BorderThickness="1,1,0,0">
<TextBlock Margin="30,10" Height="50" HorizontalAlignment="Center" Text="{Binding XPath=@Date}"/>
</Border>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Border BorderBrush="Black" BorderThickness="0,0,1,0"/>
</StackPanel>
</Grid>
</Page>
我不知道你的项目会有多大,但是在开始WPF时我可以给你的最大提示是查看PRISM框架:
http://www.codeplex.com/CompositeWPF
http://msdn.microsoft.com/en-us/magazine/cc785479.aspx
这是一个很好的框架,为你解决了很多问题。
关于您的日历,我会建议将其作为可重复使用的无望控制,本文可能会帮助您:
http://www.codeproject.com/KB/WPF/WPFOutlookCalendar.aspx
如果您稍后决定使用绑定,则可以遵循MVVM模式。 更多细节:
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
如果您想要每天分别显示约会,则可以使用'RelayCommand'进入第二天。
链接地址: http://www.djcxy.com/p/44653.html