2016-08-02 26 views
3

私は自分でWPFを学習しようとしていますが、それは少し苦労しています。バインドを介して、添付プロパティの値を設定する方法を知る必要があります。添付プロパティGrid.RowおよびGrid.RowSpanは、バインディングのソースではなく、の宛先です。 StackOverflowについても同様の質問がありましたが、WPFを本当に知っている人が尋ねて回答したり、バリューコンバータのような複雑な問題を抱えていました。私は適用可能で、わかりやすい答えを見つけられませんでした。添付プロパティをバインドする方法

この場合、1日のスケジュールを表すグリッドがあり、イベントを追加したいと思います。各イベントは、イベントの開始時刻と期間に応じて、特定のグリッド行から開始し、複数の行にまたがります。私の理解では、バインディングのソースとして依存関係プロパティを使用する必要があるので、イベントオブジェクト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> 
+1

私はあなたが達成したいことについて曖昧な手がかりを持っています。しかし、CodeBehindとxamlを混ぜることは難しく、実現することは不可能です。一つ自分自身に尋ねなさい。私はCodeBehindで**すべて**を行い、私が望むすべてのコントロールにアクセスできるようにするか、またはMVBMに切り替える必要があります。これは、DataBindingが意味をなさないためです。 – lokusking

答えて

1

ここ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> 

のViewModel

public class ViewModel 
{ 
    public ViewModel() 
    { 
     RowNumber = 2; 
    } 

    public int RowNumber { get; set; } 
} 

DataContextをビューに設定しました。CodeBehindです。以下のようになります。DataContextViewModelクラスにリンクされています。異なる方法でDataContextを設定することができます。

xaml.cs

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = new ViewModel();  
    } 
} 

あなたがアプリケーションを起動すると、それはRowNumber 2に設定し、3行目にTextBlockが表示されます。後で更新によって行を変更することができますRowNumberからViewModel

+0

ありがとう、アビン。あなたのサンプルビューは非常にはっきりしていますが、私はViewModelに関する質問があります。あなたの例では、ViewModelとTextBlockをリンクしていますか?コードで2番目のTextBlockを作成し、それを子として追加した場合、新しいTextModelを新しいViewModelにリンクして、各TextBlockがグリッドの正しい領域に表示されるようにするにはどうすればよいですか? –

+0

私はcodebehindからdataContextを設定する方法を示す答えを編集しました。より多くのテキストブロックを追加するには、新しいテキストブロックをTextBlockのコレクションに追加して、それを保持するコンテナを追加できるようにします。あなたはItemsControlをその質問に使用しています。そのため、ItemsControlにバインドされているコレクションの数に基づいてコントロールや要素を拡張できるコレクションです。 ItemsControlでプロパティを設定する必要がある場合は、スタイルを使用する必要があります。それが助けて欲しいGoogleはあなたの親友です。 –

関連する問題