我有一个管理车辆和员工的系统,当您根据日期点击他们的名字时,您应该能够看到他们当天可用的时间。
根据上一张表格中选择的日期,它只会显示1天!所以我需要1列,但时间可能是12:30-14:15等等。
像这样的视觉效果:
视觉时间视觉时间
照片:
我已经研究过创建一个自定义控件或用户控件但我对这个主题的了解很少,而且我已经花了几个小时在一个圆圈里跑来跑去。
答案 0 :(得分:4)
发布此答案是因为OP要求:
这是你在WPF中的表现方式:
<Window x:Class="MiscSamples.TimeBookings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MiscSamples"
Title="TimeBookings" Height="300" Width="300">
<Window.Resources>
<local:TimeRangeToVerticalMarginConverter x:Key="VerticalMarginConverter"/>
<local:TimeRangeHeightConverter x:Key="HeightConverter"/>
</Window.Resources>
<ScrollViewer>
<Grid>
<ItemsControl ItemsSource="{Binding Available}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1" Height="60">
<TextBlock Text="{Binding StringFormat='hh tt'}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl ItemsSource="{Binding Bookings}">
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Margin" Value="{Binding Converter={StaticResource VerticalMarginConverter}}"/>
<Setter Property="Height" Value="{Binding Converter={StaticResource HeightConverter}}"/>
<Setter Property="VerticalAlignment" Value="Top"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="#601050FF" BorderBrush="LightSkyBlue" BorderThickness="1"
x:Name="Border">
<Viewbox Stretch="Uniform">
<TextBlock Text="Booked" FontWeight="Bold" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-45"/>
</TextBlock.LayoutTransform>
</TextBlock>
</Viewbox>
<Border.ToolTip>
<ToolTip>
<StackPanel>
<TextBlock>
<Run Text="From" FontWeight="Bold"/>
<Run Text="{Binding StartString, Mode=OneWay}"/>
</TextBlock>
<TextBlock>
<Run Text="To" FontWeight="Bold"/>
<Run Text="{Binding EndString,Mode=OneWay}"/>
</TextBlock>
</StackPanel>
</ToolTip>
</Border.ToolTip>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</ScrollViewer>
代码背后:
public partial class TimeBookings : Window
{
public TimeBookings()
{
InitializeComponent();
DataContext = new TimeBookingsViewModel();
}
}
视图模型:
public class TimeBookingsViewModel
{
public ObservableCollection<DateTime> Available { get; set; }
public ObservableCollection<TimeRange> Bookings { get; set; }
public TimeBookingsViewModel()
{
Available = new ObservableCollection<DateTime>(Enumerable.Range(8, 11).Select(x => new DateTime(2013, 1, 1).AddHours(x)));
Bookings = new ObservableCollection<TimeRange>();
Bookings.Add(new TimeRange(8, 0, 9, 50) {Base = TimeSpan.FromHours(8)});
Bookings.Add(new TimeRange(10, 0, 11, 00) { Base = TimeSpan.FromHours(8) });
Bookings.Add(new TimeRange(12, 00, 13, 30) { Base = TimeSpan.FromHours(8) });
}
}
数据项:
public class TimeRange
{
public TimeSpan Base { get; set; }
public TimeSpan Start { get; set; }
public TimeSpan End { get; set; }
public string StartString { get { return new DateTime(Start.Ticks).ToString("hh:mm tt"); } }
public string EndString { get { return new DateTime(End.Ticks).ToString("hh:mm tt"); } }
public TimeRange(int starthour, int startminute, int endhour, int endminute)
{
Start = new TimeSpan(0, starthour, startminute, 0);
End = new TimeSpan(0, endhour, endminute, 0);
}
}
还有一些助手(转换器等):
public class TimeRangeToVerticalMarginConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is TimeRange))
return null;
var range = (TimeRange) value;
return new Thickness(2, range.Start.TotalMinutes - range.Base.TotalMinutes, 2, 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class TimeRangeHeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is TimeRange))
return null;
var range = value as TimeRange;
return range.End.Subtract(range.Start).TotalMinutes;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Viewbox
内,使其延伸到可用大小。如果你愿意,你可以改变它,但我无法想象一种更好的方法来使文本适合不同预订的可用空间。ToolTip
。您可以在WPF中really do what you want。底线:
忘记winforms,它太有限了,它没有(真正的)数据绑定,它需要大量的代码来做更少的事情,它不支持任何级别的自定义,它迫使你创建糟糕的Windows 95喜欢用户界面。
WPF Rocks :只需将我的代码复制并粘贴到File -> New Project -> WPF Application
中,然后自行查看结果。
答案 1 :(得分:1)
评估开发控件所花费的时间,将其乘以您的成本/小时,添加一些您将(肯定)产生的错误,并将其与一些经过验证的测试解决方案进行比较:
http://www.telerik.com/products/winforms/scheduler.aspx
http://www.devexpress.com/Products/NET/Controls/WinForms/Scheduler/
我建议您购买您的控件(或某些)。
答案 2 :(得分:1)
您最好的选择是创建一个继承自类似控件的自定义控件,对于您的示例,沿着图片框的行可能是有益的。 对于(略微过时的C ++)自定义控件,请参阅:http://msdn.microsoft.com/en-us/library/ms364048(v=vs.80).aspx
就自定义绘图设置而言:http://msdn.microsoft.com/en-us/library/windows/desktop/bb761817(v=vs.85).aspx
作为概括,这个想法如下: 捕获WM_PAINT事件,并在该事件中向控件渲染预先绘制的图像(这通常通过创建绘制表面,然后将其复制到控件的可渲染疼痛区域来完成)此方法避免任何'闪烁”。
绘图命令大多是简单的'drawline(xy_start,xy_end)。
最后,为了处理一天中的时间,如果你选择(rendersurface.height /(24 * 60)),你将有一个时间到像素的转换。例如:
double convert_Size = (rendersurface.height / (24*60)); //height / Hours_in_day * Minites
int time = (hour * 60) + minite_past_hour;
Pixels_from_top = time * convert_Size;
Pixels_from_top现在是白天该时间的像素y坐标。