我想學習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