How to bind objects list to infragistics data grid? - wpf

Pretty simple task, but the source code doesn't do required job... Please advise.
There is Products collection in the class (approach is based on the MVVm pattern, but that is not influe on the current issue):
public class ProductWindowViewModel : WorkspaceViewModel // implements INotifyPropertyChanged
{
public ProductWindowViewModel()
{
Products = new List<Product>(ProductService.Instance.Repository.GetAll());
}
List<Product> Products { get; set; }
}
Here is class declaration:
public class Product : IEntity
{
#region Public Properties
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int Cost { get; set; }
#endregion
}
The class instance is binded to the window's Grid data context:
ProductWindow wnd = new ProductWindow();
wnd.MainGrid.DataContext = new ProductWindowViewModel();
wnd.ShowDialog();
And here is xaml code of the window:
<Window x:Class="WpfTest1.ProductWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ProductWindow" Height="300" Width="300" xmlns:igDP="http://infragistics.com/DataPresenter"
xmlns:ViewModel="clr-namespace:ViewModel;assembly=ViewModel">
<Grid x:Name="MainGrid">
<Grid.Resources>
<ObjectDataProvider x:Key="odpObjectDataProvider" ObjectType="{x:Type ViewModel:ProductWindowViewModel}" />
</Grid.Resources>
<Grid DataContext="{StaticResource odpObjectDataProvider}">
<igDP:XamDataGrid DataSource="{Binding Path=Products}"/>
</Grid>
</Grid>
The xamDataGrid sampe is the same. overall code is pretty simple, but doesn't work.
Does anybody know why? Any thoughts are welcome.
How could I debug binding to resolve the problem himselft?
Thanks.

Ok, maybe this won't exactly answer your question, but it looks like you are instantiating your viewmodel class twice. Once in your code, immediately after creating your window, and once in the ObjectDataProvider thing. It will probably be easier to debug if you settle on one of them. Suggestion:
1. Comment out this line: wnd.MainGrid.DataContext = new ProductWindowViewModel();
2. Set a breakpoint inside the constructor of your viewmodel
3. Start it up and see if the breakpoint gets hit. If it does get hit, you know you are doing something right.
Also, check the output window in visual studio and see if any binding exceptions are reported there.

In my case the code in the windows constructor is redundant. Now all is working, seems like removing unnecessary assignement resolved an issue.

Related

Setting UserControl ViewModel Property

All -
I am using Unity in my WPF application for DI (without prism). I have my MainWindow.xaml and MainWindowViewModel.cs. I have a usercontrol in my Mainwindow.xaml. The user control has its own uc1.xaml and uc1viewmodel.cs. The UC1 ViewModel is currently exposed as a property on MainWindowViewModel so I can set the datacontext on the usercontrol (as recommended by many ppl here).
The question I have is how/where can I set this property - will it be in app.xaml.cs or will it be in the constructor of mainwindowviewmodel. Code Snippets:
App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//Step 1 - One Time - Creating an instance of the container
UnityContainer unity = new UnityContainer();
//Step 2 - Registering your MainWindowViewModel
unity.RegisterType<IViewModel, UserControl1ViewModel>();
//Step 3 - Creating an Instance
UserControl1ViewModel uc1_mwvm = unity.Resolve<UserControl1ViewModel>(); <-- doesnt help
MainWindowViewModel mwvm = unity.Resolve<MainWindowViewModel>();
MainWindow mw = unity.Resolve<MainWindow>();
mw.Show();
}
MainWindowViewModel.cs
public class MainWindowViewModel
{
public IViewModel IVM { get; set; }
public MainWindowViewModel()
{
//IVM = new UserControl1ViewModel(); <-- All I really want is an equivalent but letting Unity do the work.
}
}
MainWindow.xaml
<Window x:Class="_05_ViewFist_UC_Unity_Working.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc1="clr-namespace:_05_ViewFist_UC_Unity_Working"
xmlns:uc2="clr-namespace:_05_ViewFist_UC_Unity_Working"
Title="MainWindow" Height="350" Width="525">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding NNN}" />
<uc1:UC1 DataContext="{Binding UC1VM}" />
<uc2:UC2 DataContext="{Binding UC2VM}" />
</StackPanel>
</Window>
UC1
<UserControl x:Class="_05_ViewFist_UC_Unity_Working.UC1"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" >
<StackPanel Orientation="Horizontal" Background="Red">
<TextBlock Text="UC1 " />
<TextBlock Text="{Binding FirstName}" />
</StackPanel>
</UserControl>
As you see from the code - Instance of UC1 is created in xaml (MainWindow.xaml) and hence when MainWindow instance is created in app.xaml.cs - it still doesnt create an instance of UserControl1ViewModel.
Question again is : Dont think its a good practice for me to call the Unity Resolve statement in the constructor of MainwindowViewModel. Is that correct??
Can somebody share a code snippet of how/where I can do this?
Thanks
I downloaded your solution from github and tried to solve your problem.
You did a great job just you forgot few details such as property attributes.
This is how your App.cs file shall look alike:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//Step 1 - One Time - Creating an instance of the container
UnityContainer unity = new UnityContainer();
//Step 2 - Registeration
unity.RegisterType<IMainWindowViewModel, MainWindowViewModel>();
unity.RegisterType<IUC1ViewModel, UC1ViewModel>();
unity.RegisterType<IUC2ViewModel, UC2ViewModel>();
//// Instance of MainWindowViewModel will be created once you call Resolve MainWindow.
MainWindow mw = unity.Resolve<MainWindow>();
mw.Show();
}
Here is what I changed:
public class MainWindowViewModel : IMainWindowViewModel
{
#region Public Properties
[Dependency]
public IUC1ViewModel UC1VM { get; set; }
[Dependency]
public IUC2ViewModel UC2VM { get; set; }
public string NNN { get; set; }
#endregion
public MainWindowViewModel()
{
NNN = "This value coming from MainWindowViewModel";
}
}
[Dependency] is a property attibute that tells Unity where to inject values.
I could merge my code to your repo in github if you wish so.
Let me know if this helped you any futher. Feel free to mark this as the answer.
You can use the service locator pattern. I use it with Unity as a DI.
internal class ServiceLocator
{
[...]
public MainViewModel Main { get { return container.Resolve<MainViewModel>(); } }
}
You can intantiate your class the way you want (DI or not, the class initializes the DI or receive it as a parameter, you can store the DI in a private static property, you can initialize your class if DI is null or when the application starts etc...).
In your App.xaml
<Application.Resources>
<vm:ServiceLocator x:Key="Locator"/>
</Application.Resources>
And now, you can set your datacontext
DataContext="{Binding Main, Source={StaticResource Locator}}"
Edit:
I found another way of doing it (among other):
Take a look at this article. In the command, you can resolve your viewmodel as you like.

How to access a KinectSensorchooser object on an xaml file in a different cs file?

I am a beginner in WPF and c#.I am trying to create an application using Kinect for Windows. I have a kinectsensorchooser in my Kinect.cs and it controls the SensorChooser in the MainWindow.xaml
But I am not sure how to control it.
My code is as follows:
MainWindow.xaml
<Canvas>
<k:KinectSensorChooserUI KinectSensorChooser="{Binding SCkinectSensorChooser} "Name="sensorChooserCP"/>
<k:KinectUserViewer k:KinectRegion.KinectRegion="{Binding kinectRegionCP}"/>
<k:KinectRegion Name="kinectRegionCP" KinectSensor="{Binding ElementName=SCkinectsensor}">
<Grid>
some kinect tile buttons come in here...
</Grid>
</k:KinectRegion>
</Canvas>
Kinect.cs
public KinectSensor SCkinectsensor;
public KinectSensorChooser SCkinectSensorChooser;
the values of the two objects will be set dynamically during the program execution. I want these changes to be reflected in the MainWindow
App.xaml
<Application x:Class="Kinect.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
xmlns:local="clr-namespace:Kinect">
<Application.Resources>
<local:Kinect x:Key="Kinect" />
</Application.Resources>
I am doing something wrong and the code is not responding as I wish... What should I do? I need help
Are you setting your DataContext in the main window? If not, your Binding will do nothing.
MainWindow.xaml
<Window x:Class="Kinect.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{StaticResource Kinect}">
...
</Window>
Another thing to note, is that in WPF, you can only bind to properties.
Kinect.cs
public KinectSensor SCkinectsensor { get; private set; }
public KinectSensorChooser SCkinectSensorChooser { get; private set; }
If you expect these properties to change outside of the constructor, then this class needs to implement INotifyPropertyChanged, and your properties would look like this:
private KinectSensor kinectSensor;
public KinectSensor SCkinectSensor
{
get { return kinectSensor; }
set
{
kinectSensor = value;
PropertyChanged(this, new PropertyChangedEventArgs("SCkinectSensor");
}
}

Add member method as a resource

I'm implementing a class that contains an ObservableCollection and in my XAML I have a polyline.
I successfully binded the XAML dataContext to the this class and the polyline to the Observable collection. But now, of course, I'm facing a wrong type conversion.
I found an example of value converter and I added it to my code but I'm not able to add it as a resource in my XAML ...
The overall structure looks like that
public class externalClass
{
public ObservableCollection<Point> debugCh1 { get; set; }
public void test()
{
... performo modifications
on debugCh1 for testing purposes...
}
public class PointCollectionConverter : IValueConverter
{
.. implements convert and cnverBack
}
}
For the XAML
<Window x:Class="tester.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="277" Width="525" xmlns:my="clr-namespace:binding;assembly=binding" xmlns:my1="clr-namespace:deviceManager;assembly=deviceManager" Closing="Window_Closing">
<Window.Resources>
<local:PointCollectionConverter x:Key="pointCollectionConverter"/>
</Window.Resources>
... The window Itself ...
<Polyline Points="{Binding debugCh1}" />
...
</Window>
And for the C# behind
public partial class MainWindow : Window
{
private externalClass toTest;
public MainWindow()
{
InitializeComponent();
DataContext = toTest;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
toTest.test();
}
}
The whole thing works nice but for the <local:PointCollectionConverter..
Compiler says The type 'local:PointCollectionConverter' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built.
Any suggestions on how to add this reference??
You just have to make sure the namespaces are lined up. I'd start by separating your converter class from the externalClass class (I'm not sure it's even possible to reference nested-classes like that from XAML):
namespace MyCompany.MyProject
{
public class PointCollectionConverter : IValueConverter
{
.. implements convert and cnverBack
}
}
Now you can define the local xmlns and link it to MyCompany.MyProject:
<Window xmlns:local="clr-namespace:MyCompany.MyProject"
And with that the converter should be accessible as written.
<local:PointCollectionConverter x:Key="pointCollectionConverter"/>

Binding a save command WPF

I have a window with 3 textboxes in a grid -this is my view- and I have Save button to add a new user to my user list with the datas from the textboxes.
I want to use a relay command to do this on my viewmodel class but I am quite confused with how to make the bindings. I hope it's clear enough. Any ideas, or examples will be helpful.
thanks in advance.
You should have a ViewModel something like the following :
class UserViewModel
{
public String Name { get; set; }
public String Password { get; set; }
public String Email { get; set; }
public RelayCommand AddUserCommand { get; set; }
public UserViewModel()
{
AddUserCommand = new RelayCommand(AddUser);
}
void AddUser(object parameter)
{
// Code to add user here.
}
}
And you can use it like following :
<StackPanel>
<TextBox Text="{Binding Name}"></TextBox>
<TextBox Text="{Binding Password}"></TextBox>
<TextBox Text="{Binding Email}"></TextBox>
<Button Command="{Binding AddUserCommand}">Add</Button>
</StackPanel>
To make this work, put following code in your UserControl/Control/Window's constructor :
DataContext = new UserViewModel();
I presume that you read Josh Smith article: WPF Apps With The Model-View-ViewModel Design Pattern. If you didn't, then read it first, and then download code, because example is very similar to your problem.
Did you created an instance of the ViewModel and putted this instance in the DataContext of your view or stackpanel?
example:
UserViewModel viewModel = new UserViewModel();
UserWindow view = new UserWindow();
view.DataContext = viewModel;
view.Show();
There are several options on coupling the View and the Viewmodel:
Create the View and ViewModel and set the ViewModel to the DataContext property (code above)
Create the ViewModel in the constructor of the View and fill the DataContext property with it
Create a Resource in your view of the type of your ViewModel and fill the DataContext property in XAML
I prefer the first option because you can combine the Views and Viewmodels as you like at runtime.
Hopefully this is a helpfull answer.

Binding Enum[] to ListBox

I have next enumeration
Enum rcCategory
{
Incoming,
Internal,
Outgoing
}
and I have property "categories" in my class which has rcCategory[] type.
I would like to bind this property to the listBox. I use next code for this
MyListBox.SetBinding (ListBox.ItemsSource, new Binding {Source= myClass.categories});
But this code doesnt work as expected.
How Can I do this. My listBox always is empty but source property has value
See Bea Stollnitz top ranked article on it.
In short you need to bind to an ObjectProvider which calls the static method Enum.GetValues( typeof(YourEnum) ) to return the list.
http://bea.stollnitz.com/blog/?p=28
Update: Sorry got a slight speedreading issue. This one is easier.. Verified that it works. Recommended: Find up a copy of ProgrammingWPF and go thru the DataBinding chapter...
XAML:
<ListBox DockPanel.Dock="Left" ItemsSource="{Binding EnumArrayProp}"/>
Codebehind:
public partial class Window1 : Window
{
public rcCategory[] EnumArrayProp
{
get; set;
}
public Window1()
{
InitializeComponent();
this.EnumArrayProp = new rcCategory[] { rcCategory.Incoming, rcCategory.Incoming, rcCategory.Outgoing };
this.DataContext = this;
}

Resources