[英]How to Bind Attached Property
我試圖自己學習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>
這是MainWindow的代碼隱藏文件:
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>
可以綁定Grid.Row
下面是一個簡單的MVVM
示例,
視圖
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<TextBlock Text="Hello" Grid.Row="{Binding RowNumber}"></TextBlock>
</Grid>
</Window>
視圖模型
public class ViewModel
{
public ViewModel()
{
RowNumber = 2;
}
public int RowNumber { get; set; }
}
我已將DataContext
設置為從CodeBehind
查看。 如下所示,哪個DataContext
鏈接到ViewModel
類。 我們可以用不同的方式設置DataContext
。
xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
當您啟動應用程序時,它會將RowNumber
設置為2並在第3行顯示TextBlock
。 稍后您可以通過從ViewModel
更新RowNumber
來更改行
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.