I am trying to implement a user control that represents a timeline (like in a video editor) with a segment whose start- and end-marker can be dragged by the user.
I am representing a segment like this in my view model:
public class Moment : ViewModelBase
{
[Reactive] public double From { get; set; }
[Reactive] public double Duration { get; set; }
}
And attempted to implement the view using a grid with grid splitters like this:
<Grid ColumnDefinitions="Auto,3,Auto,3,*" HorizontalAlignment="Stretch">
<Panel Grid.Column="0" Name="SpacerLeft"
Width="{Binding From}" />
<GridSplitter Grid.Column="1" Background="cyan" />
<Rectangle Grid.Column="2" Name="SpacerSegment"
HorizontalAlignment="Stretch" Fill="red" Height="40"
Width="{Binding Duration}">
</Rectangle>
<GridSplitter Grid.Column="3" Background="cyan" />
<Panel Grid.Column="4" Name="SpacerRight"/>
</Grid>
This works as in I can somewhat visually resize the segment:
However, I am struggling to get the size changes back into the view model, which you can also see in the red area not changing size. I couldn't find a way to retrieve the width changes of the SpacerLeft
or SpacerSegment
controls.
What I tried instead was removing the dedicated Width
properties and instead binding the grid's ColumnDefinitions
. I added this property to my view model:
public ColumnDefinitions ColumnDefinitions
{
get => ColumnDefinitions.Parse($"{From},3,{Duration},3,*");
set
{
From = value[0].ActualWidth;
Duration = value[2].ActualWidth;
}
}
and changed the view XAML to this:
<Grid ColumnDefinitions="{Binding ColumnDefinitions}" HorizontalAlignment="Stretch">
<Panel Grid.Column="0" Name="SpacerLeft" />
<GridSplitter Grid.Column="1" Background="cyan" />
<Rectangle Grid.Column="2" Name="SpacerSegment"
HorizontalAlignment="Stretch" Fill="red" Height="40">
</Rectangle>
<GridSplitter Grid.Column="3" Background="cyan" />
<Panel Grid.Column="4" Name="SpacerRight"/>
</Grid>
But this fails to compile for a reason that unfortunately doesn't make much sense to me:
InvalidCastException: Unable to cast object of type 'Avalonia.Data.Binding' to type 'Avalonia.Controls.ColumnDefinition'. System.InvalidCastException: Unable to cast object of type 'Avalonia.Data.Binding' to type 'Avalonia.Controls.ColumnDefinition'.
at Avalonia.Collections.AvaloniaList`1.System.Collections.IList.Add(Object value) in /_/src/Avalonia.Base/Collections/AvaloniaList.cs:line 520
at Builder_1ee6d795025442edb279bcc7110e88eb_avares://AvaloniaOutseekClient/Views/MomentsSourceView.axaml.XamlClosure_2.Build(IServiceProvider )
at Avalonia.Markup.Xaml.XamlIl.Runtime.XamlIlRuntimeHelpers.<>c__DisplayClass0_0.<DeferredTransformationFactoryV1>b__0(IServiceProvider sp) in /_/src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs:line 28
at Avalonia.Markup.Xaml.Templates.TemplateContent.Load(Object templateContent) in /_/src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs:line 17
at Avalonia.Markup.Xaml.Templates.DataTemplate.Build(Object data, IControl existing) in /_/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs:line 33
at Avalonia.Controls.Presenters.ContentPresenter.CreateChild() in /_/src/Avalonia.Controls/Presenters/ContentPresenter.cs:line 356
...