我遇到问题从我的viewmodel引发的事件有时会在服务时将datacontext显示为视图中的null。我开始认为这是一个弱的绑定模式问题,而且我没有使用它或者误解了它(一般来说设计模式并且在几个月前开始使用WPF)。
相关的MainWindow.xaml
<Grid Tree:TreeView.ItemSelected="DisplayRequested"
Tree:TreeView.PoolCategoriesChanged="PoolContentChanged">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="0" VerticalAlignment="Stretch"/>
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch"
Background="Gray" ShowsPreview="True" Width="5"
HorizontalAlignment="Center"/>
<GridSplitter Grid.Column="2" VerticalAlignment="Stretch"/>
<Tree:TreeView Name="poolTree" Grid.Column="0" Focusable="True" />
<ScrollViewer Grid.Column="2" VerticalScrollBarVisibility="Auto">
<Details:DetailsView Name="detailsDisplay" Focusable="True"/>
</ScrollViewer>
</Grid>
背后的相关代码
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var vm = (CLUViewModel)e.NewValue;
if (vm == null) return;
vm.OwnerCleanupStarted += OnOwnerCleanupStarting;
vm.OwnerCleanupEnded += OnOwnerCleanupEnding;
}
#region Event Handlers
private void OnOwnerCleanupEnding(object sender, EventArgs e)
{
ViewServices.CloseProgressDialog();
}
private void OnOwnerCleanupStarting(object sender, EventArgs e)
{
var vm = DataContext as CLUViewModel;
if (vm == null) return;
var progressDialogViewModel = vm.ProgressDialogVM;
ViewServices.ShowProgressDialog(GetWindow(this), progressDialogViewModel);
}
#endregion
}
我有几个RoutedEvents
似乎没有问题。 OnOwnerCleanupStarting
事件似乎在var vm = DataContext as CLUViewModel;
上返回null很多。这是因为它绑定得太强而且没有使用WPF框架吗?
如果我把它放在调试和跟踪中它总是有效,并且在正常使用期间多次正常工作。这是一种竞争条件,我在内存中使用的监听器是在对子组件聚焦时未初始化的视图吗?
来自VM的调用逻辑:
public class CLUViewModel : ViewModelBase
{
#region Properties
private RelayCommand _manageOwnersDialogCommand;
public ProgressDialogViewModel ProgressDialogVM;
#endregion
public CLUViewModel()
{
ProgressDialogVM = new ProgressDialogViewModel(string.Empty);
}
#region ManageOwnersDialogCommand
public ICommand ManageOwnersDialogCommand
{
get
{
return _manageOwnersDialogCommand ??
(_manageOwnersDialogCommand = new RelayCommand(param => OnManageOwnersDialogShow()));
}
}
private void OnManageOwnersDialogShow()
{
var dialog = new ManageOwnersDialog();
var vm = new ManageOwnersViewModel();
dialog.DataContext = vm;
if (!dialog.ShowDialog().Value) return;
var ownersRequiringCleanup = GetOwnersRequiringCleanup(vm);
if(ownersRequiringCleanup.Count < 1) return;
ProgressDialogVM.ClearViewModel();
ProgressDialogVM.TokenSource = new CancellationTokenSource();
ProgressDialogVM.ProgressMax = ownersRequiringCleanup.Count*2;
RaiseOwnerCleanupStartedEvent();
var taskOne = Task.Factory.StartNew(() => OwnerCleanupService.DoOwnerCleanup(ownersRequiringCleanup, ProgressDialogVM));
taskOne.ContinueWith(t => RaiseOwnerCleanupEndedEvent(), TaskScheduler.FromCurrentSynchronizationContext());
}
private List<Owner> GetOwnersRequiringCleanup(ManageOwnersViewModel vm)
{
var ownersRequiringCleanup = new List<Owner>();
// using DB to determine cleanup
// Proprietary code removed for this discussion
return ownersRequiringCleanup;
}
#endregion
#region Events
public event EventHandler OwnerCleanupStarted;
public event EventHandler OwnerCleanupEnded;
public void RaiseOwnerCleanupStartedEvent()
{
if (OwnerCleanupStarted == null) return;
OwnerCleanupStarted(this, new EventArgs());
}
public void RaiseOwnerCleanupEndedEvent()
{
if (OwnerCleanupEnded == null) return;
OwnerCleanupEnded(this, new EventArgs());
}
#endregion
}
我在其他几个控件中遇到了同样的问题,他们的各种虚拟机调用了父母(在树视图中)并且父母提出了这个事件。
我一直在学习这一点,而我在VM方面使用的一些事件是我之前对事情如何运作的理解。这是我应该将一个事件调到我的视图中然后开始RountedEvent
到达适当级别的事件吗?我是否陷入了强结合与弱结合的陷阱?
编辑:解决了父/子TreeView问题。 Master-Detail模式意味着我一直在访问不可见或从未加载过的详细视图。现在的初步问题仍然是出现空值。有没有更好的方法从VM回调到View相关的问题,这些问题对View DataContext没有任何困难?
答案 0 :(得分:1)
我建议在WPF中使用基于事件的编程模型。因为进入这样的事情太容易了。基于事件的编程强制紧密耦合。所以它是双重禁止
不是在View中抛出事件,而是使用DelegateCommand来执行ViewModel级别中定义的操作,而不是在ViewModel中抛出事件,只需使用常规属性和INotifyPropertyChanged来表示事态。
这当然需要从winforms或其他任何非wpf思维方式中获得重大的转移,但是当你意识到这一点时,你会产生更少和更清晰的代码。