簡體   English   中英

如何捆綁附屬物

[英]How to Bind Attached Property

我試圖自己學習WPF,這有點掙扎。 我需要知道如何通過綁定設置附加屬性的值。 附加屬性Grid.Row和Grid.RowSpan是綁定的目標 ,而不是源。 在StackOverflow上已經提出了類似的問題,但是他們被真正了解WPF的人詢問和回答,或者他們涉及價值轉換器等並發症。 我沒有找到適合我並且理解的答案。

在這種情況下,我有一個代表一整天時間表的網格,我想向它添加事件。 每個事件將從特定網格行開始並跨越多個行,具體取決於事件的開始時間和持續時間。 我的理解是你必須使用依賴屬性作為綁定的源,因此我的事件對象ActivityBlock具有StartIncrementDurationIncrements依賴項屬性來描述它在網格上的位置。

就是這樣,這就是我想做的事情:通過綁定在網格中創建一個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM