committed by
GitHub
109 changed files with 1387 additions and 722 deletions
@ -1,7 +1,7 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="HarfBuzzSharp" Version="2.8.2.1-preview.108" /> |
<PackageReference Include="HarfBuzzSharp" Version="2.8.2.3" /> |
||||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2.1-preview.108" /> |
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2.3" /> |
||||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2.1-preview.108" /> |
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2.3" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,5 +1,5 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.1" /> |
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,5 +1,5 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="Moq" Version="4.14.1" /> |
<PackageReference Include="Moq" Version="4.18.4" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,7 +1,7 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="SkiaSharp" Version="2.88.1" /> |
<PackageReference Include="SkiaSharp" Version="2.88.3" /> |
||||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.1" /> |
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.3" /> |
||||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.1" /> |
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.3" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,16 +1,79 @@ |
|||||
using System; |
using System; |
||||
|
using System.Collections.Generic; |
||||
using System.IO; |
using System.IO; |
||||
|
using System.Linq; |
||||
using System.Reflection; |
using System.Reflection; |
||||
|
using System.Text.RegularExpressions; |
||||
using Avalonia.Markup.Xaml; |
using Avalonia.Markup.Xaml; |
||||
using Avalonia.Markup.Xaml.XamlIl; |
using Avalonia.Markup.Xaml.XamlIl; |
||||
|
|
||||
namespace Avalonia.Designer.HostApp |
namespace Avalonia.Designer.HostApp; |
||||
|
|
||||
|
class DesignXamlLoader : AvaloniaXamlLoader.IRuntimeXamlLoader |
||||
{ |
{ |
||||
class DesignXamlLoader : AvaloniaXamlLoader.IRuntimeXamlLoader |
public object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) |
||||
|
{ |
||||
|
PreloadDepsAssemblies(configuration.LocalAssembly ?? Assembly.GetEntryAssembly()); |
||||
|
|
||||
|
return AvaloniaXamlIlRuntimeCompiler.Load(document, configuration); |
||||
|
} |
||||
|
|
||||
|
private void PreloadDepsAssemblies(Assembly targetAssembly) |
||||
{ |
{ |
||||
public object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) |
// Assemblies loaded in memory (e.g. single file) return empty string from Location.
|
||||
|
// In these cases, don't try probing next to the assembly.
|
||||
|
var assemblyLocation = targetAssembly.Location; |
||||
|
if (string.IsNullOrEmpty(assemblyLocation)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var depsJsonFile = Path.ChangeExtension(assemblyLocation, ".deps.json"); |
||||
|
if (!File.Exists(depsJsonFile)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
using var stream = File.OpenRead(depsJsonFile); |
||||
|
|
||||
|
/* |
||||
|
We can't use any references in the Avalonia.Designer.HostApp. Including even json. |
||||
|
Ideally we would prefer Microsoft.Extensions.DependencyModel package, but can't use it here. |
||||
|
So, instead we need to fallback to some JSON parsing using pretty easy regex. |
||||
|
|
||||
|
Json part example: |
||||
|
"Avalonia.Xaml.Interactions/11.0.0-preview5": { |
||||
|
"dependencies": { |
||||
|
"Avalonia": "11.0.999", |
||||
|
"Avalonia.Xaml.Interactivity": "11.0.0-preview5" |
||||
|
}, |
||||
|
"runtime": { |
||||
|
"lib/net6.0/Avalonia.Xaml.Interactions.dll": { |
||||
|
"assemblyVersion": "11.0.0.0", |
||||
|
"fileVersion": "11.0.0.0" |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
We want to extract "lib/net6.0/Avalonia.Xaml.Interactions.dll" from here. |
||||
|
No need to resolve real path of ref assemblies. |
||||
|
No need to handle special cases with .NET Framework and GAC. |
||||
|
*/ |
||||
|
var text = new StreamReader(stream).ReadToEnd(); |
||||
|
var matches = Regex.Matches( text, """runtime"\s*:\s*{\s*"([^"]+)""");
|
||||
|
|
||||
|
foreach (Match match in matches) |
||||
{ |
{ |
||||
return AvaloniaXamlIlRuntimeCompiler.Load(document, configuration); |
if (match.Groups[1] is { Success: true } g) |
||||
|
{ |
||||
|
var assemblyName = Path.GetFileNameWithoutExtension(g.Value); |
||||
|
try |
||||
|
{ |
||||
|
_ = Assembly.Load(new AssemblyName(assemblyName)); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,330 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using Avalonia.Controls.Presenters; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
using Avalonia.Controls.Templates; |
||||
|
using Avalonia.Data; |
||||
|
using Avalonia.Styling; |
||||
|
using Avalonia.UnitTests; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Avalonia.Controls.UnitTests.Primitives |
||||
|
{ |
||||
|
public class SelectingItemsControlTests_SelectedValue |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Setting_SelectedItem_Sets_SelectedValue() |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
Template = Template() |
||||
|
}; |
||||
|
|
||||
|
sic.SelectedItem = items[0]; |
||||
|
|
||||
|
Assert.Equal(items[0].Name, sic.SelectedValue); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_SelectedIndex_Sets_SelectedValue() |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
Template = Template() |
||||
|
}; |
||||
|
|
||||
|
sic.SelectedIndex = 0; |
||||
|
|
||||
|
Assert.Equal(items[0].Name, sic.SelectedValue); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_SelectedItems_Sets_SelectedValue() |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new ListBox |
||||
|
{ |
||||
|
Items = items, |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
Template = Template() |
||||
|
}; |
||||
|
|
||||
|
sic.SelectedItems = new List<TestClass> |
||||
|
{ |
||||
|
items[1], |
||||
|
items[3], |
||||
|
items[4] |
||||
|
}; |
||||
|
|
||||
|
// When interacting, SelectedItem is the first item in the SelectedItems collection
|
||||
|
// But when set here, it's the last
|
||||
|
Assert.Equal(items[4].Name, sic.SelectedValue); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_SelectedValue_Sets_SelectedIndex() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
Template = Template() |
||||
|
}; |
||||
|
|
||||
|
Prepare(sic); |
||||
|
|
||||
|
sic.SelectedValue = items[1].Name; |
||||
|
|
||||
|
Assert.Equal(1, sic.SelectedIndex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_SelectedValue_Sets_SelectedItem() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
Template = Template() |
||||
|
}; |
||||
|
|
||||
|
Prepare(sic); |
||||
|
|
||||
|
sic.SelectedValue = "Item2"; |
||||
|
|
||||
|
Assert.Equal(items[1], sic.SelectedItem); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Changing_SelectedValueBinding_Updates_SelectedValue() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
Template = Template() |
||||
|
}; |
||||
|
|
||||
|
sic.SelectedValue = "Item2"; |
||||
|
|
||||
|
sic.SelectedValueBinding = new Binding("AltProperty"); |
||||
|
|
||||
|
// Ensure SelectedItem didn't change
|
||||
|
Assert.Equal(items[1], sic.SelectedItem); |
||||
|
|
||||
|
|
||||
|
Assert.Equal("Alt2", sic.SelectedValue); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void SelectedValue_With_Null_SelectedValueBinding_Is_Item() |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
Template = Template() |
||||
|
}; |
||||
|
|
||||
|
sic.SelectedIndex = 0; |
||||
|
|
||||
|
Assert.Equal(items[0], sic.SelectedValue); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_SelectedValue_Before_Initialize_Should_Retain_Selection() |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
Template = Template(), |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
SelectedValue = "Item2" |
||||
|
}; |
||||
|
|
||||
|
sic.BeginInit(); |
||||
|
sic.EndInit(); |
||||
|
|
||||
|
Assert.Equal(items[1].Name, sic.SelectedValue); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_SelectedValue_During_Initialize_Should_Take_Priority_Over_Previous_Value() |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
Template = Template(), |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
SelectedValue = "Item2" |
||||
|
}; |
||||
|
|
||||
|
sic.BeginInit(); |
||||
|
sic.SelectedValue = "Item1"; |
||||
|
sic.EndInit(); |
||||
|
|
||||
|
Assert.Equal(items[0].Name, sic.SelectedValue); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Changing_Items_Should_Clear_SelectedValue() |
||||
|
{ |
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
Template = Template(), |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
SelectedValue = "Item2" |
||||
|
}; |
||||
|
|
||||
|
Prepare(sic); |
||||
|
|
||||
|
sic.Items = new List<TestClass> |
||||
|
{ |
||||
|
new TestClass("NewItem", string.Empty) |
||||
|
}; |
||||
|
|
||||
|
Assert.Equal(null, sic.SelectedValue); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Setting_SelectedValue_Should_Raise_SelectionChanged_Event() |
||||
|
{ |
||||
|
// Unlike SelectedIndex/SelectedItem tests, we need the ItemsControl to
|
||||
|
// initialize so that SelectedValue can actually be looked up
|
||||
|
using (UnitTestApplication.Start(TestServices.StyledWindow)) |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
Template = Template(), |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
}; |
||||
|
|
||||
|
Prepare(sic); |
||||
|
|
||||
|
var called = false; |
||||
|
sic.SelectionChanged += (s, e) => |
||||
|
{ |
||||
|
Assert.Same(items[1], e.AddedItems.Cast<object>().Single()); |
||||
|
Assert.Empty(e.RemovedItems); |
||||
|
called = true; |
||||
|
}; |
||||
|
|
||||
|
sic.SelectedValue = "Item2"; |
||||
|
Assert.True(called); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Clearing_SelectedValue_Should_Raise_SelectionChanged_Event() |
||||
|
{ |
||||
|
var items = TestClass.GetItems(); |
||||
|
var sic = new SelectingItemsControl |
||||
|
{ |
||||
|
Items = items, |
||||
|
Template = Template(), |
||||
|
SelectedValueBinding = new Binding("Name"), |
||||
|
SelectedValue = "Item2" |
||||
|
}; |
||||
|
|
||||
|
var called = false; |
||||
|
sic.SelectionChanged += (s, e) => |
||||
|
{ |
||||
|
Assert.Same(items[1], e.RemovedItems.Cast<object>().Single()); |
||||
|
Assert.Empty(e.AddedItems); |
||||
|
called = true; |
||||
|
}; |
||||
|
|
||||
|
sic.SelectedValue = null; |
||||
|
Assert.True(called); |
||||
|
} |
||||
|
|
||||
|
private static FuncControlTemplate Template() |
||||
|
{ |
||||
|
return new FuncControlTemplate<SelectingItemsControl>((control, scope) => |
||||
|
new ItemsPresenter |
||||
|
{ |
||||
|
Name = "itemsPresenter", |
||||
|
[~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty], |
||||
|
}.RegisterInNameScope(scope)); |
||||
|
} |
||||
|
|
||||
|
private static void Prepare(SelectingItemsControl target) |
||||
|
{ |
||||
|
var root = new TestRoot |
||||
|
{ |
||||
|
Child = target, |
||||
|
Width = 100, |
||||
|
Height = 100, |
||||
|
Styles = |
||||
|
{ |
||||
|
new Style(x => x.Is<SelectingItemsControl>()) |
||||
|
{ |
||||
|
Setters = |
||||
|
{ |
||||
|
new Setter(ListBox.TemplateProperty, Template()), |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
root.LayoutManager.ExecuteInitialLayoutPass(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class TestClass |
||||
|
{ |
||||
|
public TestClass(string name, string alt) |
||||
|
{ |
||||
|
Name = name; |
||||
|
AltProperty = alt; |
||||
|
} |
||||
|
|
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public string AltProperty { get; set; } |
||||
|
|
||||
|
public static List<TestClass> GetItems() |
||||
|
{ |
||||
|
return new List<TestClass> |
||||
|
{ |
||||
|
new TestClass("Item1", "Alt1"), |
||||
|
new TestClass("Item2", "Alt2"), |
||||
|
new TestClass("Item3", "Alt3"), |
||||
|
new TestClass("Item4", "Alt4"), |
||||
|
new TestClass("Item5", "Alt5"), |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue