I have a DataGrid with two way binding and not sure why this does not work, any help would be appreciated.
I wanted to dynamically bind to the DataGrid using a twoway binding object.
I used the columns in XAML. If I just set the 'ItemSource" property directly - it works but then the two binding doesn't work - if I change my source in code the Grid doesn't reflect that change.
I created a simple sample to illustrate my setup
Here is the XAML
<UserControl x:Class="SilverlightApplication1.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="356" d:DesignWidth="590" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Grid x:Name="LayoutRoot" Background="White">
<sdk:DataGrid AutoGenerateColumns="False" Height="136" HorizontalAlignment="Left" Margin="71,116,0,0" Name="MyGrid" VerticalAlignment="Top" Width="453" >
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding Path=Label, Mode=TwoWay}" CanUserReorder="True" CanUserResize="True" CanUserSort="True" Width="Auto" Header="Selected" />
<sdk:DataGridTextColumn Binding="{Binding Path=YValue, Mode=TwoWay}" CanUserReorder="True" CanUserResize="True" CanUserSort="True" Header="Name" Width="*" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
</UserControl>
Here is the code behind
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
ObservableCollection<Value> values = new ObservableCollection<Value>();
values.Add(new Value() { Label = "Sony", YValue = 50 });
values.Add(new Value() { Label = "Dell", YValue = 35 });
values.Add(new Value() { Label = "HP", YValue = 27 });
values.Add(new Value() { Label = "HCL", YValue = 17 });
values.Add(new Value() { Label = "Toshiba", YValue = 16 });
PagedCollectionView p = new PagedCollectionView(values);
Binding b = new Binding("ValuesBinding");
b.Mode = BindingMode.TwoWay;
b.Source = values;
MyGrid.SetBinding(DataGrid.ItemsSourceProperty, b);
}
}
public class Value : INotifyPropertyChanged
{
public String Label
{
get
{ return _label; }
set
{
_label = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Label"));
}
}
public Double YValue
{
get
{return _yValue;}
set
{
_yValue = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("YValue"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
Double _yValue;
String _label;
}
}
There are a couple of problems that I can see here.
The first line that you use to create your binding is
Binding b = new Binding("ValuesBinding");
This won't do what you want. The string ValuesBinding is being used as a property-path, and the ObservableCollection you're binding the DataGrid to has no property on it named ValuesBinding. Indeed, if you look in the VS Output window, you should see a message such as
System.Windows.Data Error: BindingExpression path error: 'ValuesBinding' property not found on 'System.Collections.ObjectModel.ObservableCollection`1 ...
However, if you remove "ValuesBinding" from the above to leave you with
Binding b = new Binding();
then you get an error about two-way bindings needing a Path. However, you don't need a two-way binding here. You can simply remove the line b.Mode = BindingMode.TwoWay; and the error goes away.
Two-way bindings are used to allow the view-layer to set properties in the view-model layer. The Path specifies where to find the view-model property to set. However, since you're binding straight to a collection, there's no property involved and hence nothing that the view-layer could set.
In your case, this binding doesn't need to be two-way. Changes to the collection itself (e.g. adding or removing items) can still be made, even when using a one-way binding for the ItemsSource. The two-way bindings you have on the Label and YValue properties of your Value class will also work as you expect. Setting a one-way binding on the DataGrid's ItemsSource doesn't make the whole grid read-only.
Finally, I'm not sure why you're creating a binding in code-behind to bind to a collection already available in the code-behind. You can achieve the same by just writing
MyGrid.ItemsSource = values;
Related
I'm making a Window to manage the users who using laptop. I have the window named "LaptopWindow" which contain a TextBox to display the user id of the one using it. I have made a button to open new UserControl named "FindEmployeeUC" to find the "EmpID" by select the row in DataGrid of UserControl and pass it back to the TextBox in "LaptopWindow".
I got the selected row of the DataGrid and use the property name "SelectedUA" to hold it inside the view model "UserAccountViewModel".
When OnPropertyChanged event fire I call the instance of "LaptopManagementViewModel" (this view model is bound with "LaptopWindow") and set the EmpID to the TextBox in "LaptopWindow" by the property named "ReceiverID"
The property "ReceiverID" got value but the UI of "LaptopWindow" didn't get update.
I tried to use Delegate, Singleton pattern, It had the same result.
Here is some code to explain more what I'm facing
The "LaptopWindow" xaml:
<StackPanel Grid.Row="2" Grid.Column="1" Style="{StaticResource inputControl}">
<TextBlock Text="Người nhận"/>
<TextBox Name="txtReceiver" Text="{Binding ReceiverID,Source={StaticResource vmLaptopManagement}}" Margin="0,0,30,0"/>
</StackPanel>
<!--Button open FindEmpUC -->
<Button Grid.Row="2" Grid.Column="1" Width="30" Height="29" HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="Transparent" Margin="0,4,4,4" Command="{Binding CmdFindEmp}">
<Image Source="/imgs/find-48.png" Stretch="Uniform" />
</Button>
The "LaptopManagementViewModel":
//the userAccountVM
UserAccountViewModel userAccountVM;
//the constructor
public LaptopManagementViewModel(UserAccountViewModel userAccountVM)
{
LstDVUS = LaptopManagementBLL.Instance.GetDVUsageStatuses();
LstLaptop = LaptopManagementBLL.Instance.GetLaptopsInfo();
this.userAccountVM = userAccountVM;
ReceiverID = this.userAccountVM.SelectedUA.EmpID;
}
//the ReceiverID property
string receiverID;
public string ReceiverID
{
get { return receiverID; }
set
{
receiverID = value;
OnPropertyChanged("ReceiverID");
}
}
//function open FindEmployeeUC
private void FindEmployee(object obj)
{
//show findEmployee UC
Window wd = new Window()
{
Content = new FindEmployeeUC(),
};
wd.ShowDialog();
}
The "FindEmployeeUC" xaml:
<DataGrid Grid.Row="1" ItemsSource="{Binding LstUA}" CanUserAddRows="False" SelectedItem="{Binding SelectedUA,Mode=TwoWay}" AutoGenerateColumns="False" ColumnWidth="*" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}"></DataGridTextColumn>
<DataGridTextColumn Header="EmpID" Binding="{Binding EmpID}"></DataGridTextColumn>
<DataGridTextColumn Header="EmpName" Binding="{Binding EmpName}"></DataGridTextColumn>
<DataGridTextColumn Header="Position" Binding="{Binding Position}"></DataGridTextColumn>
<DataGridTextColumn Header="LineGroup" Binding="{Binding LineGroup}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
The "UserAccountViewModel":
//The property "SelectedUA"
UserAccountModel selectedUA;
public UserAccountModel SelectedUA
{
get { return selectedUA; }
set
{
if(selectedUA!=value)
{
selectedUA = value;
LaptopManagementViewModel laptopVM = new LaptopManagementViewModel(this);
OnPropertyChanged("SelectedUA");
}
}
}
I expect to get the EmpID for the TextBox in "LaptopWindow". I attach a picture for more detail:
Thanks in advance!
In your OnPropertyChanged event invocator you are always creating a new instance of UserAccountViewModel. This instance is never referenced in your XAML code, therefore your view can't see this new instances.
Since view model have a state you typically use a single instance for a binding target.
I removed the parameterized constructor to enable the instantiation in XAML (the instance is assigned to the UserAccountVM property from XAML) and also removed the reference to LaptopManagementViewModel from UserAccountViewModel. I created the view model instances and added them to the ResourceDictionary of App.xaml.
I also added a PropertyChanged event handler to the LaptopManagementViewModel to listen for changes of UserAccountViewModel.SelectedUA.
It is also highly recommended to avoid string literals. Instead of calling OnPropertyChanged("MyProperty") you should use the free compiler support by applying nameof(): OnPropertyChanged(nameof(MyClass.MyProperty)). I replaced the corresponding code. You now get rid of typos and get full support of compiler checks and refactoring tools (e.g. renaming).
Also stay away from Singletons. They smell strong.
Last complaint: make fields always private (or protected), especially when they are property backing fields. If you don't use any access modifier then internal will apply implicitly. Which is equivalent to public inside a shared assembly and fields should never be exposed.
Microsoft Docs recommends :
Generally, you should use fields only for variables that have private or protected accessibility. Data that your class exposes to client code should be provided through methods, properties and indexers. By using these constructs for indirect access to internal fields, you can guard against invalid input values. A private field that stores the data exposed by a public property is called a backing store or backing field.
App.xaml
<Application x:class="App">
<Application.Resources>
<ResourceDictionary>
<UserAccountViewModel x:Key="UserAccountViewModel" />
<LaptopManagementViewModel x:Key="LaptopManagementViewModel">
<LaptopManagementViewModel.UserAccountVM>
<StaticResource ResourceKey="UserAccountViewModel" />
</LaptopManagementViewModel.UserAccountVM>
</LaptopManagementViewModel>
</Application.Resources>
</Application>
LaptopWindow.xaml
<Window x:class="LaptopWindow">
<Window.DataContext>
<StaticResource ResourceKey="LaptopManagementViewModel" />
</Window.DataContext>
...
</Window>
FindEmployeeUC.xaml
<Window x:class="FindEmployeeUC">
<Window.DataContext>
<StaticResource ResourceKey="UserAccountViewModel" />
</Window.DataContext>
<DataGrid
...
</DataGrid>
</Window>
LaptopManagementViewModel.cs
public class LaptopManagementViewModel
{
private UserAccountViewModel userAccountVM;
public UserAccountViewModel UserAccountVM
{
get => userAccountVM;
set
{
userAccountVM = value;
OnPropertyChanged(nameof(UserAccountVM));
if (userAccountVM != null)
{
// Always clean up event handlers to avoid memory leaks
userAccountVM.PropertyChanged -= UpdateReceiverIdOnPropertyChanged;
}
userAccountVM.PropertyChanged += UpdateReceiverIdOnPropertyChanged;
}
}
// The constructor is now parameterless for the use in XAML
public LaptopManagementViewModel()
{
LstDVUS = LaptopManagementBLL.Instance.GetDVUsageStatuses();
LstLaptop = LaptopManagementBLL.Instance.GetLaptopsInfo();
}
// UserAccountVM.PropertyChanged event handler
private void UpdateReceiverIdOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals(nameof(UserAccountViewModel.SelectedUA), StringComparison.OrdinalIgnoreCase))
{
ReceiverID = UserAccountVM.SelectedUA.EmpID;
}
}
private string receiverID;
public string ReceiverID
{
get { return receiverID; }
set
{
receiverID = value;
OnPropertyChanged(nameof(ReceiverID));
}
}
}
UserAccountViewModel.cs
public class UserAccountViewModel
{
private UserAccountModel selectedUA;
public UserAccountModel SelectedUA
{
get => selectedUA;
set
{
if(selectedUA!=value)
{
// Removed wrong creation of LaptopManagementViewModel instances
selectedUA = value;
OnPropertyChanged(nameof(SelectedUA));
}
}
}
}
In setting up data binding for Observable Collection , under the following context: Implementing CollectionChanged Handler in XAML with WPF all bindings are working correctly, but I'm finding that in addition to changing the Property defined by ItemsSource within the ListBox, I am having to manually update the UI's visual container with code similar to:
XAML:
<Grid DataContext="{Binding ElementName=PollPublicStockMainWindow}">
<ListBox Height="132" HorizontalAlignment="Left" Name="lbFiles"
VerticalAlignment="Top" Width="167"
Margin="{StaticResource ConsistemtMargins}"
ItemsSource="{Binding LbItems}">
<ListBox.InputBindings>
<KeyBinding Key="Delete" Command="local:MainWindow.DeleteEntry"/>
</ListBox.InputBindings>
</ListBox>
</Grid>
CodeBehind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
LbItems = new ObservableCollection<string>();
LbItems.CollectionChanged += lbFiles_CollectionChanged;
}
private void lbFiles_CollectionChanged(object sender,
System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
MemoryPersistentStorageBridge memBridge = GetPersistentStorageBridge;
List<string> newFileList = new List<string>();
foreach (string str in LbItems) {
DoSomethingWithNewString(str); //these 2 lines are always paired?
lbFiles.Items.Add(str); // this should NOT be needed
}
}
}
Am I missing a binding?
Do you fire PropertyChanged when LbItems is set? It does not look that way. In the constructor, you call InitializeComponent first and then initialize the collection in LbItems = new ObservableCollection<string>();. I think that your collection is initialized "too late", because the binding will already have been processed. If you do not fire a property changed when LbItems is set then the binding will not be updated to actually bind to the collection.
I need to bind some data to a DataGrid with variable number of columns. I made it work using following code:
int n = 0;
foreach (string title in TitleList)
{
DataGridTextColumn col = new DataGridTextColumn();
col.Header = title;
Binding binding = new Binding(string.Format("DataList[{0}]", n++));
binding.Mode = BindingMode.TwoWay;
col.Binding = binding;
grid.Columns.Add(col);
}
where DataList is declared as:
public ObservableCollection<double> DataList { get; set; }
and TitleList is declared as:
public ObservableCollection<string> TitleList { get; set; }
The problem is that, even though I specified TwoWay binding, it is really one-way. When I click a cell to try to edit, I got an exception "'EditItem' is not allowed for this view". Did I just miss something in the binding expression?
P.S. I found an article from Deborah "Populating a DataGrid with Dynamic Columns in a Silverlight Application using MVVM". However, I had hard time to make it work for my case (specifically, I can't make the header binding work). Even if it worked, I'm still facing issues like inconsistent cell styles. That's why I'm wondering if I could make my above code work - with a little tweak?
EDIT: I found another post which might be related to my problem: Implicit Two Way binding. It looks if you bind to a list of string to a TextBox using
<TextBox Text="{Binding}"/>
You will get an error like "Two-way binding requires Path or XPath". But the problem can easily be fixed by using
<TextBox Text="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}"/>
or
<TextBox Text="{Binding .}"/>
Can anybody give me a hint if my problem can be solved in a similar way?
Do you bind to an indexer?. can you show us how your DataList Property looks like?
i did the same a while ago with an indexed property.
public SomeObjectWithIndexer DataList
{get; set;}
public class SomeObjectWithIndexer
{
public string this
{
get { ... }
set { ... }//<-- you need this one for TwoWay
}
}
EDIT: the reason that you cant edit your Property, is that you try to edit a "double field".
one workaround would be to wrap your double into a class with INotifyPropertyChanged.
public class DataListItem
{
public double MyValue { get; set;}//with OnPropertyChanged() and stuff
}
then you can use a
ObservableCollection<DataListItem>
and you can edit your value. the question wether the index are always the same stay still around :)
Binding binding = new Binding(string.Format("DataList[{0}].MyValue", n++));
EDIT2: working example: just to show twoway is working
public class DataItem
{
public string Name { get; set; }
public ObservableCollection<DataListItem> DataList { get; set; }
public DataItem()
{
this.DataList = new ObservableCollection<DataListItem>();
}
}
Wrapper for double:
public class DataListItem
{
private double myValue;
public double MyValue
{
get { return myValue; }
set { myValue = value; }//<-- set breakpoint here to see that edit is working
}
}
usercontrol with a datagrid
<UserControl x:Class="WpfStackoverflow.IndexCollectionDataGrid"
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">
<DataGrid ItemsSource="{Binding MyList}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" />
<DataGridTextColumn Header="Index1" Binding="{Binding Path=DataList[0].MyValue, Mode=TwoWay}" />
<DataGridTextColumn Header="Index2" Binding="{Binding Path=DataList[1].MyValue, Mode=TwoWay}" />
</DataGrid.Columns>
</DataGrid>
</UserControl>
.cs
public partial class IndexCollectionDataGrid : UserControl
{
public IndexCollectionDataGrid()
{
InitializeComponent();
this.MyList = new ObservableCollection<DataItem>();
var m1 = new DataItem() {Name = "test1"};
m1.DataList.Add(new DataListItem() { MyValue = 10 });
m1.DataList.Add(new DataListItem() { MyValue = 20 });
var m2 = new DataItem() { Name = "test2" };
m2.DataList.Add(new DataListItem() { MyValue = 100 });
m2.DataList.Add(new DataListItem() { MyValue = 200 });
this.MyList.Add(m1);
this.MyList.Add(m2);
this.DataContext = this;
}
public ObservableCollection<DataItem> MyList { get; set; }
}
i hope you get in the right direction with this example.
I want to use MVVM in my WPF application. I currently have a Model and a view which has DataGrid and some other controls. I created a ViewModel based on my model and don't know if I did it correctly. The view is just a simple dialog box. I want to fill the DataGrid view.
How can I tell the DataGrid to bind with the ViewModel?
I would like to bind properties(inside viewmodel like ID and Date) to the datagrid.
SO like if there is two objects inside the list I would like to see two rows in datagrid with the specific ID's and Date's.
Im setting the datacontext inside the class instead xaml.
Here is the code so far:
public class ViewModel : INotifyPropertyChanged
{
private string _id;
private DateTime _date;
private ObservableCollection<Object> _list;
public string Id
{
get { return _id; }
set
{
_id = value;
PropertChanged("Id");
}
}
public DateTime Date
{
get { return _date; }
set
{
_date = value;
PropertChanged("Date");
}
}
public ObservableCollection<Object> list
{
get { return _list; }
set
{
_list = value;
PropertChanged("list");
}
}
public LicenseViewModel()
{
list = GetList();
}
public event PropertyChangedEventHandler PropertyChanged;
public void PropertChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And the XAML:
<Window x:Class="Import"
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:Controls="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
mc:Ignorable="d"
ResizeMode="CanResizeWithGrip"
x:Name="ImportLicense"
d:DesignHeight="493" d:DesignWidth="559"
Title="Import Licenses" SizeToContent="WidthAndHeight">
<Grid Width="538">
<DataGrid x:Name="Imported" VerticalAlignment="Top" AutoGenerateColumns="False" CanUserResizeColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Entitlement ID" Binding="{Binding Path=ID}"/>
<DataGridTextColumn Header="Date Sold" Binding="{Binding Path=Date}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
You need to set the data context for the DataGrid to the instance of your view model. You can do this by simply setting the DataContext of your View or the DataGrid to your instance of your view model in the constructor of the view class. This is a quick and dirty way of doing this.
If you want to be more sophisticated you can create a DepenencyProperty on your view class like this:
public static DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel",
typeof(ItemViewModel),
typeof(ViewClassHere));
public ItemViewModel ViewModel
{
get { return (ItemViewModel)base.GetValue(ItemViewModel); }
set { base.SetValue(ItemViewModel, value); }
}
Then you'd bind to that property in any one of many ways but one way would be like:
<DataGrid ItemsSource="{Binding ElementName=windowName, Path=viewName.list}">
There are a bunch of ways to do this, these are just two possible ways to do this.
the common way to display data with a datagrid is to set the itemssource
<DataGrid ItemsSource="{Binding MyCollection}"/>
your viewmodel defines 2properties and one collection, but in your xaml you bind your properties to the datagrid columns and don't set any itemssource.
its not clear to me what you would like to see in your datagrid, but your 2 properties ID and DateTime are not part of any collection, so why you want this to display in your datagrid?
please edit your question and give some information of what you wanna see in your datagrid.
Try like this:
<window.Resources>
<ViewModel x:Key="ViewModel"></ViewModel >
</window.Resources>
<Grid x:Name="ValueDetail" DataContext="{StaticResource ViewModel}">
<DataGrid ItemsSource="{Binding MyCollection}"/>
</Grid>
I have a ComboBox on a silverlight control, that I want to bind. Sounds simple, except what I'm finding is that because the data for the ItemsSource comes from a web service asynchronously, I need to use the code behind to bind the SelectedValue only after the data has come back.
The collection that the data goes in implements INotifyCollectionChanged and INotifyPropertyChanged, so it should all be working, and indeed the combo box loads properly, but there is no value pre-selected.
What I think is happening is that the SelectedValue is getting bound before the collection has loaded - when the combobox is empty - so nothing is selected, and then later when the data comes in, the combobox is populated, but it is not checking the selected value again.
So whilst I have this working if I use code behind to hook up events and creating bindings in code, I'd like to move this all to XAML with something like:
<ComboBox HorizontalAlignment="Stretch" Margin="5,3,9,127" Name="cboCategoryID" Grid.Row="4" Grid.Column="1"
ItemsSource="{StaticResource Categories}"
SelectedValue="{Binding CategoryID, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True}"
SelectedValuePath="CategoryID"
DisplayMemberPath="Caption"
VerticalAlignment="Center">
</ComboBox>
This correctly loads items, but doesn't bind the selected value. If I put the following code in the code-behind, it all works:
public MainControl()
{
InitializeComponent();
CategoryCollection cats = new CategoryCollection();
cats.Dispatcher = this.Dispatcher;
cats.LoadComplete += new EventHandler(cats_LoadComplete);
cboCategoryID.ItemsSource = cats;
cats.LoadAll();
}
private void cats_LoadComplete(object sender, EventArgs e)
{
cboCategoryID.SetBinding(ComboBox.SelectedValueProperty, new System.Windows.Data.Binding("CategoryID"));
}
Is there a way to do this without resorting to code behind?
Are you using mvvm? If so, you can try to set the ItemsSource and SelectedItem in the callback of the web service, or take a look at this post from Kyle.
http://blogs.msdn.com/b/kylemc/archive/2010/06/18/combobox-sample-for-ria-services.aspx
you are already using a collection that notifies of changes, so if the value that you are binding the SelectedValue to is notifying of changes, then all you have to do is set that property after the values are loaded from the webservice. it SHOULD update the combobox automatically, allowing you to do your binding purely in xaml.
public myObject CategoryID { get {....}
set {
this.categoryID = value;
RaisePropertyChanged("CategoryID");}
public void DataLoadedHandler()
{
CategoryID = 34; // this will cause the binding to update
}
take a look at this simple sample:
XAML:
<UserControl
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:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" xmlns:local="clr-namespace:StackoverflowQuestions.Silverlight" xmlns:sdk1="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="StackoverflowQuestions.Silverlight.MainPage"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<DataTemplate x:Key="Item">
<TextBlock Text="{Binding PropertyToBeWatched}" />
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<!--<sdk:DataGrid ItemsSource="{Binding MyList}" RowStyle="{StaticResource Style1}">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding PropertyToBeWatched}" Header="Property1"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>-->
<ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" Height="50" VerticalAlignment="Top" ItemTemplate="{StaticResource Item}" />
</Grid>
</UserControl>
Codebehind:
public partial class MainPage : UserControl, INotifyPropertyChanged
{
private ObservableCollection _myList;
private CustomClass _selectedItem;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<CustomClass> MyList
{
get { return _myList ?? (_myList = new ObservableCollection<CustomClass>()); }
set
{
_myList = value;
RaisePropertyChanged("MyList");
}
}
public CustomClass SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
protected void RaisePropertyChanged(string propertyname)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyname));
}
public MainPage()
{
InitializeComponent();
this.DataContext = this;
MyList.Add(new CustomClass() { PropertyToBeWatched = "1"});
MyList.Add(new CustomClass() { PropertyToBeWatched = "2" });
MyList.Add(new CustomClass() { PropertyToBeWatched = "2" });
MyList.Add(new CustomClass() { PropertyToBeWatched = "2" });
SelectedItem = MyList[1]; //Here is where it happens
}
}
By binding the SelectedItem of the ComboBox to an entity, we can achieve what you want. This works TwoWay ofcourse.
Hope this helps. :D