我注意到在使用ReactiveUI的.NET 3.5应用程序中,我有一个显着的内存泄漏,似乎源自ObservableAsPropertyHelper.我创建了一个测试项目来证明它在这里.
似乎由简单的ObservableAsPropertyHelper计算属性触发的每个更改通知都会泄漏内存.泄漏似乎源于Reactive Extensions,而不是直接在ReactiveUI中,但我对OAPH的使用非常简单,我想知道是否有人遇到过这个或者可能有一个建议的修复.
内存泄漏的严重程度在.NET 3.5(RxUI 2.4,Rx 1.1)和.NET 4.0(RxUI 4.2,Rx 2.0.3)之间变化.它与.NET 3.5中每次更新属性更接近线性.但是,.NET 4.0中仍然存在漏洞.
我已经在这里使用测试应用程序上传了我的.NET 3.5和.NET 4.0测试会话的测试项目和一些探查器图像.
你可以在图像中看到对象图是不同的,所以我们可能完全在谈论两个不同的泄漏.在4.0会话(40_RetentionGraph.png)中,您可以看到分配最多的对象是Ints(我的OAPH属性的类型)和ConcurrentQueue.那里似乎有某种循环引用问题.您还可以在40_IntsAllocatedGCRootGrows.png中看到实例的GC根距离的增长.
在3.5版本(我最关心的)中,您可以看到(35_Summary.png)分配最多的对象是Action和ScheduledObserver.对象图比40版更复杂,完全不同.
我已经回顾了这个讨论,但还没有找到一个直接的答案:我的方案是,对OAPH进行非常简单的更新.任何有关这种泄漏的可能解决方案的见解都表示赞
我有一个observable,我用它来显示一个确认对话框,大致是签名:
IObservable<DialogResult> ShowDialog(string title, string message);
Run Code Online (Sandbox Code Playgroud)
这向用户显示了对话框,带有是/否按钮组合.
在我的主窗口中,我正在访问结束事件:
this.Events().Closing.[Do something here]
Run Code Online (Sandbox Code Playgroud)
我希望能够:
CancelEventArgs.Cancel如果用户单击"否"按钮,则将该属性设置为true.我试过直接订阅:
this.Events().Closing.Subscribe(e =>
{
var res = Dialogs.ShowDialog("Close?", "Really Close?").Wait();
e.Cancel = res == DialogResult.Ok;
});
Run Code Online (Sandbox Code Playgroud)
但是因为这个Wait()电话而挂起,我也尝试过异步变种:
this.Events().Closing.Subscribe(async e =>
{
var res = await Dialogs.ShowDialog("Close?", "Really Close?");
e.Cancel = res == DialogResult.Ok;
});
Run Code Online (Sandbox Code Playgroud)
哪个不好,因为它马上就会回来.
我真正想要做的是:
this.Events().Closing.ThenDo(_ => Dialogs.ShowDialog("Close?", "Really Close?"))
.Subscribe((cancelEventArgs, dialogResult) =>
{
cancelEventArgs.Cancel == dialogResult == DialogResult.Ok;
});
Run Code Online (Sandbox Code Playgroud)
但这不存在,我知道这里的关键在于我如何组合这两个可观察量,但我不知道如何这样做,而且文档对实际例子有点了解.
我想出了一种使用ReactiveUI在树视图内动态绑定用户控件的方法。
但是... 到HierachicalDataSource的顶级绑定是在XAML中,而不是在后面的代码,我需要直接设置ItemsSource而不使用this.OneWayBind。
因此,我的问题是:我是否错过了ReactiveUI框架中的某些东西,该东西会让我与this.OneWayBind绑定,并将HierachicalDataTemplete移入代码或自定义用户控件中?
特别是-OneWayBind是否有另一个支持层次结构数据模板的重载,或者是一种抑制使用时调用的数据模板生成的方法?
更新 我已经在我的测试项目中添加了选定的项目以及对Expand和Selected的编程支持,但是我不得不向XAML添加样式。我也想用一个简单的RxUI Bind替换它。更新了示例。
以下是关键细节:
主视图中的树控件
<TreeView Name="FamilyTree" >
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
</Style>
<HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Children}">
<reactiveUi:ViewModelViewHost ViewModel="{Binding ViewModel}"/>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
Run Code Online (Sandbox Code Playgroud)
后面的主视图代码
public partial class MainWindow : Window, IViewFor<MainVM>
{
public MainWindow()
{
InitializeComponent();
//build viewmodel
ViewModel = new MainVM();
//Register views
Locator.CurrentMutable.Register(() => new PersonView(), typeof(IViewFor<Person>));
Locator.CurrentMutable.Register(() => new PetView(), typeof(IViewFor<Pet>));
//NB. ! Do not use 'this.OneWayBind ... ' …Run Code Online (Sandbox Code Playgroud) 我的应用程序使用实现IViewFor<T>界面的视图.视图已在依赖项解析程序中注册AppBootstrapper.应用程序ViewModelViewHost通过为控件的ViewModel属性分配相应的视图模型来使用控件显示视图.所有视图模型都实现了ISupportsActivation接口.
我注意到它WhenActivated被叫了两次.首先,当视图和视图模型被激活时调用它.然后在停用时,处理所有一次性用品并WhenActivated立即再次调用,然后处理一次性用品.
我在视图和视图模型中使用以下代码进行测试:
this.WhenActivated(disposables =>
{
Debug.WriteLine("ViewModel activated.");
Disposable
.Create(() =>
{
Debug.WriteLine("ViewModel deactivated.");
})
.AddTo(disposables);
});
Run Code Online (Sandbox Code Playgroud)
结果输出如下:
// App displays the view:
ViewModel activated.
View activated.
// App hides the view:
ViewModel deactivated.
View deactivated.
ViewModel activated.
View activated.
ViewModel deactivated.
View deactivated.
Run Code Online (Sandbox Code Playgroud)
通过将ViewModelViewHost控件的ViewModel属性设置为null来隐藏视图.
难道我做错了什么?
编辑:这是完整的源代码:https://gist.github.com/dmakaroff/e7d84e06e0a48d7f5298eb6b7d6187d0
按第一个Show然后按Hide按钮将产生以下输出:
SubViewModel activated.
SubView activated.
SubViewModel deactivated.
SubView deactivated.
SubViewModel activated.
SubView activated.
SubViewModel deactivated. …Run Code Online (Sandbox Code Playgroud) 我已经看到一些关于使用Observables而不是使用async/await的任务的讨论.我目前几乎只使用CreateFromTask.我一直试图理解使用CreateFromObservable而不是CreateFromTask的原因.
如果是这样,那么将CreateFromTask转换为CreateFromObservable的最佳方法是什么.
我有一个带有.Net Standard 1.4核心库的Xamarin Forms项目,它包含所有代码.我在核心和iOS项目中都引用了ReactiveUI 7.4.但是当我在iOS模拟器上编译并运行时,我在应用程序启动时收到以下错误:
2017-08-24 13:39:39.040 TestProject.iOS[25074:307385] Could not register the assembly 'ReactiveUI': System.Reflection.ReflectionTypeLoadException: The classes in the module cannot be loaded.
at (wrapper managed-to-native) System.Reflection.Assembly:GetTypes (System.Reflection.Assembly,bool)
at System.Reflection.Assembly.GetTypes () [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/10.12.0.20/src/mono/mcs/class/corlib/System.Reflection/Assembly.cs:410
at Registrar.DynamicRegistrar.CollectTypes (System.Reflection.Assembly assembly) [0x00000] in /Users/builder/data/lanes/4991/80b8487d/source/xamarin-macios/src/ObjCRuntime/DynamicRegistrar.cs:237
at Registrar.Registrar.RegisterAssembly (System.Reflection.Assembly assembly) [0x00056] in /Users/builder/data/lanes/4991/80b8487d/source/xamarin-macios/src/ObjCRuntime/Registrar.cs:1978
Loaded assembly: /Library/Frameworks/Xamarin.Interactive.framework/Versions/Current/Agents/iOS/Xamarin.Interactive.iOS.dll [External]
Loaded assembly: /Library/Frameworks/Xamarin.Interactive.framework/Versions/Current/Agents/iOS/Xamarin.Interactive.dll [External]
Unhandled Exception:
System.BadImageFormatException: <Timeout exceeded getting exception details>
Run Code Online (Sandbox Code Playgroud)
和
Unhandled Exception:
System.BadImageFormatException: Could not resolve field token 0x040000fd
File name: 'ReactiveUI'
at TestProject.iOS.AppDelegate..ctor () …Run Code Online (Sandbox Code Playgroud) 我将UserControl更改为ReactiveUserControl,现在我无法查看设计视图.有什么办法可以让设计师使用ReactiveUserControl吗?
我在 ReactiveUI 的学习曲线上苦苦挣扎,所以这个问题可能很幼稚。请帮助我理解以下之间的区别:
ObservableAsPropertyHelper<string> _input
public string Input {get {return _input.Value;}}
Run Code Online (Sandbox Code Playgroud)
和一个普通的支持变量 RaiseAndSetIfChanged:
private string _input;
public string Input {
get {return _input;}
set {RaiseAndSetIfChanged(ref _input, value);}
}
Run Code Online (Sandbox Code Playgroud)
它们是给同一只猫剥皮的两种方法,还是两种选择有不同的用例/意图?
更新:查看底部的示例
我需要在课间发消息。发布者将无限循环,调用一些方法来获取数据,然后将该调用的结果传递给OnNext. 可以有很多订阅者,但应该只有一个 IObservable 和一个长期运行的任务。这是一个实现。
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Diagnostics;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
namespace UnitTestProject1
{
[TestClass]
public class UnitTest1
{
private static string GetSomeData() => "Hi";
[TestMethod]
public async Task RunMessagingAsync()
{
var subject = new Subject<string>();
//Create a class and inject the subject as IObserver
new Publisher(subject);
//Create a class and inject the subject as IObservable
new Subscriber(subject, 1.ToString());
new Subscriber(subject, 2.ToString());
new Subscriber(subject, 3.ToString());
//Run the loop for 3 seconds
await …Run Code Online (Sandbox Code Playgroud) c# publish-subscribe reactive-programming system.reactive reactiveui
我正在尝试将 ReactiveUI 与 Avalonia 一起使用。由于 Avalonia 0.10 预览版中的初始化顺序,以下代码失败:
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;
}
Run Code Online (Sandbox Code Playgroud)
因为WhenActivated在视图绑定到 viewModel 之后调用(因此 _myProperty 为 null)。
我认为没有简单的解决方法需要大量的修改、手动提高属性等等。
所以问题是:
如何在 Avalonia 中使用 OAPH 和 WhenActivated?
reactiveui ×10
c# ×6
wpf ×4
.net ×2
avalonia ×1
avaloniaui ×1
data-binding ×1
memory-leaks ×1
mvvm ×1
properties ×1
treeview ×1
xamarin ×1
xamarin.ios ×1
xaml ×1