我有两个文件浏览器用户控件实例,控件只是一个按钮和一个文本框,但我需要两个实例,想一个diff实用程序。一旦用户为每个控件选择了一个文件,我想启用一个按钮,该按钮将对这两个文件执行操作。
我遇到的问题是如何区分控件的实例以确定是否已选择这两个文件。我想我希望我的DoSumthinViewModel只有FileChooserViewModel实现的字符串属性。
起初我有一个ViewModelLocator,它有一个属性,当访问时返回FileChooserVM的新实例,但这似乎不对,我无法区分实例。然后我沿着FileChooser的单独定位器的路径走下去,但意识到每个控件将与同一个定位器实例进行通信,从而再次与同一个FileChooserViewModel进行通信。
那么,使用同一个ViewModel的各个实例的好方法是什么?
谢谢,
Shane Holder
答案 0 :(得分:0)
您的DoSomethingViewModel可能具有控件绑定的FileChooserViewModel类型的两个属性,然后检查其字符串属性中的值。
FileChooserViewModel的简化版可能是......
public class FileChooserViewModel : ViewModelBase
{
public const string FilePathPropertyName = "FilePath";
private string _filePath;
public string FilePath
{
get { return _filePath; }
set
{
if (_filePath == value) return;
_filePath = value;
RaisePropertyChanged(FilePathPropertyName);
Messenger.Default.Send(new NotificationMessage("FilePath Updated"));
}
}
}
您的DoSomethingViewModel可能看起来像这样......
public class DoSomethingViewModel : ViewModelBase
{
public DoSomethingViewModel()
{
Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}
public const string FileChooser1PropertyName = "FileChooser1";
private FileChooserViewModel _fileChooser1 = new FileChooserViewModel();
public FileChooserViewModel FileChooser1
{
get { return _fileChooser1; }
set
{
if (_fileChooser1 == value) return;
_fileChooser1 = value;
RaisePropertyChanged(FileChooser1PropertyName);
}
}
public const string FileChooser2PropertyName = "FileChooser2";
private FileChooserViewModel _fileChooser2 = new FileChooserViewModel();
public FileChooserViewModel FileChooser2
{
get { return _fileChooser2; }
set
{
if (_fileChooser2 == value) return;
_fileChooser2 = value;
RaisePropertyChanged(FileChooser2PropertyName);
}
}
public const string BothFilesChosenPropertyName = "BothFilesChosen";
public bool BothFilesChosen
{
get
{
var result = false;
if (FileChooser1 != null && FileChooser2 != null)
result = !string.IsNullOrWhiteSpace(FileChooser1.FilePath)
&& !string.IsNullOrWhiteSpace(FileChooser2.FilePath);
return result;
}
}
private void NotificationMessageReceived(NotificationMessage msg)
{
if (msg.Sender is FileChooserViewModel)
RaisePropertyChanged(BothFilesChosenPropertyName);
}
}
调用NotificationMessageReceived方法,从FileChooserViewModel的FilePath属性setter发送NotificationMessage,然后它会在BothFilesChosen属性上引发属性更改事件。
<UserControl x:Class="DoSomethingProject.Views.DoSomethingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:DoSomethingProject.Views"
DataContext="{Binding DoSomethingViewModel, Source={StaticResource Locator}}">
<StackPanel>
<views:FileChooser DataContext="{Binding Path=FileChooser1}" />
<views:FileChooser DataContext="{Binding Path=FileChooser2}" />
<Button IsEnabled="{Binding Path=BothFilesChosen}" />
</StackPanel>
</UserControl>
另一种方法是在每个FileChooserViewModel属性上处理PropertyChanged事件,但我更喜欢使用消息传递,因为事件处理意味着您需要确保取消处理事件,这可能会导致内存问题变得混乱当事件被遗漏时。