0

c# MVVM パターンを使用して Silverlight でプロジェクトを開発しています。ページ内でカスタム コントロールを使用しています。依存関係プロパティの変更に基づいていくつかのイベントを発生させるカスタム コントロールは、同じページに新しい ViewModel インスタンスを使用しているときに正常に動作します。

ビジネス ニーズにより、ページの ViewModel インスタンスを維持する必要がありますが、同時にページ インスタンスを維持していないため、ページ インスタンスが再度作成されるたびに。

現在、特定のページを複数回開く (閉じてから再度開く) たびに特定のビュー モデルでプロパティが変更された場合、ビュー モデル コマンド (カスタム コントロールのイベント) が 1 つのプロパティ変更ごとに複数回発生します。

ビューまたはカスタム コントロールの以前のインスタンスがどこかに残り、対応するビュー モデルのプロパティの変更に応答することは理解できます。この問題を解決する最善の方法は何ですか?

// my custom control
public class CustomControl:Control
{
    public event EventHandler SearchCompletedEvent;
    public bool IsSearch
    {
        get{return (bool)GetValue(IsSearchProperty)};
        set{SetValue(IsSearchProperty,value)};
    }
    // Using a DependencyProperty as the backing store for IsSearch.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsSearchProperty=
    DependencyProperty.Register("IsSearch", typeof(bool), typeof(CustomControl), new PropertyMetadata(null, new PropertyChangedCallback(OnIsSearchPropertyChanged)));

    private static void OnIsSearchPropertyChanged(
        DependencyObject dp, DependencyPropertyChangedEventArgs de)
    {
        if (dp != null && dp is CustomControl&& de.NewValue != null)
        ((CustomControl)dp).OnIsSearchPropertyChanged((bool)de.NewValue);
    }
    private void OnIsSearchPropertyChanged(bool newValue)
    {
        if( newValue)
        {
            // some searching statements here
            if(SearchCompletedEvent!=null)
            SearchCompletedEvent(this,new EventArgs());      
        }
    }
}

public class RelayCommand : ICommand
{
    private Func<bool> canExecute;
    private Action executeAction;
    public event EventHandler CanExecuteChanged;  
    public RelayCommand(Action executeAction, Func<bool> canExecute)
    {
        this.executeAction = executeAction;
        this.canExecute = canExecute;
    } 

    public RelayCommand(Action executeAction)
    {
        this.executeAction = executeAction;
        this.canExecute = () => true;
    } 

    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    } 

    public bool CanExecute(object parameter)
    {
        return canExecute == null ? true : canExecute();
    }
}        

//
//My ViewModel is like 
public class MainPageViewModel:INotifyPropertyChanged
{
    public MainPageViewModel()
    {
        SearchCommand=new RelayCommand(SearchEventMethod);
        FindCommand=new RelayCommand(FindMethod);
    }

    protected void RaisePropertyChanged(string property)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(property));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public ICommand SearchCommand{get;set;}
    public ICommand FindCommand{get;set;}
    private bool isSearch;
    public bool IsSearch
    {
        get { return isSearch;}
        set { isSearch=value;
            RaisePropertyChanged("IsSearch");
        }
    }

    private void SearchEventMethod()
    {
        IsSearch=false;
        // some codes for execute after search
    }

    private void FindMethod()
    {
        IsSearch=true;
    }
}

//
// My ViewModel Insatance Maintainer 
public class InstanceMaintainer
{
    public string InstanceKey{get;}
    public object ViewModelInstance{get;}

    public InstanceMaintainer(string instanceKey,object Instance)
    {
        this.InstanceKey=instanceKey;
        this.ViewModelInstance=Instance;
    }
}

//
// my App.xaml.cs file
public class App:Application
{
    private static List<InstanceMaintainer> instanceList=new  List<InstanceMaintainer>();
    public static object GetInstance(string programKey)
    {
        if(programKey=="PGM001")
        {
            MyXamlPage page=new MyXamlPage();
            if(insatnceList.select(x=>x.InstanceKey).Containes(programKey))
            {
                page.DataContext=insatnce.where(x=>x.InstanceKey==programKey).FirstOrDefault().Instance;
            }
            else
            {
                MainPageViewModel vm=new MainPageViewModel();
                instanceList.Add(new InstanceMaintainer(programKey,vm);
                page.DataContext=vm;
            }
        }
    }
}

// My xaml page is like
<Grid x:Name="LayoutRoot">
    <local:CustomControl IsSearch="{Binding IsSearch,Mode=TwoWay}" 
        SearchCompletedEvent="{Binding SearchCommand,Mode=TwoWay}">
    </local:CustomControl>

    <Button Command="{Binding FindCommand,Mode=TwoWay}" />
</Grid>

このシナリオでは、特定のプログラムを初めて開く

App.GetInstance("PGM001");

ページをクリックし、[My CustomControl response] ボタンを 1 回クリックします。そして、ページを閉じて、同じ方法で同じプログラムを再度開くと、ページは新しく、ViewModelInstance は古いですよね?ここで、CustomCOntrol の応答 2、3 などのボタンをクリックします。作成された Page インスタンスがどこかに残り、ViewModel プロパティの応答が変更されるためです。

4

1 に答える 1