【问题标题】:WPF + PostSharp’ed View Model get frozen in a minuteWPF + PostSharp 的视图模型在一分钟内冻结
【发布时间】:2018-09-16 15:12:22
【问题描述】:

已更新(见下文)

经过一分钟的密集工作后,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];
    }
}

运行它并等待一分钟 - 窗口将被冻结。 任何想法如何解决它?

更新

我简化了模型 - 这个模型仍然在一分钟内被冻结:

[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类的以下版本解决了这个问题:

public class Test : INotifyPropertyChanged
{
    public string Name { get; set; }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

【问题讨论】:

  • 该问题已在 PostSharp 6.0.28 中修复。
  • 当我看到有关 PostSharp 的 [NotifyPropertyChanged] 的问题时,我的责任是提及一个更好的替代方案:Stepen Cleary 的计算属性。 github.com/StephenCleary/CalculatedProperties/blob/master/… 我两者都用过,IMO 没有理由将 Postsharp INPC 用于 MVVM。计算属性可以完成 PostSharp 所做的一切以及循环方法 LINQ 基本上任何你可以想象的疯狂依赖关系都不管多么间接,依赖关系图在运行时重新连接并且正常工作。它们速度更快,而且免费。

标签: c# wpf inotifypropertychanged postsharp .net-4.7.2


【解决方案1】:

看起来这个问题是由NotifyPropertyChanged 方面的弱事件管理器与 WPF 中的弱事件管理器之间的不兼容引起的。作为一种解决方法,您可以在将方面应用到目标元素时禁用方面的弱事件实现:

[NotifyPropertyChanged( WeakEventStrategy = WeakEventStrategy.AlwaysStrong )]
[ContentProperty("Tests")]
public class Model
{
    // ...
}

[NotifyPropertyChanged( WeakEventStrategy = WeakEventStrategy.AlwaysStrong )]
public class Test
{
    // ...
}

我们将继续调查该问题,并在修复发布后更新答案。

编辑:此问题已在 PostSharp 6.0.28 中修复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多