committed by
GitHub
69 changed files with 839 additions and 799 deletions
@ -0,0 +1,33 @@ |
|||||
|
<UserControl xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
x:Class="ControlCatalog.Pages.TabStripPage" |
||||
|
xmlns="https://github.com/avaloniaui"> |
||||
|
<StackPanel Orientation="Vertical" Spacing="4"> |
||||
|
<TextBlock Classes="h1">TabStrip</TextBlock> |
||||
|
<TextBlock Classes="h2">A control which displays a selectable strip of tabs</TextBlock> |
||||
|
|
||||
|
<Separator Margin="0 16"/> |
||||
|
|
||||
|
<TextBlock Classes="h1">Defined in XAML</TextBlock> |
||||
|
<TabStrip> |
||||
|
<TabStripItem>Item 1</TabStripItem> |
||||
|
<TabStripItem>Item 2</TabStripItem> |
||||
|
<TabStripItem IsEnabled="False">Disabled</TabStripItem> |
||||
|
</TabStrip> |
||||
|
|
||||
|
<Separator Margin="0 16"/> |
||||
|
|
||||
|
<TextBlock Classes="h1">Dynamically generated</TextBlock> |
||||
|
<TabStrip Items="{Binding}"> |
||||
|
<TabStrip.Styles> |
||||
|
<Style Selector="TabStripItem"> |
||||
|
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/> |
||||
|
</Style> |
||||
|
</TabStrip.Styles> |
||||
|
<TabStrip.ItemTemplate> |
||||
|
<DataTemplate> |
||||
|
<TextBlock Text="{Binding Header}"/> |
||||
|
</DataTemplate> |
||||
|
</TabStrip.ItemTemplate> |
||||
|
</TabStrip> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,45 @@ |
|||||
|
using System; |
||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Markup.Xaml; |
||||
|
using Avalonia.Media.Imaging; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace ControlCatalog.Pages |
||||
|
{ |
||||
|
public class TabStripPage : UserControl |
||||
|
{ |
||||
|
public TabStripPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
|
||||
|
DataContext = new[] |
||||
|
{ |
||||
|
new TabStripItemViewModel |
||||
|
{ |
||||
|
Header = "Item 1", |
||||
|
}, |
||||
|
new TabStripItemViewModel |
||||
|
{ |
||||
|
Header = "Item 2", |
||||
|
}, |
||||
|
new TabStripItemViewModel |
||||
|
{ |
||||
|
Header = "Disabled", |
||||
|
IsEnabled = false, |
||||
|
}, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private void InitializeComponent() |
||||
|
{ |
||||
|
AvaloniaXamlLoader.Load(this); |
||||
|
} |
||||
|
|
||||
|
private class TabStripItemViewModel |
||||
|
{ |
||||
|
public string Header { get; set; } |
||||
|
public bool IsEnabled { get; set; } = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,35 +0,0 @@ |
|||||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
||||
|
|
||||
using System; |
|
||||
|
|
||||
namespace Avalonia.Controls.Templates |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Selects a member of an object using a <see cref="Func{TObject, TMember}"/>.
|
|
||||
/// </summary>
|
|
||||
public class FuncMemberSelector<TObject, TMember> : IMemberSelector |
|
||||
{ |
|
||||
private readonly Func<TObject, TMember> _selector; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="FuncMemberSelector{TObject, TMember}"/>
|
|
||||
/// class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="selector">The selector.</param>
|
|
||||
public FuncMemberSelector(Func<TObject, TMember> selector) |
|
||||
{ |
|
||||
this._selector = selector; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Selects a member of an object.
|
|
||||
/// </summary>
|
|
||||
/// <param name="o">The object.</param>
|
|
||||
/// <returns>The selected member.</returns>
|
|
||||
public object Select(object o) |
|
||||
{ |
|
||||
return (o is TObject) ? _selector((TObject)o) : default(TMember); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,18 +0,0 @@ |
|||||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
||||
|
|
||||
namespace Avalonia.Controls.Templates |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Selects a member of an object.
|
|
||||
/// </summary>
|
|
||||
public interface IMemberSelector |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Selects a member of an object.
|
|
||||
/// </summary>
|
|
||||
/// <param name="o">The object.</param>
|
|
||||
/// <returns>The selected member.</returns>
|
|
||||
object Select(object o); |
|
||||
} |
|
||||
} |
|
||||
@ -1,23 +1,24 @@ |
|||||
<UserControl xmlns="https://github.com/avaloniaui" |
<UserControl xmlns="https://github.com/avaloniaui" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
x:Class="Avalonia.Diagnostics.DevTools"> |
x:Class="Avalonia.Diagnostics.DevTools"> |
||||
<Grid RowDefinitions="Auto,*,Auto"> |
<Grid RowDefinitions="*,Auto" Margin="4"> |
||||
<TabStrip SelectedIndex="{Binding SelectedTab, Mode=TwoWay}"> |
|
||||
<TabStripItem Content="Logical Tree"/> |
|
||||
<TabStripItem Content="Visual Tree"/> |
|
||||
<TabStripItem Content="Events"/> |
|
||||
</TabStrip> |
|
||||
|
|
||||
<ContentControl Content="{Binding Content}" Grid.Row="1"/> |
<TabControl Grid.Row="0" Items="{Binding Tools}" SelectedItem="{Binding SelectedTool}"> |
||||
|
<TabControl.ItemTemplate> |
||||
<StackPanel Spacing="4" Orientation="Horizontal" Grid.Row="2"> |
<DataTemplate> |
||||
<TextBlock>Hold Ctrl+Shift over a control to inspect.</TextBlock> |
<TextBlock Text="{Binding Name}" /> |
||||
<Separator Width="8"/> |
</DataTemplate> |
||||
<TextBlock>Focused:</TextBlock> |
</TabControl.ItemTemplate> |
||||
<TextBlock Text="{Binding FocusedControl}"/> |
</TabControl> |
||||
<Separator Width="8"/> |
|
||||
<TextBlock>Pointer Over:</TextBlock> |
<StackPanel Grid.Row="1" Spacing="4" Orientation="Horizontal"> |
||||
<TextBlock Text="{Binding PointerOverElement}"/> |
<TextBlock>Hold Ctrl+Shift over a control to inspect.</TextBlock> |
||||
</StackPanel> |
<Separator Width="8" /> |
||||
</Grid> |
<TextBlock>Focused:</TextBlock> |
||||
|
<TextBlock Text="{Binding FocusedControl}" /> |
||||
|
<Separator Width="8" /> |
||||
|
<TextBlock>Pointer Over:</TextBlock> |
||||
|
<TextBlock Text="{Binding PointerOverElement}" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
</UserControl> |
</UserControl> |
||||
|
|||||
@ -0,0 +1,16 @@ |
|||||
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
namespace Avalonia.Diagnostics.ViewModels |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// View model interface for tool showing up in DevTools
|
||||
|
/// </summary>
|
||||
|
public interface IDevToolViewModel |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Name of a tool.
|
||||
|
/// </summary>
|
||||
|
string Name { get; } |
||||
|
} |
||||
|
} |
||||
@ -1,4 +1,7 @@ |
|||||
using System; |
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
using System.ComponentModel; |
using System.ComponentModel; |
||||
using System.Reactive.Linq; |
using System.Reactive.Linq; |
||||
using System.Reflection; |
using System.Reflection; |
||||
@ -1,24 +0,0 @@ |
|||||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
||||
|
|
||||
using System; |
|
||||
using System.Globalization; |
|
||||
using Avalonia.Markup.Xaml.Templates; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.Converters |
|
||||
{ |
|
||||
using System.ComponentModel; |
|
||||
|
|
||||
public class MemberSelectorTypeConverter : TypeConverter |
|
||||
{ |
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) |
|
||||
{ |
|
||||
return sourceType == typeof(string); |
|
||||
} |
|
||||
|
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) |
|
||||
{ |
|
||||
return MemberSelector.Parse((string)value); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,48 +0,0 @@ |
|||||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
||||
|
|
||||
using Avalonia.Controls.Templates; |
|
||||
using Avalonia.Data; |
|
||||
using Avalonia.Data.Core; |
|
||||
using Avalonia.Markup.Parsers; |
|
||||
using System; |
|
||||
using System.Reactive.Linq; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.Templates |
|
||||
{ |
|
||||
public class MemberSelector : IMemberSelector |
|
||||
{ |
|
||||
private string _memberName; |
|
||||
|
|
||||
public string MemberName |
|
||||
{ |
|
||||
get { return _memberName; } |
|
||||
set |
|
||||
{ |
|
||||
if (_memberName != value) |
|
||||
{ |
|
||||
_memberName = value; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static MemberSelector Parse(string s) |
|
||||
{ |
|
||||
return new MemberSelector { MemberName = s }; |
|
||||
} |
|
||||
|
|
||||
public object Select(object o) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(MemberName)) |
|
||||
{ |
|
||||
return o; |
|
||||
} |
|
||||
|
|
||||
var expression = ExpressionObserverBuilder.Build(o, MemberName); |
|
||||
object result = AvaloniaProperty.UnsetValue; |
|
||||
|
|
||||
expression.Subscribe(x => result = x); |
|
||||
return (result == AvaloniaProperty.UnsetValue || result is BindingNotification) ? null : result; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,55 +0,0 @@ |
|||||
using Avalonia.Markup.Xaml.Templates; |
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Text; |
|
||||
using System.Threading.Tasks; |
|
||||
using JetBrains.dotMemoryUnit; |
|
||||
using Xunit; |
|
||||
using Xunit.Abstractions; |
|
||||
|
|
||||
namespace Avalonia.LeakTests |
|
||||
{ |
|
||||
[DotMemoryUnit(FailIfRunWithoutSupport = false)] |
|
||||
public class MemberSelectorTests |
|
||||
{ |
|
||||
public MemberSelectorTests(ITestOutputHelper atr) |
|
||||
{ |
|
||||
DotMemoryUnitTestOutput.SetOutputMethod(atr.WriteLine); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Not_Hold_Reference_To_Object() |
|
||||
{ |
|
||||
WeakReference dataRef = null; |
|
||||
|
|
||||
var selector = new MemberSelector() { MemberName = "Child.StringValue" }; |
|
||||
|
|
||||
Action run = () => |
|
||||
{ |
|
||||
var data = new Item() |
|
||||
{ |
|
||||
Child = new Item() { StringValue = "Value1" } |
|
||||
}; |
|
||||
|
|
||||
Assert.Same("Value1", selector.Select(data)); |
|
||||
|
|
||||
dataRef = new WeakReference(data); |
|
||||
}; |
|
||||
|
|
||||
run(); |
|
||||
|
|
||||
GC.Collect(); |
|
||||
|
|
||||
Assert.False(dataRef.IsAlive); |
|
||||
} |
|
||||
|
|
||||
private class Item |
|
||||
{ |
|
||||
public Item Child { get; set; } |
|
||||
public int IntValue { get; set; } |
|
||||
|
|
||||
public string StringValue { get; set; } |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,159 +0,0 @@ |
|||||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
||||
|
|
||||
using Avalonia.Markup.Xaml.Templates; |
|
||||
using System; |
|
||||
using Xunit; |
|
||||
|
|
||||
namespace Avalonia.Markup.Xaml.UnitTests.Templates |
|
||||
{ |
|
||||
public class MemberSelectorTests |
|
||||
{ |
|
||||
[Fact] |
|
||||
public void Should_Select_Child_Property_Value() |
|
||||
{ |
|
||||
var selector = new MemberSelector() { MemberName = "Child.StringValue" }; |
|
||||
|
|
||||
var data = new Item() |
|
||||
{ |
|
||||
Child = new Item() { StringValue = "Value1" } |
|
||||
}; |
|
||||
|
|
||||
Assert.Same("Value1", selector.Select(data)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Select_Child_Property_Value_In_Multiple_Items() |
|
||||
{ |
|
||||
var selector = new MemberSelector() { MemberName = "Child.StringValue" }; |
|
||||
|
|
||||
var data = new Item[] |
|
||||
{ |
|
||||
new Item() { Child = new Item() { StringValue = "Value1" } }, |
|
||||
new Item() { Child = new Item() { StringValue = "Value2" } }, |
|
||||
new Item() { Child = new Item() { StringValue = "Value3" } } |
|
||||
}; |
|
||||
|
|
||||
Assert.Same("Value1", selector.Select(data[0])); |
|
||||
Assert.Same("Value2", selector.Select(data[1])); |
|
||||
Assert.Same("Value3", selector.Select(data[2])); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Select_MoreComplex_Property_Value() |
|
||||
{ |
|
||||
var selector = new MemberSelector() { MemberName = "Child.Child.Child.StringValue" }; |
|
||||
|
|
||||
var data = new Item() |
|
||||
{ |
|
||||
Child = new Item() |
|
||||
{ |
|
||||
Child = new Item() |
|
||||
{ |
|
||||
Child = new Item() { StringValue = "Value1" } |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
Assert.Same("Value1", selector.Select(data)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Select_Null_Value_On_Null_Object() |
|
||||
{ |
|
||||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|
||||
|
|
||||
Assert.Null(selector.Select(null)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Select_Null_Value_On_Wrong_MemberName() |
|
||||
{ |
|
||||
var selector = new MemberSelector() { MemberName = "WrongProperty" }; |
|
||||
|
|
||||
var data = new Item() { StringValue = "Value1" }; |
|
||||
|
|
||||
Assert.Null(selector.Select(data)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Select_Simple_Property_Value() |
|
||||
{ |
|
||||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|
||||
|
|
||||
var data = new Item() { StringValue = "Value1" }; |
|
||||
|
|
||||
Assert.Same("Value1", selector.Select(data)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Select_Simple_Property_Value_In_Multiple_Items() |
|
||||
{ |
|
||||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|
||||
|
|
||||
var data = new Item[] |
|
||||
{ |
|
||||
new Item() { StringValue = "Value1" }, |
|
||||
new Item() { StringValue = "Value2" }, |
|
||||
new Item() { StringValue = "Value3" } |
|
||||
}; |
|
||||
|
|
||||
Assert.Same("Value1", selector.Select(data[0])); |
|
||||
Assert.Same("Value2", selector.Select(data[1])); |
|
||||
Assert.Same("Value3", selector.Select(data[2])); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Select_Target_On_Empty_MemberName() |
|
||||
{ |
|
||||
var selector = new MemberSelector(); |
|
||||
|
|
||||
var data = new Item() { StringValue = "Value1" }; |
|
||||
|
|
||||
Assert.Same(data, selector.Select(data)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Support_Change_Of_MemberName() |
|
||||
{ |
|
||||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|
||||
|
|
||||
var data = new Item() |
|
||||
{ |
|
||||
StringValue = "Value1", |
|
||||
IntValue = 1 |
|
||||
}; |
|
||||
|
|
||||
Assert.Same("Value1", selector.Select(data)); |
|
||||
|
|
||||
selector.MemberName = "IntValue"; |
|
||||
|
|
||||
Assert.Equal(1, selector.Select(data)); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public void Should_Support_Change_Of_Target_Value() |
|
||||
{ |
|
||||
var selector = new MemberSelector() { MemberName = "StringValue" }; |
|
||||
|
|
||||
var data = new Item() |
|
||||
{ |
|
||||
StringValue = "Value1" |
|
||||
}; |
|
||||
|
|
||||
Assert.Same("Value1", selector.Select(data)); |
|
||||
|
|
||||
data.StringValue = "Value2"; |
|
||||
|
|
||||
Assert.Same("Value2", selector.Select(data)); |
|
||||
} |
|
||||
|
|
||||
private class Item |
|
||||
{ |
|
||||
public Item Child { get; set; } |
|
||||
public int IntValue { get; set; } |
|
||||
|
|
||||
public string StringValue { get; set; } |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue