C# 如何在avalonia中的属性激活时使用
我正在尝试与Avalonia一起使用ReactiveUI。由于Avalonia 0.10预览中的初始化顺序,以下代码失败:C# 如何在avalonia中的属性激活时使用,c#,reactiveui,avaloniaui,avalonia,C#,Reactiveui,Avaloniaui,Avalonia,我正在尝试与Avalonia一起使用ReactiveUI。由于Avalonia 0.10预览中的初始化顺序,以下代码失败: class ViewModel : IActivatableViewModel { public ViewModel(){ this.WhenActivated(disposables => { _myProperty = observable.ToProperty(this, nameof(MyProperty)).D
class ViewModel : IActivatableViewModel
{
public ViewModel(){
this.WhenActivated(disposables => {
_myProperty = observable.ToProperty(this, nameof(MyProperty)).DisposeWith(disposables).
});
}
private ObservableAsPropertyHelper<object> _myProperty = null!;
public object MyProperty => _myProperty.Value;
}
class-ViewModel:IActivatableViewModel
{
公共视图模型(){
此。当激活时(一次性=>{
_myProperty=observable.ToProperty(此名称为(myProperty)).DisposeWith(可处置)。
});
}
私有ObservablesPropertyHelper_myProperty=null!;
公共对象MyProperty=>\u MyProperty.Value;
}
因为在视图绑定到viewModel之后调用了WhenActivated(因此_myProperty为null)
我认为没有简单的解决方法需要大量的黑客,手动提高属性等等
因此,问题是:
如何与OAPH合作以及何时在Avalonia开展活动?选项#1
允许您解决此问题的最明显模式是使用null合并运算符。通过使用此运算符,您可以通过调整代码使其看起来有点像这样来实现所需的行为:
private ObservablesPropertyHelper_我的财产;
公共TValue MyProperty=>\u MyProperty?.Value;
在这里,我们使用新的C#nullable注释将声明的字段显式标记为可空。我们这样做是因为在调用WhenActivated
块之前,\u myProperty
字段设置为null
。此外,我们在这里使用\u myProperty?.Value
语法,因为当视图模型未初始化时,myProperty
getter应该返回null
选项2
肯定更好的另一个选项是在激活时将TopProperty
订阅移到块之外,并将ObservablesPropertyHelper
字段标记为只读
。如果您的计算属性未订阅比视图模型更有效的外部服务,则无需处理由TopProperty
返回的订阅。在90%的情况下,当启动时,您不需要将ToProperty
调用保留在中。有关更多信息,请参阅文档页面。另请参阅这篇文章,这篇文章也可以为这个主题提供一些启示。因此,在90%的情况下,编写这样的代码是一种很好的方法:
private readonly ObservableAsPropertyHelper\u myProperty;
公共TValue MyProperty=>\u MyProperty.Value;
//在视图模型构造函数中:
_myProperty=obs.ToProperty(这个,x=>x.myProperty);
如果您实际订阅外部服务,例如通过构造函数注入视图模型,则可以使用私有setter将MyProperty
转换为读写属性,并编写以下代码:
class-ViewModel:IActivatableViewModel
{
公共视图模型(IDependency依赖)
{
此。当激活时(一次性=>
{
//我们现在使用的是“DisposeWith”
//订阅一个外部依赖项
//可能比视图模型更长寿。所以
//我们需要按顺序处理订阅
//以避免内存泄漏的可能性。
附属国
.外部可观察
.Subscribe(value=>MyProperty=value)
.一次性使用(一次性使用);
});
}
私人TValue_myProperty;
公共TValue MyProperty
{
get=>\u myProperty;
private set=>this.RaiseAndSetIfChanged(ref\u myProperty,value);
}
}
另外,看看RaiseAndSetIfChanged
语法是否让您觉得太冗长
选项#3(我推荐这个选项)
值得注意的是,Avalonia支持。这是一个非常有用的功能,我强烈建议您尝试一下。这意味着,在Avalonia中,您可以简单地将计算属性声明为IObservable
,Avalonia将为您管理订阅的生存期。因此,在视图模型中,请执行以下操作:
class-ViewModel:IActivatableViewModel
{
公共视图模型()
{
我的财产=
此.whenyValue(x=>x.AnotherProperty)
.Select(value=>$“您好,{value}!”);
}
公共IObservable MyProperty{get;}
//为简洁起见省略了几行
}
在视图中,编写以下代码:
OAPHs是为无法实现这些技巧的平台而发明的,但Avalonia非常擅长巧妙的标记扩展。因此,如果您针对多个UI框架并编写与框架无关的视图模型,那么OAPH是一个不错的选择。但是如果您只针对Avalonia,那么只需使用{Binding^}
选项4
或者,如果您愿意使用,请将选项3中的视图模型代码与xaml.cs
文件中视图侧的以下代码组合在一起:
this.WhenActivated(cleanup=>{
此.whenObservable(x=>x.ViewModel.MyProperty)
.BindTo(这个,x=>x.NamedTextBox.Text)
.处置(清理);
});
这里我们假设xaml
文件如下所示:
我们现在有了一个可能有助于生成x:Name
references顺便说一句。感谢您的详细回答!选项1很糟糕,完全违背了做有趣事情的目的。选项2有点没用,因为它都是关于外部依赖的。选项#3很棒,但为什么我必须使用^
?看起来很奇怪,^符号只是一种Avalonia标记扩展语法,允许将控件绑定到任务和可观察对象。它允许我们告诉Avalonia,我们绑定到的值是一个任务
或IObservable
,绑定应该有不同的行为,并跟踪他们称之为“流绑定操作符”的订阅,但这难道不是默认行为吗?如果观察到某事