7 changed files with 355 additions and 7 deletions
@ -0,0 +1,72 @@ |
|||||
|
// 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.Reactive.Linq; |
||||
|
|
||||
|
namespace Avalonia.Styling |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The `:not()` style selector.
|
||||
|
/// </summary>
|
||||
|
internal class NotSelector : Selector |
||||
|
{ |
||||
|
private readonly Selector _previous; |
||||
|
private readonly Selector _argument; |
||||
|
private string _selectorString; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="NotSelector"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="previous">The previous selector.</param>
|
||||
|
/// <param name="argument">The selector to be not-ed.</param>
|
||||
|
public NotSelector(Selector previous, Selector argument) |
||||
|
{ |
||||
|
_previous = previous; |
||||
|
_argument = argument ?? throw new InvalidOperationException("Not selector must have a selector argument."); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override bool InTemplate => _argument.InTemplate; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override bool IsCombinator => false; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override Type TargetType => _previous?.TargetType; |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override string ToString() |
||||
|
{ |
||||
|
if (_selectorString == null) |
||||
|
{ |
||||
|
_selectorString = ":not(" + _argument.ToString() + ")"; |
||||
|
} |
||||
|
|
||||
|
return _selectorString; |
||||
|
} |
||||
|
|
||||
|
protected override SelectorMatch Evaluate(IStyleable control, bool subscribe) |
||||
|
{ |
||||
|
var innerResult = _argument.Match(control, subscribe); |
||||
|
|
||||
|
switch (innerResult.Result) |
||||
|
{ |
||||
|
case SelectorMatchResult.AlwaysThisInstance: |
||||
|
return SelectorMatch.NeverThisInstance; |
||||
|
case SelectorMatchResult.AlwaysThisType: |
||||
|
return SelectorMatch.NeverThisType; |
||||
|
case SelectorMatchResult.NeverThisInstance: |
||||
|
return SelectorMatch.AlwaysThisInstance; |
||||
|
case SelectorMatchResult.NeverThisType: |
||||
|
return SelectorMatch.AlwaysThisType; |
||||
|
case SelectorMatchResult.Sometimes: |
||||
|
return new SelectorMatch(innerResult.Activator.Select(x => !x)); |
||||
|
default: |
||||
|
throw new InvalidOperationException("Invalid SelectorMatchResult."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override Selector MovePrevious() => _previous; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,114 @@ |
|||||
|
// 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.Reactive.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Avalonia.Controls; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Avalonia.Styling.UnitTests |
||||
|
{ |
||||
|
public class SelectorTests_Not |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Not_Selector_Should_Have_Correct_String_Representation() |
||||
|
{ |
||||
|
var target = default(Selector).Not(x => x.Class("foo")); |
||||
|
|
||||
|
Assert.Equal(":not(.foo)", target.ToString()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Not_OfType_Matches_Control_Of_Incorrect_Type() |
||||
|
{ |
||||
|
var control = new Control1(); |
||||
|
var target = default(Selector).Not(x => x.OfType<Control1>()); |
||||
|
|
||||
|
Assert.Equal(SelectorMatchResult.NeverThisType, target.Match(control).Result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Not_OfType_Doesnt_Match_Control_Of_Correct_Type() |
||||
|
{ |
||||
|
var control = new Control2(); |
||||
|
var target = default(Selector).Not(x => x.OfType<Control1>()); |
||||
|
|
||||
|
Assert.Equal(SelectorMatchResult.AlwaysThisType, target.Match(control).Result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Not_Class_Doesnt_Match_Control_With_Class() |
||||
|
{ |
||||
|
var control = new Control1 |
||||
|
{ |
||||
|
Classes = new Classes { "foo" }, |
||||
|
}; |
||||
|
|
||||
|
var target = default(Selector).Not(x => x.Class("foo")); |
||||
|
var match = target.Match(control); |
||||
|
|
||||
|
Assert.Equal(SelectorMatchResult.Sometimes, match.Result); |
||||
|
Assert.False(await match.Activator.Take(1)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Not_Class_Matches_Control_Without_Class() |
||||
|
{ |
||||
|
var control = new Control1 |
||||
|
{ |
||||
|
Classes = new Classes { "bar" }, |
||||
|
}; |
||||
|
|
||||
|
var target = default(Selector).Not(x => x.Class("foo")); |
||||
|
var match = target.Match(control); |
||||
|
|
||||
|
Assert.Equal(SelectorMatchResult.Sometimes, match.Result); |
||||
|
Assert.True(await match.Activator.Take(1)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task OfType_Not_Class_Matches_Control_Without_Class() |
||||
|
{ |
||||
|
var control = new Control1 |
||||
|
{ |
||||
|
Classes = new Classes { "bar" }, |
||||
|
}; |
||||
|
|
||||
|
var target = default(Selector).OfType<Control1>().Not(x => x.Class("foo")); |
||||
|
var match = target.Match(control); |
||||
|
|
||||
|
Assert.Equal(SelectorMatchResult.Sometimes, match.Result); |
||||
|
Assert.True(await match.Activator.Take(1)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void OfType_Not_Class_Doesnt_Match_Control_Of_Wrong_Type() |
||||
|
{ |
||||
|
var control = new Control2 |
||||
|
{ |
||||
|
Classes = new Classes { "foo" }, |
||||
|
}; |
||||
|
|
||||
|
var target = default(Selector).OfType<Control1>().Not(x => x.Class("foo")); |
||||
|
var match = target.Match(control); |
||||
|
|
||||
|
Assert.Equal(SelectorMatchResult.NeverThisType, match.Result); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Returns_Correct_TargetType() |
||||
|
{ |
||||
|
var target = default(Selector).OfType<Control1>().Not(x => x.Class("foo")); |
||||
|
|
||||
|
Assert.Equal(typeof(Control1), target.TargetType); |
||||
|
} |
||||
|
|
||||
|
public class Control1 : TestControlBase |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public class Control2 : TestControlBase |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue