I'm new to WPF and MVVM. Currently building a WPF application using MVVM pattern, but quickly got stuck with multiple MVVMs.
Basically I have a MainWindow, and a UserControl on the MainWindow. It's a simple UserControl which only consists of a Image Control and a Scroll Bar. As Shown below:
<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>
Corresponding ViewModel is designed to be:
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
}
In my MainWindowViewModel, there is an instance of the TwoDSliceViewModel:
internal class MainWindowViewModel:INotifyPropertyChanged
{
...
private TwoDSliceViewModel _twoDSliceViewModel = new TwoDSliceViewModel();
public TwoDSliceViewModel TwoDModuleViewModel { get { return _twoDSliceViewModel; } }
...
}
In order to get binding of the UserControl(TwoDSliceControl) work, I set up the DataContext of the UserControl in my MainWindow.xaml like below:
<Window ...>
<Window.DataContext>
<viewModel:MainWindowViewModel />
</Window.DataContext>
...
<control:TwoDImageControl x:Name="twoDSliceImageControl" DataContext="{Binding Path=TwoDModuleViewModel}" />
...
</Window>
My UserControl (TwoDSliceControl) is ViewModel specific, so I choose this way instead of using Dependency Properties. But the binding failed. You could see in my code that I created some demo data upon instantiation of the TwoDSliceViewModel, but those dummy data don't show up.
I've used breakpoints to find out that After the MainWindow is successfully initialized, the DataContext of the TwoDSliceControl is well set. But the Source property of the ImageControl in the TwoDSliceControl and the MaxValue property of the ScrollBar in the TwoDSliceControl are null.
I have the feeling that, this line of XAML code :
<control:TwoDImageControl x:Name="twoDSliceImageControl" DataContext="{Binding Path=TwoDModuleViewModel}" />
actually initialize the twoDSliceImageControl first and then set the twoDSliceImageControl.DataContext property. Upon initialization, the twoDSliceImageControl.DataContext is null, so the Binding within the twoDSliceImageControl fails. Though after initialization, the twoDSliceImageControl.DataContext is well set, bindings within the UserControl doesn't refresh, and they're still null.
Any workaround to solve this issue? Have been stuck on it for a while, and didn't find a proper solution. Thanks guys!