我想学习WPF自己,这是一个斗争。我需要知道如何通过绑定来设置附加属性的值。附加属性Grid.Row和Grid.RowSpan是目的地用于绑定,而不是源。 StackOverflow已经提出了类似的问题,但是他们被真正认识WPF的人问及回答,或者涉及价值转换器等复杂问题。我还没有找到适用于我的答案。如何绑定附加属性
在这种情况下,我有一个表示一整天的时间表的网格,并且我想向它添加事件。每个事件将从特定的网格行开始,并跨越多行,具体取决于事件的开始时间和持续时间。我的理解是,你必须使用依赖项属性作为绑定的源,所以我的事件对象ActivityBlock
具有StartIncrement
和DurationIncrements
依赖项属性来描述它在网格上的位置。
就是这样,这就是我想要做的:通过绑定在网格中创建一个UserControl位置。
我相信我的问题很可能在我的MainWindow XAML中,在网格上错误地设置了绑定。 (请注意,我在构造函数中以编程方式创建网格行,因此请勿在下面的XAML中查找它们)。
当我运行我的应用程序时,会创建事件,但它不会显示在网格上的正确位置,就好像Grid.Row和Grid.RowSpan永远不会更新一样。绑定Grid.Row和Grid.RowSpan是不可能的?如果不是,我做错了什么?
这里是MainWindow.xaml,我的问题是最有可能是:
<Window x:Class="DayCalendar.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DayCalendar"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Activated="Window_Activated"
>
<DockPanel LastChildFill="True">
<Rectangle Width="50" DockPanel.Dock="Left"/>
<Rectangle Width="50" DockPanel.Dock="Right"/>
<Grid x:Name="TheDay" Background="#EEE">
<ItemsControl ItemsSource="{Binding Path=Children}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Grid.Row" Value="{Binding Path=StartIncrement}" />
<Setter Property="Grid.RowSpan" Value="{Binding Path=DurationIncrements}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Grid>
</DockPanel>
</Window>
下面是代码隐藏文件的主窗口:
using System;
using System.Windows;
using System.Windows.Controls;
using DayCalendar.MyControls;
namespace DayCalendar {
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
var rowDefs = TheDay.RowDefinitions;
rowDefs.Clear();
for (int ix = 0; ix < (60/ActivityBlock.MINUTES_PER_INCREMENT) * 24; ix += 1) {
rowDefs.Add(new RowDefinition());
}
}
private void Window_Activated(object sender, EventArgs e) {
if (m_firstActivation) {
m_firstActivation = false;
var firstActivity = new ActivityBlock();
var today = DateTime.Now.Date;
var startTime = today.AddHours(11.5);
var durationSpan = new TimeSpan(1, 0, 0);
firstActivity.SetTimeSpan(startTime, durationSpan);
TheDay.Children.Add(firstActivity);
}
}
private bool m_firstActivation = true;
}
}
这里是ActivityBlock代码:
using System;
using System.Windows;
using System.Windows.Controls;
namespace DayCalendar.MyControls {
public partial class ActivityBlock : UserControl {
public int StartIncrement {
get { return (int) GetValue(StartIncrementProperty); }
set { SetValue(StartIncrementProperty, value); }
}
public int DurationIncrements {
get { return (int) GetValue(DurationIncrementsProperty); }
set { SetValue(DurationIncrementsProperty, value); }
}
public ActivityBlock() {
InitializeComponent();
}
public void SetTimeSpan(DateTime startTime, TimeSpan duration) {
int startMinute = startTime.Hour * 60 + startTime.Minute;
int durationMinutes = (int) duration.TotalMinutes;
StartIncrement = startMinute/MINUTES_PER_INCREMENT;
DurationIncrements = Math.Max(1, durationMinutes/MINUTES_PER_INCREMENT);
}
static ActivityBlock() {
var thisType = typeof(ActivityBlock);
var affectsArrangeAndMeasure = FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure;
int startIncrementDefault = 0;
StartIncrementProperty = DependencyProperty.Register(
nameof(StartIncrement),
startIncrementDefault.GetType(),
thisType,
new FrameworkPropertyMetadata(startIncrementDefault, affectsArrangeAndMeasure)
);
int durationIncrementsDefault = 1;
DurationIncrementsProperty = DependencyProperty.Register(
nameof(DurationIncrements),
durationIncrementsDefault.GetType(),
thisType,
new FrameworkPropertyMetadata(startIncrementDefault, affectsArrangeAndMeasure)
);
}
public const int MINUTES_PER_INCREMENT = 6; // 1/10th of an hour
static public readonly DependencyProperty StartIncrementProperty;
static public readonly DependencyProperty DurationIncrementsProperty;
}
}
对应的XAML不是很有趣,但我将它包括在需要的情况下:
<UserControl x:Class="DayCalendar.MyControls.ActivityBlock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:DayCalendar.MyControls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Border BorderThickness="3" BorderBrush="Black" Background="Chartreuse">
<DockPanel LastChildFill="True">
<TextBlock TextWrapping="WrapWithOverflow">Event Description</TextBlock>
</DockPanel>
</Border>
</UserControl>
我对您要实现的内容有模糊的线索。但是你很难将CodeBehind和xaml混合在一起,以至于无法实现。问问你自己一件事。我会在CodeBehind中执行**所有操作**,并且能够访问我希望的每一个控件,或者我应该切换到MVVM,因为DataBinding仅在此处有意义。 – lokusking