I need a layout that stacks Items horizontal or vertical. Each Item should be separated by a Splitter, so the User can change the Size (Like the Toolbox Container in VisualStudio) The Items come from a Model, so I need a ItemsControl where I can set the ItemsSource.
My first idea was to build a CustomControl derived from Grid. Their I used the "OnVisualChildrenChanged" Method to react when a new Item is added. Then I wantet to add new Column-/Rowdefinitions (Depending wether it schould be horizontal or vertical). But here was the first Proplem. When the Grid is set to IsItemsHost="true" I get a Error that the DefinitionsCollection is not accessable...
Heres a CodeSnipped from the custom control, where I tried to add a row.
private void SetRows()
{
this.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto };
}
protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
{
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
SetRows();
}
EDIT:
I think I found a solution right now.
First I created a CustomControl that derives from ItemsControl. In his template I add a Grid without inserting a Itempresenter. Now I override OnItemsChange. When a Item is added to the Collection I create a FrameworkElement and set DataContext to the added Item, than I add two Column definition to the Grid and add my Item plus an Gridsplitter to the Grid. This works well, now I only need to get the ItemTemplate from my Itemscontrol to use it in the grid.
When I solved this last issue I will add a small example.
Heres my Solution so far. If someone has a better idea, you're welcome.
Heres the CustomControl Code behind:
public class ResizableItemControl : ItemsControl
{
public ObservableCollection<FrameworkElement> _gridItems = new ObservableCollection<FrameworkElement>();
private Grid _grid;
static ResizableItemControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ResizableItemControl), new FrameworkPropertyMetadata(typeof(ResizableItemControl)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (this.Template != null)
{
_grid = this.Template.FindName("PART_Grid", this) as Grid;
}
// Add all existing items to grid
foreach (var item in Items)
{
AddItemToGrid(item);
}
}
/// <summary>
/// Called when Items in ItemsCollection changing
/// </summary>
/// <param name="e"></param>
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (Items.Count > 0)
{
//Add Items in Grid when new Items where add
var myItem = this.Items[Items.Count - 1];
AddItemToGrid(myItem);
}
break;
}
}
/// <summary>
/// Adds Items to grid plus GridSplitter
/// </summary>
/// <param name="myItem"></param>
private void AddItemToGrid(object myItem)
{
var visualItem = this.ItemTemplate.LoadContent() as FrameworkElement;
if (visualItem != null)
{
visualItem.DataContext = myItem;
if (_grid != null)
{
if (_grid.ColumnDefinitions.Count != 0)
{
_grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
_grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
var gridSplitter = CreateSplitter();
Grid.SetColumn(gridSplitter, _grid.ColumnDefinitions.Count - 2);
Grid.SetColumn(visualItem, _grid.ColumnDefinitions.Count - 1);
_grid.Children.Add(gridSplitter);
_grid.Children.Add(visualItem);
//_grid.Children.Add(myTest);
}
else
{
_grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
Grid.SetColumn(visualItem, _grid.ColumnDefinitions.Count - 1);
_grid.Children.Add(visualItem);
}
}
}
}
private static GridSplitter CreateSplitter()
{
var gridSplitter = new GridSplitter() {ResizeDirection = GridResizeDirection.Columns};
gridSplitter.Width = 5;
gridSplitter.HorizontalAlignment = HorizontalAlignment.Stretch;
gridSplitter.Background = new SolidColorBrush(Colors.Black);
return gridSplitter;
}
}
The generic Xaml:
<Style TargetType="{x:Type controls:ResizableItemControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:ResizableItemControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Hidden">
<Grid x:Name="PART_Grid"></Grid>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And how to use it:
<controls:ResizableItemControl
ItemsSource="{Binding ElementName=this,Path=Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label
Content="{Binding Name}"
ToolTip="{Binding Description}"
Background="Black"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</controls:ResizableItemControl>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With