Reputation: 105
I am trying to cover my C# WPF application into an MVVM pattern using Structuremap IoC container for dependency injection.
My code is works well until I try to use the same command binding in UserControls as Windows.
If I try to bind a command in a certain UserControl, I got the following error: System.Windows.Data Error: 40 : BindingExpression path error: 'HelloWorldCommand' property not found on 'object' ''MainWindowViewModel' (HashCode=7304143)'. BindingExpression:Path=HelloWorldCommand; DataItem='MainWindowViewModel' (HashCode=7304143); target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')
So the problem is that my HelloWorldCommand
is it in my CustomUserControlViewModel
which contained and binded by MainWindowViewModel
.
My code is 90% same to the following tutorial: Part 1 Part 2
Only the ObjectFactory method is different, which can be seen below:
public sealed class ObjectFactory
{
public static IContainer Container { get; private set; }
private static Action<ConfigurationExpression> _initialiseMethod;
private static readonly Lazy<IContainer> _containerBuilder =
new Lazy<IContainer>(CreateContainer, LazyThreadSafetyMode.ExecutionAndPublication);
public static void Initialise()
{
Container = _containerBuilder.Value;
}
private static IContainer CreateContainer()
{
return new Container(config =>
{
#region services
config.For<IFileDisplayerService>().Singleton().Use<FileDisplayerService>();
config.For<IWatermarkService>().Singleton().Use<WatermarkService>();
#endregion
#region windows
config.For<IWindow>().Use<MainWindow>();
config.For<IWatermarkWindow>().Use<WatermarkSettingsWindow>();
config.For<IMainWindow>().Singleton().Use<MainWindow>();
config.For<IMainWindowViewModel>().Singleton().Use<MainWindowViewModel>();
config.For<IWatermarkSettingsWindow>().Singleton().Use<WatermarkSettingsWindow>();
config.For<IWatermarkSettingsWindowViewModel>().Singleton().Use<WatermarkSettingsWindowViewModel>();
#endregion
#region views
config.For<IFileListView>().Use<FileListView>();
config.For<IFileListViewModel>().Use<FileListViewModel>()
.Ctor<IView>().Is<FileListView>();
config.For<IFileDisplayerView>().Use<FileDisplayerView>();
config.For<IFileDisplayerViewModel>().Use<FileDisplayerViewModel>()
.Ctor<IView>().Is<FileDisplayerView>();
#endregion
});
}
}
My concrete question is that how can I bind a command to a user control which has an own- and a parent ViewModel? This is not shown in the example above.
I think the parent ViewModel should contain the command as well, but I don't know how can I pass it to the parent ViewModel from child ViewModel.
Upvotes: 1
Views: 162
Reputation: 105
Thank you mm8 I solved my problem like the following mode:
MainWindowViewModel:
public IViewModel FileListViewModel { get; set; }
public IViewModel FileDisplayerViewModel { get; set; }
public IView FileListView { get; set; }
public IView FileDisplayerView { get; set; }
public MainWindowViewModel(IWindow window, IContainer container,
IFileDisplayerViewModel fileDisplayerViewModel, IFileListViewModel fileListViewModel) : base(window, container)
{
FileListViewModel = fileListViewModel;
FileListView = FileListViewModel.View;
FileDisplayerViewModel = fileDisplayerViewModel;
FileDisplayerView = FileDisplayerViewModel.View;
}
Now I can bind my UserControl's ViewModel into UserControlView:
<Button Command="{Binding FileListViewModel.HelloWorldCommand}" Width="100" Height="20" Content="Push" Background="White"></Button>
This is not entirely what I wanted but it saves me from catastrophic spaghetti code. I think it is feasible that I have a child view collection which is used to automatically bind a command from them if it is not available in the parent view. But this is sufficient now to proceed the project. Thank you!
Upvotes: 1