PropertyChangedEventManager
などの弱いイベントマネージャを使用して、WPFアプリケーションのイベントを購読しています。WPFで「ハングアラウンド」のイベントが貧弱です - これは予期された動作ですか?
しかし、メモリリークの可能性がありますが、ガーベッジコレクタがイベントを受け取る前にイベントに反応するものだけが厳密にメモリリークではないと思います。ここに私の問題を実証する例を示します
MainWindow
クラスと私が聞きたいことを、プロパティ番号とコードビハインド美しい、とリスニングクラスへの強い参照。
それは1を追加する/強い参照を削除し、1は、プロパティ番号変更するには、2つのボタンイベントがあります。XAMLで
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
// strong reference to listening class that will be added/removed
private TestReferenceClass strongReference;
// property that the listening class will listen to
private int number;
public int Number
{
get { return number; }
set { number = value; NotifyPropertyChanged(); }
}
// for UI
private bool referenceExists;
public bool ReferenceExists
{
get { return referenceExists; }
set { referenceExists = value; NotifyPropertyChanged(); }
}
//button event to change Number
private void ChangeProp(object sender, RoutedEventArgs e)
{
Number++;
}
//button event to assign/remove reference
private void ToggleReference(object sender, RoutedEventArgs e)
{
if (strongReference != null)
{
strongReference = null;
ReferenceExists = false;
}
else
{
strongReference = new TestReferenceClass(this);
ReferenceExists = true;
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
を:
<Window x:Class="WpfApp.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"
mc:Ignorable="d"
Title="MainWindow" Height="150" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
<Button Margin="10, 0" Click="ToggleReference">Toggle Reff</Button>
<Grid>
<TextBlock Text="No Refference" Background="White" VerticalAlignment="Center"/>
<TextBlock Text="Refference" Visibility="{Binding ReferenceExists, Converter={StaticResource BooleanToVisibilityConverter}}" Background="White" VerticalAlignment="Center"/>
</Grid>
<Button Margin="10, 0" Click="ChangeProp">Change property</Button>
<TextBox Text="{Binding Number}" Width="200" IsReadOnly="True"/>
</StackPanel>
</Window>
次に「参照」はありますプロパティの変更をリッスンするクラス。単純に作成され、弱いイベントリスナーPropertyChangedEventManager
を使用して数値の変更をリッスンしている:
public class TestReferenceClass
{
public TestReferenceClass(MainWindow source)
{
// add a weak event manager
PropertyChangedEventManager.AddHandler(source, Source_PropertyChanged, string.Empty);
}
private void Source_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Number")
{
Console.WriteLine("Property changed! " + (sender as MainWindow).Number);
}
}
}
結果が弱いリスナーを残して、あなたが作成および破棄の参照を、そのイベントをトリガすることができます小さなアプリケーションです参照を保持している:
それはそれであなたの周りだけ弱い参照によって保持されているのオブジェクトにイベントをトリガすることができますビットをいじり後に明らかになりました。あなたは数回破壊する/作成ボタンをスパムした場合、あなたは同じのために複数のイベントをトリガすることができます。このようにクリックしてください:
Property changed! 3
Property changed! 3
Property changed! 3
Property changed! 4
Property changed! 4
Property changed! 4
参照が除去された後、それはまた、かなりしばらくの間、トリガーます。しかし、はが最終的に削除されているように見えますが、多分ガベージコレクションのラウンド後に真のリークは避けられますか?
これが期待どおりの動作ですか?私。弱いイベントリスナーは、イベントをトリガーする前に他の参照がないことを積極的にチェックするのではなく、オブジェクトがガベージコレクションされたことを単にチェックします(弱い参照だけなので起こります)。
通常はこれは問題ではありませんが、変更のためにかなり高価な操作(グラフのデータを取得)をしているケースがあります。トラック(ユーザーがレイアウト全体に物事をドラッグアンドドロップできる非常にインタラクティブなUI)。私はIDisposableまたはそれに類するものを実装することができますが、それは大きなリファクタリングになります。
この高価な変更が発生する前にガベージコレクションを強制するのが解決策です。 – Joe
そうではありません。すぐにイベントからの退会を希望する場合は、おそらく強力な参照を使用する必要があります:https://stackoverflow.com/questions/43201093/is-it-safe-to-replace-all-standard-event-handler -to-weakeventmanager-or-its-vari/43204926#43204926 – mm8
私はそう心配しました。ありがとう。右、大きなIDisposableリファクタリング時間! – Joe