我有一个RuleCondition<TValue>
班:
public class RuleCondition<TValue>
{
public string PropertyToCheck { get; private set; }
public TValue Value { get; private set; }
public RuleCondition(string propertyToCheck, TValue value)
{
PropertyToCheck = propertyToCheck;
Value = value;
}
}
在Rule<T>
类中,我有一个包含它的实例的字段:
public abstract class Rule<T>
{
private readonly string mPropertyName;
private readonly object mError;
private readonly RuleCondition<TValue> mCondition;
protected Rule(string propertyName, object error, RuleCondition<TValue> condition)
{
mCondition = condition;
}
// ...
}
现在我想将我的RuleCondition<T>
添加到Rule
(继承自Collection<Rule<T>>
的{{1}}和DelegateRule<T>
的继承人)中
Rule<T>
我收到一个错误,指出类型不匹配,这是正确的。我现在的问题是:如何获得Rules.Add(new DelegateRule<ConnectionSettingsViewModel>(nameof(Username),
"Username: Cannot be empty, starting with a space or a backslash.",
x => !string.IsNullOrWhiteSpace(x.Username),
new RuleCondition<LoginOptions>(nameof(LoginUsage), LoginOptions.Instrument)));
的{{1}},而不必在“ top”中声明它并破坏我的所有代码。只是为了在TValue
类中获得约束而在各处声明约束是不对的。
有没有更简单的方法?我想念什么?
编辑:RuleCondition
已经是RuleCondition<TValue>
类型。
我认为我必须添加更多解释:
“链”从此处开始:
T
如果现在像*ViewModel
那样将public class ConnectionSettingsViewModel : NotifyDataErrorInfo<ConnectionSettingsViewModel>
{ }
约束添加到TValue
类,则还需要将该约束提供给Rule
类。因此,进入“顶级”类别。但这感觉不对。在Rule<T, TValue>
和“最后一个”类NotifyDataErrorInfo
之间的每个类中声明该约束。
编辑2:
我从here中获取了代码,以对我的MVVM应用程序实施控件验证。但是我认为我需要满足一些控制条件。因此,规则不会每次都“执行”,而只是在特定的NotifyDataErrorInfo
例如被选中。
答案 0 :(得分:1)
根据您的输入和该博客文章,您可以执行类似的操作。考虑到您需要稍微修改该博客中提供的类。
首先,您可以创建ConditionalRule<T, TValue>
来继承DelegateRule<T>
(或您想要的任何其他Rule<T>
)。 为此,您需要取消密封DelegateRule
类
public class ConditionalRule<T, TValue> : DelegateRule<T>
{
public TValue Value { get; private set; }
public ConditionalRule(string propertyName, object error, Func<T, bool> rule, TValue value)
: base(propertyName, error, rule)
{
Value = value;
}
public override bool Apply(T obj)
{
// do your business driven condition check before calling
return base.Apply(obj);
}
}
第二,您必须使用其他通用方法扩展RuleCollection<T>
:
public sealed class RuleCollection<T> : Collection<Rule<T>>
{
#region Public Methods
/// <summary>
/// Adds a new <see cref="Rule{T}"/> to this instance.
/// </summary>
/// <param name="propertyName">The name of the property the rules applies to.</param>
/// <param name="error">The error if the object does not satisfy the rule.</param>
/// <param name="rule">The rule to execute.</param>
public void Add(string propertyName, object error, Func<T, bool> rule)
{
this.Add(new DelegateRule<T>(propertyName, error, rule));
}
public void AddConditional<TValue>(string propertyName, object error, Func<T, bool> rule, TValue value)
{
this.Add(new ConditionalRule<T, TValue>(propertyName, error, rule, value)
}
//....
#endregion
}
此外,您需要修改代码,以便将规则添加到集合中,具体取决于要添加的规则:
Rules.AddConditional<LoginOptions>(
new ConditionalRule<ConnectionSettingsViewModel, LoginOptions>(
nameof(Username),
"Username: Cannot be empty, starting with a space or a backslash.",
x => !string.IsNullOrWhiteSpace(x.Username),
LoginOptions.Instrument
)
);
请注意,我没有检查代码,因此您可能会遇到一些编译时问题,但是通常的想法是使用继承从Rule<T>
中创建特定规则。这样,每个规则都将很好地适合RuleCollection<T>