在 ItemsControl 中定位项目
Positioning Items in ItemsControl
我有一个 ItemsControl
绑定到这样的数据:
<ItemsControl Name="MainPanel" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Definition}" TextWrapping="Wrap"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
在我的数据模型中,每个项目都有一个 y
坐标,用于将项目垂直放置在屏幕上,并且每个项目的高度可变(因为 TextWrapping
)。
我需要每个项目都定位在 y
坐标上,除非它与前一个项目重叠,在这种情况下它被放置在前一个项目的下方。
我想使用 Margin
属性 来做到这一点,但实际上并不是那么简单...
关于如何进行的任何想法?
我认为更改 TextBlock.Margin.Top
是一种简单的方法。
<ItemsControl ItemsSource="your model collection"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- Need ItemsControl for calculation. -->
<TextBlock Text="{Binding Text}" TextWrapping="Wrap"
Tag="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}}">
<TextBlock.Margin>
<MultiBinding Converter="{StaticResource calcOffsetY}">
<Binding RelativeSource="{RelativeSource Self}"/>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
</MultiBinding>
</TextBlock.Margin>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
和转换器。
public class CalcOffsetY : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var tbk = (TextBlock)values[0];
var offsetY = tbk.TranslatePoint(tbk.RenderTransformOrigin, (UIElement)tbk.Tag).Y -
tbk.Margin.Top;
var y = ((YourModelType)tbk.DataContext).Y;
tbk.SetCurrentValue(TextBlock.MarginProperty, new Thickness(tbk.Margin.Left, y > offsetY ? y - offsetY : 0,
tbk.Margin.Right, tbk.Margin.Bottom));
tbk.UpdateLayout(); // Update layout immediately, so next item will get correct result.
return Binding.DoNothing; // Already nothing to do.
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
我有一个 ItemsControl
绑定到这样的数据:
<ItemsControl Name="MainPanel" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Definition}" TextWrapping="Wrap"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
在我的数据模型中,每个项目都有一个 y
坐标,用于将项目垂直放置在屏幕上,并且每个项目的高度可变(因为 TextWrapping
)。
我需要每个项目都定位在 y
坐标上,除非它与前一个项目重叠,在这种情况下它被放置在前一个项目的下方。
我想使用 Margin
属性 来做到这一点,但实际上并不是那么简单...
关于如何进行的任何想法?
我认为更改 TextBlock.Margin.Top
是一种简单的方法。
<ItemsControl ItemsSource="your model collection"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- Need ItemsControl for calculation. -->
<TextBlock Text="{Binding Text}" TextWrapping="Wrap"
Tag="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}}">
<TextBlock.Margin>
<MultiBinding Converter="{StaticResource calcOffsetY}">
<Binding RelativeSource="{RelativeSource Self}"/>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
</MultiBinding>
</TextBlock.Margin>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
和转换器。
public class CalcOffsetY : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var tbk = (TextBlock)values[0];
var offsetY = tbk.TranslatePoint(tbk.RenderTransformOrigin, (UIElement)tbk.Tag).Y -
tbk.Margin.Top;
var y = ((YourModelType)tbk.DataContext).Y;
tbk.SetCurrentValue(TextBlock.MarginProperty, new Thickness(tbk.Margin.Left, y > offsetY ? y - offsetY : 0,
tbk.Margin.Right, tbk.Margin.Bottom));
tbk.UpdateLayout(); // Update layout immediately, so next item will get correct result.
return Binding.DoNothing; // Already nothing to do.
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}