複数のオブジェクトを持つアプリケーションを準備しています。それぞれに整数の ID と文字列データがあります。同じIDを持つオブジェクトのデータを同じにしたい。このオブジェクトを SharedObject と呼びます (このオブジェクトは、一部のデータベース テーブルの ViewModel のように機能します)。
とても簡単だと言えるかもしれません。オブジェクトを 1 つ作成し、必要なときにいつでも参照できます。しかし、実際には、オブジェクトがいつどこで作成されるかを予測できないため、この方法はうまくいきません。
したがって、この問題を処理するために、SharedObject クラスに静的イベントを配置し、SharedObject データが変更されたときにそれを呼び出すことにしました (INotifyPropertyChanged の PropertyChanged イベントのように、私のものは静的です。これにより、SharedObject の各インスタンスに表示されます)。問題は、メモリリークだらけのプログラムになってしまうことです!!
昨夜、メモリ リークの問題を解決するには弱いイベント パターンを使用する必要があることを整理しました。
弱いイベント パターンの完全な実装を求めて昨夜ネットを検索しましたが、最終的には何も表示されなかったか、ページが削除されました。
最後に、弱いイベント パターンでそれを行う方法を見つけ、このアプローチをテストするテスト プロジェクトを作成しましたが、うまくいきませんでした。ReceiveWeakEvent イベントを呼び出すことができませんでした。
何か不足していますか?または、このパターンを実装する正しい方法は何ですか?
ちなみに、私はアプリケーションで Win XP をサポートする必要があるため .net 4 を使用しています (これは私の顧客が必要としているものです。それについて私に尋ねないでください)。そのため、一般的な WeakEventManager クラスを使用できません。
長い投稿で申し訳ありませんが、この問題は私が髪を引き裂くところだったので、事前に感謝します.
完全なアプリケーション コードは次のとおりです。
SharedObject クラス:
public class SharedObject :INotifyPropertyChanged,IWeakEventListener
{
static WaekEvent sheardEvent = new WaekEvent();
public event PropertyChangedEventHandler PropertyChanged;
public int ID { get; private set; }
public SharedObject(int id)
{
this.ID = id;
SharedWeakEventManager.AddListener(sheardEvent, this);
}
string data;
public string Data
{
get
{
return data;
}
set
{
if(value != data)
{
data = value;
OnPropertyChanged("Data");
sheardEvent.RiseSharedEvent(this, new PropertyChangedEventArgs("Data"));
}
}
}
protected virtual void OnPropertyChanged(string propName)
{
PropertyChangedEventHandler handler;
lock (this)
{
handler = PropertyChanged;
}
if (handler != null)
handler.Invoke(this, new PropertyChangedEventArgs(propName));
}
void OnSharedPropertyChaingo(object sender,PropertyChangedEventArgs e)
{
SharedObject s = sender as SharedObject;
if (s == null || s.ID != ID)
return;
data = s.Data;
OnPropertyChanged("Data");
}
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
if(managerType == typeof(SharedWeakEventManager) && sender is SharedObject)
{
OnSharedPropertyChaingo(sender, e as PropertyChangedEventArgs);
}
return false;
}
}
WaekEvent および SharedWeakEventManager クラス:
public class SharedObject
{
public event EventHandler SharedEvent;
public void RiseSharedEvent(object sender, EventArgs args)
{
if (SharedEvent != null)
SharedEvent.Invoke(sender, args);
}
}
public class SharedWeakEventManager : WeakEventManager
{
public static SharedWeakEventManager CurrentManager
{
get
{
var manager_type = typeof(SharedWeakEventManager);
var manager = WeakEventManager.GetCurrentManager(manager_type) as SharedWeakEventManager;
if (manager == null)
{
manager = new SharedWeakEventManager();
WeakEventManager.SetCurrentManager(manager_type, manager);
}
return manager;
}
}
public static void AddListener(WaekEvent source, IWeakEventListener listener)
{
CurrentManager.ProtectedAddListener(source, listener);
}
public static void RemoveListener(WaekEvent source, IWeakEventListener listener)
{
CurrentManager.ProtectedRemoveListener(source, listener);
}
protected override void StartListening(object source)
{
((WaekEvent)source).SharedEvent += this.DeliverEvent;
}
protected override void StopListening(object source)
{
((WaekEvent)source).SharedEvent -= this.DeliverEvent;
}
}
MainWindow の XAML 部分:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListView x:Name="View" Margin="10,49,10,10" SelectionChanged="ListView_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" Width="100" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="Data" Width="100" DisplayMemberBinding="{Binding Data}"/>
</GridView>
</ListView.View>
</ListView>
<Button Content="New" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="10,13.01,0,0" Click="Button_Click"/>
<TextBox x:Name="IDText" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="92" Margin="136.2,11,0,0"/>
<TextBox x:Name="DataText" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="92" Margin="280.799,11,0,0" TextChanged="DataText_TextChanged"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="ID" VerticalAlignment="Top" Margin="119.593,14,0,0"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Data" VerticalAlignment="Top" Margin="251.106,15.01,0,0"/>
<Button Content="Remove" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="377.799,12,0,0" Click="Button_Click_1"/>
</Grid>
MainWindow クラス:
public partial class MainWindow : Window
{
private ObservableCollection<SharedObject> sharedObjects;
public ObservableCollection<SharedObject> SharedObjects
{
get
{
if (sharedObjects == null)
sharedObjects = new ObservableCollection<SharedObject>();
return sharedObjects;
}
}
public SharedObject SelelectedObject { get; set; }
public MainWindow()
{
InitializeComponent();
View.ItemsSource = SharedObjects;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
int id;
if (!int.TryParse(IDText.Text, out id))
return;
SharedObject x = new SharedObject(id);
x.Data = DataText.Text;
SharedObjects.Add(x);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
if (SelelectedObject == null)
return;
SharedObjects.Remove(SelelectedObject);
SelelectedObject = null;
}
private void DataText_TextChanged(object sender, TextChangedEventArgs e)
{
if (SelelectedObject != null)
SelelectedObject.Data = DataText.Text;
}
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelelectedObject = View.SelectedItem as SharedObject;
if (SelelectedObject == null)
return;
IDText.Text = SelelectedObject.ID.ToString();
DataText.Text = SelelectedObject.Data;
}
}