Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/292.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果可以更改VisualParent,如何在UserControl中处理订阅_C#_Wpf_Dispose_Subscription - Fatal编程技术网

C# 如果可以更改VisualParent,如何在UserControl中处理订阅

C# 如果可以更改VisualParent,如何在UserControl中处理订阅,c#,wpf,dispose,subscription,C#,Wpf,Dispose,Subscription,我有一个FooUserControl,它订阅它的LoadedEvent。此UserControl可以放置在gui上的其他位置(在任何窗口上或任何控件内部)。为了避免泄漏,我实施了某种处理 此解决方案的问题: 如果将FooUserControl放在TabControl的TabItem上并更改选项卡,则调用OnVisualParentChanged()并释放订阅。如果我不添加此方法,而您关闭选项卡项,则订阅在后台仍然有效,尽管可以释放用户控件。页面 公共类FooUserControl:UserCon

我有一个
FooUserControl
,它订阅它的
LoadedEvent
。此
UserControl
可以放置在gui上的其他位置(在任何
窗口上或任何
控件内部)。为了避免泄漏,我实施了某种处理

此解决方案的问题:

如果将
FooUserControl
放在
TabControl
TabItem
上并更改选项卡,则调用
OnVisualParentChanged()
并释放订阅。如果我不添加此方法,而您关闭
选项卡项
,则订阅在后台仍然有效,尽管可以释放
用户控件
页面

公共类FooUserControl:UserControl
{
私人IDisposable_订阅;
公共FooUserControl()
{
已加载+=\u已加载;
}
私有void _onload(对象发送方,RoutedEventArgs e)
{
//避免多次订阅
已加载-=\u已加载;
//将钩子添加到父窗口以处置订阅
var parentWindow=Window.GetWindow(此);
if(parentWindow!=null)
parentWindow.Closed+=\u ParentWindowOnClosed;
_Subscription=MyObservableInstance.Subscribe(…);
}
私有void\u ParentWindowOnClosed(对象?发送方,事件参数e)
{
_处置();
}
//检查父视图是否已更改
//如果使用页上的控件,可能会发生这种情况
VisualParentChanged上受保护的覆盖无效(DependencyObject oldParent)
{
如果(oldParent!=null)
{
_处置();
}
base.OnVisualParentChanged(旧父级);
}
私有void_Dispose()
{
_订阅?.Dispose();
}
}

我终于找到了解决办法。在
unload
事件中,我扫描
Logical/VisualTree
是否仍然存在实例

由于
wpf
中没有真正的
处理
机制,所以我采用了这个解决方案。我愿意找到更好的解决方案

FooUserControl

公共类FooUserControl:UserControl
{
私人IDisposable_订阅;
私人窗口(ParentWindow);;
公共FooUserControl()
{
已加载+=\u已加载;
卸载+=\u未加载;
}
私有void _onload(对象发送方,RoutedEventArgs e)
{
//避免多次订阅
已加载-=\u已加载;
//将钩子添加到父窗口以处置订阅
_ParentWindow=Window.GetWindow(此);
_ParentWindow.Closed+=\u ParentWindowOnClosed;
_Subscription=MyObservableInstance.Subscribe(…);
}
私有void\u OnUnloaded(对象发送方,路由目标)
{
//如果控件已被删除,请查看逻辑和可视树
if(_ParentWindow.FindChildById(Uid)==null)
{
_处置();
}
}
私有void\u ParentWindowOnClosed(对象?发送方,事件参数e)
{
_处置();
}
私有void_Dispose()
{
_订阅?.Dispose();
}
}
DependencyObjectExtensions

公共静态类DependencyObjectExtensions
{
/// 
///分析可视树和逻辑树,以查找给定对象的所有元素
///是该项的后代的类型。
/// 
///查询项目的类型。
///标记搜索源的根元素。如果
///源已经是请求的类型,它将不包括在结果中。
///系统的UID
///与请求的类型匹配的所有子体。
公共静态T FindChildById(此DependencyObject源,字符串uid),其中T:UIElement
{
如果(源!=null)
{
var childs=GetChildObjects(源);
foreach(子对象中的DependencyObject子对象)
{
//分析子项是否与请求的类型匹配
如果(child!=null&&child是T dependencyObject&&dependencyObject.Uid.Equals(Uid))
{
返回dependencyObject;
}
var后代=FindChildByUid(子对象,uid);
if(后代!=null)
返回后代;
}
}
返回null;
}
/// 
///此方法是WPF的替代方法
///方法,其中
///支持内容元素。请记住,对于内容元素,
///此方法返回到元素的逻辑树。
/// 
///要处理的项目。
///已提交项目的子元素(如果可用)。
公共静态IEnumerable GetChildObjects(此DependencyObject父对象)
{
如果(父项==null)产量中断;
if(父元素为ContentElement | |父元素为FrameworkElement)
{
//对内容/框架元素使用逻辑树
foreach(LogicalTreeHelper.GetChildren(父)中的对象obj)
{
var depObj=obj作为DependencyObject;
如果(depObj!=null)产生返回(DependencyObject)对象;
}
}
其他的
{
//默认情况下使用可视树
int count=VisualTreeHelper.GetChildrenCount(父级);
for(int i=0;i
为什么不订阅选项卡项更改事件并删除此事件中的用户控件?还有,
MyObservableInstance.Subscribe(…)
implementedIt是一个公共nuget包(
NLogViewer
),所以我对它的最终实现一无所知。在订阅中,推送新的日志条目,然后