Skip to content

Support complex types in datatype #18379

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions samples/BindingDemo/BindingDemo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework>
<!-- <AvaloniaXamlIlDebuggerLaunch>true</AvaloniaXamlIlDebuggerLaunch>-->
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
Expand Down
13 changes: 7 additions & 6 deletions samples/BindingDemo/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
x:Class="BindingDemo.MainWindow"
xmlns:vm="using:BindingDemo.ViewModels"
xmlns:local="using:BindingDemo"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
Title="AvaloniaUI Bindings Test"
Width="800"
Height="600"
Expand All @@ -29,7 +30,7 @@
</StackPanel>
<StackPanel Margin="18" Spacing="4" Width="200">
<TextBlock FontSize="16" Text="Collection Bindings"/>
<TextBox Watermark="Items[1].StringValue" UseFloatingWatermark="True" Text="{Binding Path=Items[1].StringValue}"/>
<TextBox Watermark="Items[1].Value" UseFloatingWatermark="True" Text="{Binding Path=Items[1].Value}"/>
<Button Command="{Binding ShuffleItems}">Shuffle</Button>
</StackPanel>
<StackPanel Margin="18" Spacing="4" Width="200">
Expand All @@ -51,9 +52,9 @@
<TextBox Watermark="Value of first TextBox" UseFloatingWatermark="True"
Text="{Binding #first.Text, Mode=TwoWay}"/>
<TextBox Watermark="Value of SharedItem.StringValue" UseFloatingWatermark="True"
Text="{Binding StringValue, Source={StaticResource SharedItem}, Mode=TwoWay, DataType=vm:MainWindowViewModel+TestItem}"/>
Text="{Binding Value, Source={StaticResource SharedItem}, Mode=TwoWay, DataType={x:Type vm:MainWindowViewModel+TestItem, x:TypeArguments=x:String}}"/>
<TextBox Watermark="Value of SharedItem.StringValue (duplicate)" UseFloatingWatermark="True"
Text="{Binding StringValue, Source={StaticResource SharedItem}, Mode=TwoWay, DataType=vm:MainWindowViewModel+TestItem}"/>
Text="{Binding Value, Source={StaticResource SharedItem}, Mode=TwoWay, DataType={x:Type vm:MainWindowViewModel+TestItem, x:TypeArguments=x:String}}"/>
</StackPanel>
<StackPanel Margin="18" Spacing="4" Width="200" HorizontalAlignment="Left">
<TextBlock FontSize="16" Text="Scheduler"/>
Expand All @@ -67,8 +68,8 @@
<TabItem Header="ListBox">
<StackPanel Orientation="Horizontal">
<StackPanel.DataTemplates>
<DataTemplate DataType="vm:MainWindowViewModel+TestItem">
<TextBlock Text="{Binding StringValue}"/>
<DataTemplate x:DataType="{x:Type vm:MainWindowViewModel+TestItem, x:TypeArguments=x:String}">
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</StackPanel.DataTemplates>
<StackPanel Margin="18" Spacing="4" Width="200">
Expand All @@ -81,7 +82,7 @@
</StackPanel>
<ContentControl Content="{ReflectionBinding Selection.SelectedItems[0]}">
<ContentControl.DataTemplates>
<DataTemplate DataType="vm:MainWindowViewModel+TestItem">
<DataTemplate x:DataType="{x:Type vm:MainWindowViewModel+TestItem, x:TypeArguments=x:String}">
<local:TestItemView></local:TestItemView>
</DataTemplate>
</ContentControl.DataTemplates>
Expand Down
2 changes: 1 addition & 1 deletion samples/BindingDemo/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class MainWindow : Window
{
public MainWindow()
{
Resources["SharedItem"] = new MainWindowViewModel.TestItem() { StringValue = "shared" };
Resources["SharedItem"] = new MainWindowViewModel.TestItem<string>() { Value = "shared" };
this.InitializeComponent();
this.DataContext = new MainWindowViewModel();
this.AttachDevTools();
Expand Down
4 changes: 2 additions & 2 deletions samples/BindingDemo/TestItemView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:viewModels="using:BindingDemo.ViewModels"
x:Class="BindingDemo.TestItemView"
x:DataType="viewModels:MainWindowViewModel+TestItem">
x:DataType="{x:Type viewModels:MainWindowViewModel+TestItem, x:TypeArguments=x:String}">
<StackPanel>
<TextBlock Classes="h1" Text="{Binding StringValue}"/>
<TextBlock Classes="h1" Text="{Binding Value}"/>
<TextBox Text="{Binding Detail}" AcceptsReturn="True"/>
</StackPanel>
</UserControl>
22 changes: 11 additions & 11 deletions samples/BindingDemo/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ public class MainWindowViewModel : ViewModelBase

public MainWindowViewModel()
{
Items = new ObservableCollection<TestItem>(
Enumerable.Range(0, 20).Select(x => new TestItem
Items = new ObservableCollection<TestItem<string>>(
Enumerable.Range(0, 20).Select(x => new TestItem<string>
{
StringValue = "Item " + x,
Value = "Item " + x,
Detail = "Item " + x + " details",
}));

Selection = new SelectionModel<TestItem> { SingleSelect = false };
Selection = new SelectionModel<TestItem<string>> { SingleSelect = false };

ShuffleItems = MiniCommand.Create(() =>
{
Expand Down Expand Up @@ -58,8 +58,8 @@ public MainWindowViewModel()
.Select(x => DateTimeOffset.Now);
}

public ObservableCollection<TestItem> Items { get; }
public SelectionModel<TestItem> Selection { get; }
public ObservableCollection<TestItem<string>> Items { get; }
public SelectionModel<TestItem<string>> Selection { get; }
public MiniCommand ShuffleItems { get; }

public string BooleanString
Expand Down Expand Up @@ -117,15 +117,15 @@ bool CanDo(object parameter)
}

// Nested class, jsut so we can test it in XAML
public class TestItem : ViewModelBase
public class TestItem<T> : ViewModelBase
{
private string _stringValue = "String Value";
private T _value;
private string _detail;

public string StringValue
public T Value
{
get { return _stringValue; }
set { this.RaiseAndSetIfChanged(ref this._stringValue, value); }
get { return _value; }
set { this.RaiseAndSetIfChanged(ref this._value, value); }
}

public string Detail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode nod
{
on.Children.RemoveAt(i);
i--;
if (directive.Values[0] is XamlAstTextNode text)
if (directive.Values[0] is XamlTypeExtensionNode typeNode)
{
directiveDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on, typeNode.Value.GetClrType());
}
else if (directive.Values[0] is XamlAstTextNode text)
{
directiveDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on,
TypeReferenceResolver.ResolveType(context, text.Text, isMarkupExtension: false, text, strict: true).Type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,37 @@ public void ResolvesParentDataContextTypeBasedOnContextShortSyntax()
}
}

[Fact]
public void Resolves_Nested_Generic_DataTypes()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
x:DataType='{x:Type local:TestDataContext+NestedGeneric, x:TypeArguments=x:String}'
x:Name='MyWindow'>
<Panel>
<TextBlock Text='{CompiledBinding Value}' Name='textBlock' />
</Panel>
</Window>");
var textBlock = window.GetControl<TextBlock>("textBlock");

var dataContext = new TestDataContext
{
NestedGenericString = new TestDataContext.NestedGeneric<string>
{
Value = "10"
}
};

window.DataContext = dataContext.NestedGenericString;

Assert.Equal(dataContext.NestedGenericString.Value, textBlock.Text);
}
}

static void Throws(string type, Action cb)
{
try
Expand Down Expand Up @@ -2459,6 +2490,8 @@ public class TestDataContext : TestDataContextBaseClass, IHasPropertyDerived, IH

public INonIntegerIndexerDerived NonIntegerIndexerInterfaceProperty => NonIntegerIndexerProperty;

public NestedGeneric<string>? NestedGenericString { get; init; }

string IHasExplicitProperty.ExplicitProperty => "Hello";

public string ExplicitProperty => "Bye";
Expand All @@ -2484,6 +2517,11 @@ public string this[string key]
}
}
}

public class NestedGeneric<T>
{
public T Value { get; set; }
}
}

public class ListItemCollectionView<T> : List<T>
Expand Down
Loading