WPF C# get Object properties without adding extra variables into the viewmodel - c#

I'm curently trying to implemnt a Combobox binding to a list and some labels showing the details of a selected object. The binding to the Combobox works without any problems but I don't want to add extra variables into my ViewModel just to display the name and speed of my car objects.
Is there any way to Map the object variables of the selected combobox item on to the labels without adding additional variables into my ViewModel?
That's the code I'm currently working with
MainWondow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace StackOF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ViewModel viewModel;
public MainWindow()
{
viewModel = new ViewModel();
DataContext = viewModel;
InitializeComponent();
}
}
}
ViewModel.cs
using _02_WPFCarInfo.AutoKlassen;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace StackOF
{
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<AutoModel> _autoModels;
private AutoModel selectedModel;
public ObservableCollection<AutoModel> AutoModels
{
get { return _autoModels; }
set
{
_autoModels = value;
OnPropertyChanged();
}
}
public AutoModel SelectedModel
{
get { return selectedModel; }
set
{
selectedModel = value;
OnPropertyChanged();
}
}
public ViewModel()
{
_autoModels = generateCars();
}
private ObservableCollection<AutoModel> generateCars()
{
AutoModel model1 = new AutoModel();
AutoModel model2 = new AutoModel();
AutoModel model3 = new AutoModel();
model1.name = "Mercedes C12 Pro";
model1.speed = "125 km\\h";
model2.name = "Audi A12";
model2.speed = "236 km\\h";
model3.name = "Audi S20 Pro";
model3.speed = "300 km\\h";
ObservableCollection<AutoModel> cars = new ObservableCollection<AutoModel>();
cars.Add(model1);
cars.Add(model2);
cars.Add(model3);
return cars;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MainWindow.xaml
<Window x:Class="StackOF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StackOF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ComboBox SelectedItem="{Binding SelectedModel}" DisplayMemberPath="name" ItemsSource="{Binding AutoModels}" HorizontalAlignment="Center" Margin="0,164,0,0" VerticalAlignment="Top" Width="212"/>
<Label Content="Name:" HorizontalAlignment="Left" Margin="294,231,0,0" VerticalAlignment="Top"/>
<Label Content="Speed:" HorizontalAlignment="Left" Margin="294,262,0,0" VerticalAlignment="Top"/>
<TextBlock HorizontalAlignment="Center" Margin="0,241,0,0" TextWrapping="Wrap" Text="---" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
<TextBlock HorizontalAlignment="Center" Margin="0,267,0,0" TextWrapping="Wrap" Text="---" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
</Grid>
</Window>
AutoModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _02_WPFCarInfo.AutoKlassen
{
public class AutoModel
{
public String name { get; set; }
public String speed { get; set; }
public AutoModel()
{
this.speed = String.Empty;
this.name = String.Empty;
}
public AutoModel(String name, String speed)
{
this.speed = speed;
this.name = name;
}
}
}
I thought about something like :
<TextBlock HorizontalAlignment="Center" Margin="0,241,0,0" TextWrapping="Wrap" Text="{Binding SelectedModel.name}" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
<TextBlock HorizontalAlignment="Center" Margin="0,267,0,0" TextWrapping="Wrap" Text="{Binding SelectedModel.speed}" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
But obviously it is not possible to select the variables of "SelectedModel" that way.

Ok nvm it DOES work. It only does not work if you have a textblock with opening and closing tag with text inbetween
This works:
<TextBlock HorizontalAlignment="Center" Margin="0,241,0,0" TextWrapping="Wrap" Text="{Binding SelectedModel.name}" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
but this doesn't
<TextBlock HorizontalAlignment="Center" Margin="0,241,0,0" TextWrapping="Wrap" Text="{Binding SelectedModel.name}" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303">---</TextBlock>

Related

WPF ComboBox selection causes selection in second ComboBox

I'm binding two comboboxes to the same listviewcollection. The problem is that selecting a value in one combobox, causes the other combobox selected item to change to the exact value of the first combobox. They are coupled and I want them to be independent of each other.
MyListViewCollection is like this
modelsView = new ListCollectionView(MainVM.All_Models);
All_Models is an Observable collection of custom objects like this
public ObservableCollection<MLModel> All_Models { get; set; } = new ObservableCollection<MLModel>() { };
I bind two ComboBoxes to modelsview like this
<ComboBox ItemsSource="{Binding Path=modelsView}" SelectedItem="{Binding SelectedModel_Right}" SelectionChanged="RightSideModelSelection">
<ComboBox ItemsSource="{Binding Path=modelsView}" SelectedItem="{Binding SelectedModel_Left}" SelectionChanged="LeftSideModelSelection">
So everything works fine, the comboboxes contain the identical lists of items from the models view which is what I want.
I definitely have bound the selected item to two separate properties in the view model, and those are
private MLModel _selectedModel_left;
public MLModel SelectedModel_Left
{
get { return _selectedModel_left; }
set
{
SetProperty(ref _selectedModel_left, value);
}
}
private MLModel _selectedModel_right;
public MLModel SelectedModel_Right
{
get { return _selectedModel_right; }
set
{
SetProperty(ref _selectedModel_right, value);
}
}
The only thing I can think of is that they are both referencing the same object in the collection, but I'm not exactly sure how it causes this behavior.
Also the desired behavior is that each combobox be able to select and display a different item from the same collection.
Any explanation would be helpful as well as the recommended way to decouple the two comboboxes selection from each other.
EDIT: As requested here is the code to create a minimal working example
MainWindow.xaml
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication3"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation="Vertical">
<ComboBox ItemsSource="{Binding Path=modelsView}" SelectedItem="{Binding SelectedModel_Left}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox ItemsSource="{Binding Path=modelsView}" SelectedItem="{Binding SelectedModel_Right}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication3
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
}
MLModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApplication3
{
public class MLModel
{
public string Name { get; set; }
public string Type { get; set; }
}
}
ViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace WpfApplication3
{
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ViewModel()
{
modelsView = new ListCollectionView(All_Models);
//modelsView.Filter = modelsFilter;
}
public ListCollectionView modelsView { get; set; }
public ObservableCollection<MLModel> All_Models { get; set; } = new ObservableCollection<MLModel>() {
new MLModel() { Name = "One", Type = "TypeOne" },
new MLModel() {Name = "Two", Type = "TypeTwo" },
new MLModel() {Name = "Three", Type = "TypeThree" }
};
private MLModel _selectedModel_left;
public MLModel SelectedModel_Left
{
get { return _selectedModel_left; }
set
{
this._selectedModel_left = value;
NotifyPropertyChanged();
}
}
private MLModel _selectedModel_right;
public MLModel SelectedModel_Right
{
get { return _selectedModel_right; }
set
{
this._selectedModel_right = value;
NotifyPropertyChanged();
}
}
}
}
From the documentation:
If the target is an ItemsControl, the current item is synchronized with the selected item.
You are sharing the same ListCollectionView between both ComboBox objects. This means that the current selected item is updated in the view, and replicated in any other ItemsControl where that same view is used.
If you don't want this behavior, you need to give each ComboBox its own ListCollectionView object to bind to.
Alternatively, you can set the IsSynchronizedWithCurrentItem property of each ComboBox to false.

Get value from a Combobox Binding MVVM not get correctly

Hi i made a bindable combobox with MVVM and when i'm trying to get the value of combobox it gets the path of the value ex:I select a name and it return WpfApp1.Parts .
How can i get the name from combobox as string?
And if enyone know how can i save the combobox that when i add a new value , like when i enter again on the program my last entered value to be there!
View.Parts:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
namespace WpfApp1
{
public class Parts : Changed
{
public string name;
public string Name
{
get { return name; }
set
{
if (name != value)
{
name = value;
RaisePropertyChanged("Name");
}
}
}
}
}
ViewModel.AddViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace WpfApp1
{
public class AddViewModel : Changed
{
private ObservableCollection<Parts> _persons;
public string names;
public AddViewModel()
{
Persons = new ObservableCollection<Parts>()
{
new Parts{Name="Nirav"}
,new Parts{Name="Kapil"}
,new Parts{Name="Arvind"}
,new Parts{Name="Rajan"}
};
}
public ObservableCollection<Parts> Persons
{
get { return _persons; }
set {
if (_persons != value)
{
_persons = value;
RaisePropertyChanged("Persons");
}
}
}
private Parts _sperson;
public Parts SPerson
{
get { return _sperson; }
set {
if (_sperson != value)
{
_sperson = value;
RaisePropertyChanged("SPerson");
}
}
}
}
}
MainWindow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public AddViewModel addviewmodel;
public MainWindow()
{
InitializeComponent();
addviewmodel = new AddViewModel();
DataContext = addviewmodel;
}
public AddViewModel getModel()
{
return addviewmodel;
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//textshow.Text = holo.SelectedItem;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
getModel().Persons.Add(new Parts { Name = cmbtxt.Text});
}
}
}
MainWindowXaml:
<Grid>
<ComboBox x:Name="holo" ItemsSource="{Binding Persons}" SelectedItem="{Binding SPerson}" SelectionChanged="ComboBox_SelectionChanged" HorizontalAlignment="Left" Margin="391,17,0,0" VerticalAlignment="Top" Width="314" Height="27">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBox Name="cmbtxt" HorizontalAlignment="Left" Height="23" Margin="24,21,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="172" />
<Button Content="Add" HorizontalAlignment="Left" Margin="24,88,0,0" VerticalAlignment="Top" Width="156" Height="49" Click="Button_Click"/>
<TextBlock x:Name="textshow" HorizontalAlignment="Left" Text="{Binding Path=SPerson}" TextWrapping="Wrap" VerticalAlignment="Top" Margin="391,104,0,0" Height="33" Width="223"/>
</Grid>
You should bind to the Name property of the selected item returned by the SPerson property:
<TextBlock x:Name="textshow" HorizontalAlignment="Left"
Text="{Binding Path=SPerson.Name}"
TextWrapping="Wrap" VerticalAlignment="Top"
Margin="391,104,0,0" Height="33" Width="223"/>
What you currently see is the ToString() representation of the Parts class so the other option would to override this method:
public class Parts : Changed
{
public string name;
public string Name
{
get { return name; }
set
{
if (name != value)
{
name = value;
RaisePropertyChanged("Name");
}
}
}
public override string ToString()
{
return name;
}
}
The error is here
<TextBlock x:Name="textshow" HorizontalAlignment="Left" Text="{Binding Path=SPerson}"
You cannot bind Text property to complex Object like Parts you should bind it to the Name as you did with ComboBox

Binding a subclass in c#/WPF (DataContext = obj) (Binding subclass.var}

I want to use databinding in c#/WPF. Creating an object and using it as datacontext already works with its variables.
But I want to create classes in the datacontext object and use these variables.
The right binding should work with ....{Binding Path=Eyeobj.Farbe}....
Is the problem on the DataContenxt, class or the WPFs side?
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace DataContextDemo
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Person obj = new Person()
{
FirstName = "John",
LastName = "Smith",
Age = 30
};
public MainWindow()
{
InitializeComponent();
this.DataContext = obj;
}
}
}
MainWindow.xaml
<Window x:Class="DataContextDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DataContextDemo"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBlock Margin="4" Text="First Name" VerticalAlignment="Center"/>
<TextBox Margin="4" Text="{Binding Path= FirstName}" Grid.Column="1"/>
<TextBlock Margin="4" Text="Last Name" Grid.Row="1" VerticalAlignment="Center"/>
<TextBox Margin="4" Text="{Binding Path= LastName}" Grid.Column="2" Grid.Row="1"/>
Person.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace DataContextDemo
{
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Augen Eyeobj = new Augen("Red");
//public PropertyChangedEventHandler handler = PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string FirstName
{
get
{
return this.firstName;
}
set
{
this.firstName = value;
NotifyPropertyChanged();
}
}
public string LastName
{
get
{
return this.lastName;
}
set
{
this.lastName = value;
NotifyPropertyChanged();
}
}
public int Age
{
get
{
return this.age;
}
set
{
this.age = value;
NotifyPropertyChanged();
}
}
private string firstName { get; set; }
public string lastName { get; set; }
public int age { get; set; }
}
}
<TextBlock Margin="4" Text="Age" Grid.Row="2" VerticalAlignment="Center"/>
<TextBox Margin="4" Text="{Binding Path = Eyeobj.Farbe}" Grid.Column="3" Grid.Row="2"/>
<TextBlock Margin="3" Text="{Binding Path=Eyeobj.Farbe}" Grid.Row="2" Grid.Column="3" x:Name="testbox"></TextBlock>
<Button Margin="4" Grid.Row="3" Click="Button_Click"></Button>
</Grid>
</Window>
Augen.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace DataContextDemo
{
public class Augen : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string farbe = "Blau";
public Augen(string farbe)
{
Farbe = farbe;
}
//public PropertyChangedEventHandler handler = PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string Farbe
{
get
{
return this.farbe;
}
set
{
this.farbe = value;
NotifyPropertyChanged();
}
}
}
}
You use your Eyeobj as a field - it won't be visible from the view. Make the property, as you've done with the FirstName for example, implementing INotifyPropertyChanged.
private Augen _eyeobj;
public Augen Eyeobj
{
get
{
return _eyeobj;
}
set
{
if(_eyeobj != value)
{
_eyeobj = value;
NotifyPropertyChanged("Eyeobj");
}
}
}

WPF C# ComboBox with multiple lines and accepting returns?

Is there an easy way to do a multiline combobox in WPF C#? What do I mean by this? I mean a textbox that supports multiple lines and carriage returns; where it word wraps... It needs to have a scrollbar so that if the text in the box is taller than the height of the combobox, the user can scroll down.
In addition, because its a combobox, it needs to have a dropdown button so that the user can quickly swap between groups of text. I've tried googling for this, but I can't find anyone talking about such a combobox.
EDITED FOR COMPLETE WORKING SOLUTION:
XAML:
<Window x:Class="delete.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">
<Grid>
<ComboBox Height="30" Width="300" ItemsSource="{Binding items}" SelectedItem="{Binding item}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBox AcceptsReturn="True" TextWrapping="Wrap" Width="250" Height="30" Text="{Binding Name}" VerticalScrollBarVisibility="Auto"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>
Code-behind:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace delete
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
Setup();
this.DataContext = this;
}
ObservableCollection<Thang> _items;
public ObservableCollection<Thang> items
{
get { return _items; }
set
{
_items = value;
OnPropertyChanged("items");
}
}
private Thang _item;
public Thang item
{
get { return _item; }
set
{
_item = value;
OnPropertyChanged("item");
}
}
public void Setup()
{
items = new ObservableCollection<Thang>();
items.Add(new Thang("1", "One"));
items.Add(new Thang("2", "Two"));
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public class Thang
{
public Thang(string id, string name)
{
Name = name;
ID = id;
}
public string Name { get; set; }
public string ID { get; set; }
}
}

I cant have two different datasources to bind to my different panorama Items

i have created two different classes for two different binding sources . Model1.cs and Model2.cs .
Model1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MultiBindingTest
{
class Model1
{
public string str1 { get; set; }
public string str2 { get; set; }
public Model1(string one , string two)
{
str1 = one;
str2 = two;
}
}
}
Model2.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MultiBindingTest
{
class Model2
{
public string one { get; set; }
public string two { get; set; }
public Model2 (string str1 , string str2)
{
one = str1;
two = str2;
}
}
}
i have two other classes which i want them to be the data source , they are named vm1.cs and vm2.cs ; vm1 has an observable collection of the class type Model1 and Vm2 has an observable collection of class type model2 that i fill with data in their constructor .
Vm1.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MultiBindingTest
{
class vm1:NotificationObject
{
private static ObservableCollection<Model1> _testVM1;
public static ObservableCollection<Model1> TestVM1
{
get { return _testVM1; }
set { _testVM1 = value; }
}
public vm1()
{
TestVM1 = new ObservableCollection<Model1>();
TestVM1.Add(new Model1("1", "Model1"));
TestVM1.Add(new Model1("2", "Model1"));
TestVM1.Add(new Model1("3", "Model1"));
}
}
}
VM2.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MultiBindingTest
{
class vm2:NotificationObject
{
private static ObservableCollection<Model2> _testVM2;
public static ObservableCollection<Model2> TestVM2
{
get { return _testVM2; }
set { _testVM2 = value; }
}
public vm2()
{
TestVM2 = new ObservableCollection<Model2>();
TestVM2.Add(new Model2("1", "Model2"));
TestVM2.Add(new Model2("2", "Model2"));
TestVM2.Add(new Model2("3", "Model2"));
}
}
}
NotificationObject
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MultiBindingTest
{
public class NotificationObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
i want to bind Vm1 to be the datacontext of panoramaitem1 and vm2 to be the datacontext of panoramaItem2 so i can bind the longlistselector items in each . but i get an xamlParseException , what am i doing wrong.
MainPage Xaml
<phone:PhoneApplicationPage
x:Class="MultiBindingTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MultiBindingTest"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<phone:Panorama x:Name="mainPanorama"
Title="Binding Test Application">
<phone:PanoramaItem x:Name="ItemOne"
Header="Item One">
<phone:LongListSelector>
<phone:LongListSelector.DataContext>
<local:vm1 />
</phone:LongListSelector.DataContext>
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=str1}"/>
<TextBlock Text="{Binding Path=str2}" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</phone:PanoramaItem>
<phone:PanoramaItem x:Name="ItemTwo"
Header="Item Two">
<phone:LongListSelector>
<phone:LongListSelector.DataContext>
<local:vm2 />
</phone:LongListSelector.DataContext>
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=one}" />
<TextBlock Text="{Binding Path=two}" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</phone:PanoramaItem>
</phone:Panorama>
</phone:PhoneApplicationPage>
Additional Information
All the classes are in the same namespace
XamlParseException
System.Windows.Markup.XamlParseException occurred
HResult=-2146233087
Message=Cannot create instance of type 'MultiBindingTest.vm1' [Line: 23 Position: 33]
Source=System.Windows
LineNumber=23
LinePosition=33
StackTrace:
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at MultiBindingTest.MainPage.InitializeComponent()
at MultiBindingTest.MainPage..ctor()
InnerException:
Make your viewmodel classes public:
public class vm1:NotificationObject{...}
public class vm2:NotificationObject{...}

Categories

Resources