将 UserControl 的 DataContext 绑定到子 ViewModel
Bind the DataContext of a UserControl to a sub ViewModel
我是 WPF 和 MVVM 的新手。目前正在使用 MVVM 模式构建 WPF 应用程序,但很快就陷入了使用多个 MVVM 的困境。
基本上我有一个主窗口,主窗口上有一个用户控件。这是一个简单的 UserControl,仅由一个图像控件和一个滚动条组成。如下图:
<UserControl x:Class="AutomaticContourEvaluation_WURO_WPF.Views.TwoDImageControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AutomaticContourEvaluation_WURO_WPF.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding Path=CurrentSlice}" x:Name="sliceDisplayControl" />
<ScrollBar Grid.Column="1" Minimum="0" Maximum="{Binding Path=NumberOfSlices, FallbackValue=10}" Value="{Binding Path=SliceIndex, Mode=TwoWay, FallbackValue=0}" x:Name="sliceSelectionScrollBar" Margin="0,0,0,0"/>
</Grid>
相应的 ViewModel 设计为:
internal class TwoDSliceViewModel : INotifyPropertyChanged
{
private List<BitmapImage> _imageSlices;
private int _sliceIndex = 0;
public BitmapImage CurrentSlice { get { return _imageSlices[SliceIndex]; } }
public int NumberOfSlices { get { return _imageSlices.Count; } }
public int SliceIndex
{
get
{
return _sliceIndex;
}
set
{
if (_sliceIndex != value)
{
_sliceIndex = value;
NotifyPropertyChanged("SliceIndex");
NotifyPropertyChanged("CurrentSlice");
}
}
}
public TwoDSliceViewModel()
{
BitmapImage demoImage = new BitmapImage();
demoImage.UriSource = new Uri("2Ddemo.jpg", UriKind.Relative);
demoImage.CacheOption = BitmapCacheOption.OnLoad;
if (_imageSlices == null)
{
_imageSlices = new List<BitmapImage>();
}
_imageSlices.Add(demoImage);
}
public TwoDSliceViewModel(List<BitmapImage> imageSlices)
{
_imageSlices = imageSlices;
}
public void updateImageSlices(List<BitmapImage> images)
{
_imageSlices = images;
_sliceIndex = 0;
NotifyPropertyChanged("CurrentSlice");
NotifyPropertyChanged("NumberOfSlices");
NotifyPropertyChanged("SliceIndex");
}
#region INotifyPropertyChanged Methods
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
在我的 MainWindowViewModel 中,有一个 TwoDSliceViewModel 的实例:
internal class MainWindowViewModel:INotifyPropertyChanged
{
...
private TwoDSliceViewModel _twoDSliceViewModel = new TwoDSliceViewModel();
public TwoDSliceViewModel TwoDModuleViewModel { get { return _twoDSliceViewModel; } }
...
}
为了绑定 UserControl(TwoDSliceControl) 工作,我在 MainWindow.xaml 中设置了 UserControl 的 DataContext,如下所示:
<Window ...>
<Window.DataContext>
<viewModel:MainWindowViewModel />
</Window.DataContext>
...
<control:TwoDImageControl x:Name="twoDSliceImageControl" DataContext="{Binding Path=TwoDModuleViewModel}" />
...
</Window>
我的 UserControl (TwoDSliceControl) 是特定于 ViewModel 的,所以我选择这种方式而不是使用依赖属性。但是绑定失败。您可以在我的代码中看到,我在实例化 TwoDSliceViewModel 时创建了一些演示数据,但这些虚拟数据没有显示。
我打过断点发现MainWindow初始化成功后,TwoDSliceControl的DataContext设置好了。但是TwoDSliceControl中ImageControl的Source属性和TwoDSliceControl中ScrollBar的MaxValue属性为空
我的感觉是,这行 XAML 代码:
<control:TwoDImageControl x:Name="twoDSliceImageControl" DataContext="{Binding Path=TwoDModuleViewModel}" />
实际上是先初始化twoDSliceImageControl,然后设置twoDSliceImageControl.DataContext 属性。初始化时,twoDSliceImageControl.DataContext 为空,因此 twoDSliceImageControl 中的绑定失败。虽然在初始化后,twoDSliceImageControl.DataContext 已设置好,但 UserControl 中的绑定不会刷新,并且它们仍然为空。
有解决此问题的方法吗?纠结了好久,一直没有找到合适的解决办法。谢谢大家!
谢谢大家。我终于找到了。
这些代码行似乎有一些问题:
BitmapImage demoImage = new BitmapImage();
demoImage.UriSource = new Uri("2Ddemo.jpg", UriKind.Relative);
demoImage.CacheOption = BitmapCacheOption.OnLoad;
相反,我需要使用 BitmapImage.BeginInit() 和 BitmapImage.EndInit() 包装 BitmapImage 创建。
所以工作代码是:
BitmapImage demoImage = new BitmapImage();
demoImage.BeginInit();
demoImage.UriSource = new Uri("2Ddemo.jpg", UriKind.Relative);
demoImage.CacheOption = BitmapCacheOption.OnLoad;
demoImage.EndInit();
实际上绑定没有任何问题!
我是 WPF 和 MVVM 的新手。目前正在使用 MVVM 模式构建 WPF 应用程序,但很快就陷入了使用多个 MVVM 的困境。
基本上我有一个主窗口,主窗口上有一个用户控件。这是一个简单的 UserControl,仅由一个图像控件和一个滚动条组成。如下图:
<UserControl x:Class="AutomaticContourEvaluation_WURO_WPF.Views.TwoDImageControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AutomaticContourEvaluation_WURO_WPF.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding Path=CurrentSlice}" x:Name="sliceDisplayControl" />
<ScrollBar Grid.Column="1" Minimum="0" Maximum="{Binding Path=NumberOfSlices, FallbackValue=10}" Value="{Binding Path=SliceIndex, Mode=TwoWay, FallbackValue=0}" x:Name="sliceSelectionScrollBar" Margin="0,0,0,0"/>
</Grid>
相应的 ViewModel 设计为:
internal class TwoDSliceViewModel : INotifyPropertyChanged
{
private List<BitmapImage> _imageSlices;
private int _sliceIndex = 0;
public BitmapImage CurrentSlice { get { return _imageSlices[SliceIndex]; } }
public int NumberOfSlices { get { return _imageSlices.Count; } }
public int SliceIndex
{
get
{
return _sliceIndex;
}
set
{
if (_sliceIndex != value)
{
_sliceIndex = value;
NotifyPropertyChanged("SliceIndex");
NotifyPropertyChanged("CurrentSlice");
}
}
}
public TwoDSliceViewModel()
{
BitmapImage demoImage = new BitmapImage();
demoImage.UriSource = new Uri("2Ddemo.jpg", UriKind.Relative);
demoImage.CacheOption = BitmapCacheOption.OnLoad;
if (_imageSlices == null)
{
_imageSlices = new List<BitmapImage>();
}
_imageSlices.Add(demoImage);
}
public TwoDSliceViewModel(List<BitmapImage> imageSlices)
{
_imageSlices = imageSlices;
}
public void updateImageSlices(List<BitmapImage> images)
{
_imageSlices = images;
_sliceIndex = 0;
NotifyPropertyChanged("CurrentSlice");
NotifyPropertyChanged("NumberOfSlices");
NotifyPropertyChanged("SliceIndex");
}
#region INotifyPropertyChanged Methods
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
在我的 MainWindowViewModel 中,有一个 TwoDSliceViewModel 的实例:
internal class MainWindowViewModel:INotifyPropertyChanged
{
...
private TwoDSliceViewModel _twoDSliceViewModel = new TwoDSliceViewModel();
public TwoDSliceViewModel TwoDModuleViewModel { get { return _twoDSliceViewModel; } }
...
}
为了绑定 UserControl(TwoDSliceControl) 工作,我在 MainWindow.xaml 中设置了 UserControl 的 DataContext,如下所示:
<Window ...>
<Window.DataContext>
<viewModel:MainWindowViewModel />
</Window.DataContext>
...
<control:TwoDImageControl x:Name="twoDSliceImageControl" DataContext="{Binding Path=TwoDModuleViewModel}" />
...
</Window>
我的 UserControl (TwoDSliceControl) 是特定于 ViewModel 的,所以我选择这种方式而不是使用依赖属性。但是绑定失败。您可以在我的代码中看到,我在实例化 TwoDSliceViewModel 时创建了一些演示数据,但这些虚拟数据没有显示。
我打过断点发现MainWindow初始化成功后,TwoDSliceControl的DataContext设置好了。但是TwoDSliceControl中ImageControl的Source属性和TwoDSliceControl中ScrollBar的MaxValue属性为空
我的感觉是,这行 XAML 代码:
<control:TwoDImageControl x:Name="twoDSliceImageControl" DataContext="{Binding Path=TwoDModuleViewModel}" />
实际上是先初始化twoDSliceImageControl,然后设置twoDSliceImageControl.DataContext 属性。初始化时,twoDSliceImageControl.DataContext 为空,因此 twoDSliceImageControl 中的绑定失败。虽然在初始化后,twoDSliceImageControl.DataContext 已设置好,但 UserControl 中的绑定不会刷新,并且它们仍然为空。
有解决此问题的方法吗?纠结了好久,一直没有找到合适的解决办法。谢谢大家!
谢谢大家。我终于找到了。 这些代码行似乎有一些问题:
BitmapImage demoImage = new BitmapImage();
demoImage.UriSource = new Uri("2Ddemo.jpg", UriKind.Relative);
demoImage.CacheOption = BitmapCacheOption.OnLoad;
相反,我需要使用 BitmapImage.BeginInit() 和 BitmapImage.EndInit() 包装 BitmapImage 创建。
所以工作代码是:
BitmapImage demoImage = new BitmapImage();
demoImage.BeginInit();
demoImage.UriSource = new Uri("2Ddemo.jpg", UriKind.Relative);
demoImage.CacheOption = BitmapCacheOption.OnLoad;
demoImage.EndInit();
实际上绑定没有任何问题!