I'm trying to use a UserControl I did, but currently, I've an error:
No parameterless constructor defined for this object
The thing is... There is only one constructor, and it has no parameters.
Here is some code:
<DockPanel x:Class="Xms.SomePackage.NewLicenseWizard"
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:wizard="clr-namespace:my.wizard.namepsace;assembly=My.Common.Assembly"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" LastChildFill="True">
<wizard:Wizard> <-- Error is here -->
<wizard:WizardPage>
<wizard:WizardPage.ContentElement>
<TextBlock>Page one</TextBlock>
</wizard:WizardPage.ContentElement>
</wizard:WizardPage>
</wizard:Wizard>
</DockPanel>
The Wizard UserControl looks like this:
[ContentProperty("Pages")]
public partial class Wizard : UserControl, IView
{
#region Dependency Properties
//All the Dependencies Properties)]
#endregion
#region Public Properties
internal WizardViewModel ViewModel
{
get { return DataContext as WizardViewModel; }
set { DataContext = value; }
}
#endregion
#region Constructor
public Wizard()
{
Pages = new ObservableCollection<WizardPage>();
InitializeComponent();
ViewModelLocationProvider.AutoWireViewModelChanged(this);
//[Some other initialization]
}
#endregion
}
I just removed the DependencyProperties.
So why is it thinking that I've no parameterless constructor?
(at runtime I've no issues)
EDIT
Here is the ViewModel bound to the Wizard UserControl:
internal class WizardViewModel : XmsViewModelBase
{
#region public Properties
public InteractionRequest<CloseWindowRequest> CloseWindowRequest { get; private set; }
public DelegateCommand GoToPreviousPageCommand { get; set; }
public DelegateCommand GoToNextPageCommand { get; set; }
public DelegateCommand FinishCommand { get; set; }
public DelegateCommand CancelCommand { get; set; }
public ObservableCollection<WizardPage> Pages
{
get { return GetValue<ObservableCollection<WizardPage>>(); }
set { SetValue(value); }
}
public WizardPage CurrentPage
{
get { return GetValue<WizardPage>(); }
set
{
SetValue(value);
HandleCurrentPageChanged();
}
}
public Boolean IsLastPage
{
get { return GetValue<Boolean>(); }
set { SetValue(value); }
}
#endregion
#region Constructor
public WizardViewModel()
{
Pages = new ObservableCollection<WizardPage>();
//+Initialization of commands
}
#endregion
#region Private Methods
// All the methods related to the commands
#endregion
}
Related
While exploring DI/IOC with Unity with WPF, I came across a question and need your feedback. Please consider the following scenario...
================================================================
public interface IDataServices
{
string GetData();
}
================================================================
public class CopyTextDataServices : IDataServices
{
public string GetData()
{
return "copy text from CopyTextDataServices";
}
}
================================================================
public class TextDataServices : IDataServices
{
public string GetData()
{
return "I am injected by setter property injection";
}
}
================================================================
public interface ITextViewModel
{
string LabelContnet { get; set; }
}
================================================================
public class TextViewModel : ITextViewModel
{
public TextViewModel()
{
LabelContnet = "This is from view model";
}
public string LabelContnet { get; set; }
}
================================================================
public partial class MainWindow : Window
{
public MainWindow(ITextViewModel textViewModel)
{
InitializeComponent();
Loaded += MainWindow_Loaded;
DataContext = textViewModel;
}
[Dependency]
public IDataServices Services { get; set; }
containing the event data.</param>
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
LabelLeft.Content = Services.GetData();
}
}
================================================================
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataServices, TextDataServices>();
container.RegisterType<IDataServices, CopyTextDataServices>();
container.RegisterType<ITextViewModel, TextViewModel>();
var window = container.Resolve<MainWindow>();
window.Show();
}
}
================================================================
<Window x:Class="TestAppWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" FontSize="20">
<StackPanel>
<Label Content="{Binding Path=LabelContnet,FallbackValue=Left}" HorizontalAlignment="Left" Name="LabelLeft" />
<Label Content="{Binding Path=LabelContnet,FallbackValue=Right}" HorizontalAlignment="Left" Name="LabelRight" />
</StackPanel>
</Window>
===================================================================
Now the result of this appears in the labels is
copy text from CopyTextDataServices
This is from view model
But I want to know if I want to get data from TextDataServices, how can I do that?
The problem is in this line:
container.RegisterType<IDataServices, TextDataServices>();
// This overwrites the previous mapping.
// All dependencies to IDataServices will use CopyTextDataServices.
container.RegisterType<IDataServices, CopyTextDataServices>();
If you want to have both IDataServices, you'll need to register one or both as named instances.
container.RegisterType<IDataServices, TextDataServices>("TextDataServicesName");
container.RegisterType<IDataServices, CopyTextDataServices>("CopyTextDataServicesName");
In your control:
[Dependency("TextDataServicesName")]
public IDataServices Services { get; set; }
I'm trying to get Lazy to work for a collection in my ViewModel that I'm binding to. The collection loads through MEF fine, but never gets displayed in the bound UI.
Here's the UI:
<Window x:Class="TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<ItemsControl ItemsSource="{Binding MyList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding ItemTitle}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel>
</Window>
The code-behind class:
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
this.DataContext = new TestVM();
}
}
The ViewModel:
public class TestVM : INotifyPropertyChanged, IPartImportsSatisfiedNotification
{
public TestVM()
{
//I'm using a static class to initiate the import
CompositionInitializer.SatisfyImports(this);
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
[ImportMany(typeof(MyItemBase))]
public Lazy<MyItemBase>[] MyList { get; set; }
public void OnImportsSatisfied()
{
this.PropertyChanged(this, new PropertyChangedEventArgs("MyList"));
}
}
The base class for the items, and some inherited test classes:
[InheritedExport]
public class MyItemBase
{
public MyItemBase()
{
}
public string ItemTitle{ get; set; }
}
public class MyItem1: MyItemBase
{
public MyItem1()
{
this.ItemTitle = "Item 1";
}
}
public class MyItem2: MyItemBase
{
public MyItem2()
{
this.ItemTitle = "Item 2";
}
}
This works IF I just remove the Lazy loading. However, I'll need to apply some export attributes later, which means going to Lazy.
the problem is that you want bind to a list of MyItembase object, but your actual binding is to a lazy arrray of MyItembase objects.(as long as you never call .Value for your lazy item nothing will happen)
i my projects i use a private lazy collection for mef and a normal ObservableCollection for wpf. btw i would prefer Constructor injection for your Mef import
public class TestVM : INotifyPropertyChanged, IPartImportsSatisfiedNotification
{
public TestVM()
{
//I'm using a static class to initiate the import
CompositionInitializer.SatisfyImports(this);
this.MyList = new ObservableCollection();
foreach(var lazyitem in _mefList)
{
this.MyList.Add(lazyitem.Value);
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public ObservbableCollection<MyItemBase> MyList{ get; set; }
[ImportMany(typeof(MyItemBase))]
private IEnumarable<Lazy<MyItemBase>> _mefList { get; set; }
public void OnImportsSatisfied()
{
//this.PropertyChanged(this, new PropertyChangedEventArgs("MyList"));
}
}
now I'm doing so Binding:
field:
private readonly RestaurantContext m_context = new RestaurantContext();
init:
m_context.Load(m_context.GetGroupQuery());
this.dataGridGroup.DataContext = m_context.Groups;
How do this in xaml ?
Juste expose your m_context, ensure that the class that encapsulate this property is set as the datacontext of your view and bind your dataGridGroup datacontext to your prperty.
For example :
public partial class Window1
{
public Window1()
{
InitializeComponent();
DataContext = new WindowViewModel();//this will set the WindowViewModel object below as the datacontext of the window
}
}
public class WindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void InvokePropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
public WindowViewModel()
{
restContext = new RestaurantContext();//init 1
restContext.Load(restContext.GetGroupQuery());//init 2
InvokePropertyChanged(new PropertyChangedEventArgs("RestContext"));//notify the view th update datacontext
}
private RestaurantContext restContext;
/// <summary>
/// Gets or sets the RestContext (which will be vound to the datagrid datacontext)
/// </summary>
public RestaurantContext RestContext
{
get { return restContext; }
set
{
if (RestContext != value)
{
restContext = value;
InvokePropertyChanged(new PropertyChangedEventArgs("RestContext"));
}
}
}
}
/// <summary>
/// Whatever class
/// </summary>
public class RestaurantContext
{
public void Load(object getGroupQuery)
{
//Whatever here
}
public object GetGroupQuery()
{
//Whatever here
return new object();
}
IEnumerable Groups { get; set; }
}
XAML :
<Window x:Class="StackOverflow.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Width="100" Height="100" >
<Grid>
<DataGrid DataContex="{Binding RestContext.Groups}"></DataGrid>
</Grid>
</Window>
In your XAML:
<DataGrid x:Name="dataGridGroup" DataContext={Binding Groups} />
It will automatically bind to the Groups property of your ViewModel
I have the Xaml which should basically bind a set of ContextualButtons for a selected tab's viewmodel to the ItemsSource property of the ToolBar. For some reason, this binding is not actually occuring unless I use Snoop to inspect the element manually...It seems that the act of snooping the element is somehow requerying the binding somehow.
Does anyone know what I might be doing wrong here? This behavior is the same if I use a Listbox as well, so I know it is something that I am doing incorrectly...but I am not sure what.
SelectedView is a bound property to the selected view from a Xam Tab control.
XAML
<ToolBar DataContext="{Binding SelectedView.ViewModel}"
ItemsSource="{Binding ContextualButtons}" >
<ToolBar.ItemTemplate>
<DataTemplate>
<!-- <Button ToolTip="{Binding Name}"-->
<!-- Command="{Binding Command}">-->
<!-- <Button.Content>-->
<!-- <Image Width="32" Height="32" Source="{Binding ImageSource}"/>-->
<!-- </Button.Content>-->
<!-- </Button>-->
<Button Content="{Binding Name}"/>
</DataTemplate>
</ToolBar.ItemTemplate>
</ToolBar>
Code
public class TestViewModel : BaseViewModel, IBulkToolViewModel
{
public TestViewModel()
{
ContextualButtons = new ObservableCollection<IContextualButton>()
{
new ContextualButton("Test Button",
new DelegateCommand<object>(
o_ => Trace.WriteLine("Called Test Button")), String.Empty)
};
}
public string Key { get; set; }
private ObservableCollection<IContextualButton> _contextualButtons;
public ObservableCollection<IContextualButton> ContextualButtons
{
get { return _contextualButtons; }
set
{
if (_contextualButtons == value) return;
_contextualButtons = value;
//OnPropertyChanged("ContextualButtons");
}
}
}
public partial class TestView : UserControl, IBulkToolView
{
public TestView()
{
InitializeComponent();
}
public IBulkToolViewModel ViewModel { get; set; }
}
public class ContextualButton : IContextualButton
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public ICommand Command { get; set; }
public string ImageSource { get; set; }
public ContextualButton(string name_, ICommand command_, string imageSource_)
{
Name = name_;
Command = command_;
ImageSource = imageSource_;
}
}
public class BulkToolShellViewModel : BaseViewModel, IBaseToolShellViewModel, IViewModel
{
private IBulkToolView _selectedView;
public IBulkToolView SelectedView
{
get
{
return _selectedView;
}
set
{
if (_selectedView == value) return;
_selectedView = value;
OnPropertyChanged("SelectedView");
}
}
public ObservableCollection<IBulkToolView> Views { get; set; }
public DelegateCommand<object> AddViewCommand { get; private set; }
public DelegateCommand<object> OpenPortfolioCommand { get; private set; }
public DelegateCommand<object> SavePortfolioCommand { get; private set; }
public DelegateCommand<object> GetHelpCommand { get; private set; }
public BulkToolShellViewModel(ObservableCollection<IBulkToolView> views_)
: this()
{
Views = views_;
}
public BulkToolShellViewModel()
{
Views = new ObservableCollection<IBulkToolView>();
AddViewCommand = new DelegateCommand<object>(o_ => Views.Add(new TestView
{
ViewModel = new TestViewModel()
}));
OpenPortfolioCommand = new DelegateCommand<object>(OpenPortfolio);
SavePortfolioCommand = new DelegateCommand<object>(SavePortfolio);
GetHelpCommand = new DelegateCommand<object>(GetHelp);
}
private void GetHelp(object obj_)
{
}
private void SavePortfolio(object obj_)
{
}
private void OpenPortfolio(object obj_)
{
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged()
{
throw new NotImplementedException();
}
public void RaisePropertyChanged(string propertyName)
{
throw new NotImplementedException();
}
public string this[string columnName]
{
get { throw new NotImplementedException(); }
}
public string Error { get; private set; }
public AsyncContext Async { get; private set; }
public XmlLanguage Language { get; private set; }
public string Key { get; set; }
}
Thanks!
Why does BulkToolShellViewModel have its own PropertyChanged event along with RaisePropertyChanged methods that do nothing? Shouldn't it inherit this functionality from BaseViewModel? Perhaps the UI is attaching to BulkToolShellViewModel.PropertyChanged rather than BaseViewModel.PropertyChanged and is never being notified of changes.
I've got a view
<UserControl x:Class="Modules.NavigationMenu.Views.NavigationMenuView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<StackPanel>
<Button Command="{Binding InspectionCommand}">Inspection</Button>
<Button Command="{Binding HandheldCommand}">Handheld</Button>
</StackPanel>
</UserControl>
and a simple view model - but the commands won't seem to fire - can anyone point me in the right direction please?
public class NavigationMenuViewModel : INavigationMenuViewModel
{
public INavigationMenuView View { get; set; }
public NavigationMenuViewModel(IEventAggregator eventAggregator, INavigationMenuView view)
{
View = view;
HandheldCommand = new DelegateCommand<object>(LaunchHandheld);
InspectionCommand = new DelegateCommand<object>(LaunchInspection);
}
private void LaunchInspection(object obj)
{
MessageBox.Show("Inspection Clicked");
}
private void LaunchHandheld(object obj)
{
MessageBox.Show("Handheld Clicked");
}
public DelegateCommand<object> HandheldCommand { get; set; }
public DelegateCommand<object> InspectionCommand { get; set; }
}
My Module just looks like ...
public class NavigationMenuModule : IModule
{
private readonly IUnityContainer _container;
private readonly IRegionManager _regionManager;
public NavigationMenuModule(IUnityContainer container, IRegionManager regionManager)
{
_container = container;
_regionManager = regionManager;
}
#region Implementation of IModule
public void Initialize()
{
RegisterViewsAndServices();
var viewModel = _container.Resolve<INavigationMenuViewModel>();
_regionManager.Regions[RegionNames.MainMenu].Add(viewModel.View);
}
#endregion
#region Protected Methods
protected void RegisterViewsAndServices()
{
_container.RegisterType<INavigationMenuView, NavigationMenuView>();
_container.RegisterType<INavigationMenuViewModel, NavigationMenuViewModel>();
}
#endregion
}
Are you sure that the command binding is working? If you run the app and look in the debug output panel, do you see any binding warnings? Perhaps the DataContext of your UserControl isn't set to your NavigationMenuViewModel.