我们正在使用 c# MVVM 模式使用 Silverlight 开发一个项目。我们在页面内使用自定义控件。自定义控件根据其依赖属性更改引发一些事件,当我为同一页面使用新的 ViewModel 实例时,这些事件可以正常工作。
由于我们的业务需要,我们必须维护一个页面的 ViewModel 实例,同时我们不维护页面实例,所以每次都会重新创建页面实例。
现在,如果在特定页面打开超过一次(关闭然后重新打开)时特定视图模型中的任何属性发生更改,则视图模型命令(自定义控件的事件)每次单个属性更改都会引发多次。
我可以理解视图或自定义控件的先前实例保留在某处并响应相应视图模型的属性更改。解决此问题的最佳方法是什么?
// 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 响应一次。我再次关闭页面,用同样的方法打开同一个程序,现在页面是新的,ViewModelInstance 是旧的,对吗?现在我单击按钮 CustomCONtrol 响应二、三等。因为创建的 Page 实例仍然存在于某处并且对 ViewModel 属性更改的响应。