WPF + PostSharp 的视图模型在一分钟内冻结
WPF + PostSharp’ed View Model get frozen in a minute
已更新(见下文)
WPF 在经过一分钟的密集工作后开始忽略 属性 更改通知。这是要重现的演示(也在 GitHub 上)。查看模型是:
[Aggregatable]
[NotifyPropertyChanged]
[ContentProperty("Tests")]
public class Model
{
[Child] public AdvisableCollection<Test> Tests { get; } = new AdvisableCollection<Test>();
[Child] public Test Test { get; set; }
}
其中:
[Aggregatable]
[NotifyPropertyChanged]
public class Test
{
public string Name { get; set; }
[Parent] public Model Model { get; private set; }
}
XAML:
<Window x:Class="Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Demo"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:Model>
<local:Test Name="a"/>
<local:Test Name="b"/>
<local:Test Name="c"/>
<local:Test Name="d"/>
</local:Model>
</Window.DataContext>
<TextBox DockPanel.Dock="Top" Text="{Binding Test.Name, Mode=OneWay}"/>
</Window>
后面的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Timer = new DispatcherTimer();
Timer.Interval = TimeSpan.FromMilliseconds(250);
Timer.Tick += Timer_Tick;
Timer.Start();
}
DispatcherTimer Timer { get; }
Random Random = new Random();
Model Model => DataContext as Model;
private void Timer_Tick(object sender, EventArgs e)
{
var i = Random.Next(Model.Tests.Count);
Model.Test = Model.Tests[i];
}
}
运行 等待一分钟 – window 会被冻结。
有什么解决办法吗?
更新
我简化了模型 - 这个仍然在一分钟内冻结:
[NotifyPropertyChanged]
[ContentProperty("Tests")]
public class Model
{
public List<Test> Tests { get; } = new List<Test>();
public Test Test { get; set; }
}
[NotifyPropertyChanged]
public class Test
{
public string Name { get; set; }
}
但是Test
class下面的版本解决了问题:
public class Test : INotifyPropertyChanged
{
public string Name { get; set; }
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
看来这个问题是由于NotifyPropertyChanged
方面的弱事件管理器与WPF中的弱事件管理器不兼容造成的。作为解决方法,您可以在将方面应用到目标元素时禁用方面的弱事件实现:
[NotifyPropertyChanged( WeakEventStrategy = WeakEventStrategy.AlwaysStrong )]
[ContentProperty("Tests")]
public class Model
{
// ...
}
[NotifyPropertyChanged( WeakEventStrategy = WeakEventStrategy.AlwaysStrong )]
public class Test
{
// ...
}
我们将继续调查该问题,并在修复发布后更新答案。
编辑:此问题已在 PostSharp 6.0.28 中修复。
已更新(见下文)
WPF 在经过一分钟的密集工作后开始忽略 属性 更改通知。这是要重现的演示(也在 GitHub 上)。查看模型是:
[Aggregatable]
[NotifyPropertyChanged]
[ContentProperty("Tests")]
public class Model
{
[Child] public AdvisableCollection<Test> Tests { get; } = new AdvisableCollection<Test>();
[Child] public Test Test { get; set; }
}
其中:
[Aggregatable]
[NotifyPropertyChanged]
public class Test
{
public string Name { get; set; }
[Parent] public Model Model { get; private set; }
}
XAML:
<Window x:Class="Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Demo"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:Model>
<local:Test Name="a"/>
<local:Test Name="b"/>
<local:Test Name="c"/>
<local:Test Name="d"/>
</local:Model>
</Window.DataContext>
<TextBox DockPanel.Dock="Top" Text="{Binding Test.Name, Mode=OneWay}"/>
</Window>
后面的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Timer = new DispatcherTimer();
Timer.Interval = TimeSpan.FromMilliseconds(250);
Timer.Tick += Timer_Tick;
Timer.Start();
}
DispatcherTimer Timer { get; }
Random Random = new Random();
Model Model => DataContext as Model;
private void Timer_Tick(object sender, EventArgs e)
{
var i = Random.Next(Model.Tests.Count);
Model.Test = Model.Tests[i];
}
}
运行 等待一分钟 – window 会被冻结。 有什么解决办法吗?
更新
我简化了模型 - 这个仍然在一分钟内冻结:
[NotifyPropertyChanged]
[ContentProperty("Tests")]
public class Model
{
public List<Test> Tests { get; } = new List<Test>();
public Test Test { get; set; }
}
[NotifyPropertyChanged]
public class Test
{
public string Name { get; set; }
}
但是Test
class下面的版本解决了问题:
public class Test : INotifyPropertyChanged
{
public string Name { get; set; }
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
看来这个问题是由于NotifyPropertyChanged
方面的弱事件管理器与WPF中的弱事件管理器不兼容造成的。作为解决方法,您可以在将方面应用到目标元素时禁用方面的弱事件实现:
[NotifyPropertyChanged( WeakEventStrategy = WeakEventStrategy.AlwaysStrong )]
[ContentProperty("Tests")]
public class Model
{
// ...
}
[NotifyPropertyChanged( WeakEventStrategy = WeakEventStrategy.AlwaysStrong )]
public class Test
{
// ...
}
我们将继续调查该问题,并在修复发布后更新答案。
编辑:此问题已在 PostSharp 6.0.28 中修复。