I'm having trouble binding XmlDataProvider from ViewModel (my DataContext) to ListBox's ItemsSource.
This is what I did -
In Xaml -
<ListBox ItemsSource="{Binding Path=SelectedXmlProvider}">...</ListBox>
In my ViewModel class -
public XmlDataProvider SelectedFeedXmlProvider
{
get { return _selectedFeedXmlProvider; }
set
{
_selectedFeedXmlProvider = value;
RaisePropertyChanged("SelectedFeedXmlProvider");
}
}
In my application -
viewModel.SelectedFeedXmlProvider = new XmlDataProvider
{
Source = new Uri("http://sxp.microsoft.com/feeds/3.0/MSDNTN/CSharpHeadlines"),
XPath = "//item"
};
And... ListBox is EMPTY! (where it should have been full with data).
When setting the ListBox's ItemsSource to an XmlDataProvider that's defined as a static resource, all is fine. Thing is, I must use MVVM, and I need to be able to dynamically change the XML source.
Can someone help? what's wrong with the code above? why is the list empty?
Thanks!
Related
I have a requirement where I need to bind a list of observable collections to the item source of dynamically created ComboBoxes.
The problem is we bind through xaml conventionally in ItemsSource property but now the control rows in the grid are being added dynamically so each ComboBox in a row reference to the same collection whereas I need to bind it to a separate collection in observable collection list each time a row in the grid is added.
This what I have tried so far, any guidance would be appreciated. Thanks.
public virtual List<ObservableCollection<ComboBoxEntity>> ListRewardRule { get; set; }
Xaml :
<itimControls:ComboBox Name="cboReward"
IsMandatory="True"
itimComponents:ComponentManager.ComponentId="TXT_GROUP_RULE"
MaxWidth="400"
MinWidth="150"
ItemsSource="{Binding ListRewardRule, ElementName=RDefinitionScreen}"
DisplayMemberPath="Name"
SelectedValuePath="Code"
Loaded="cboReward_Loaded"
SelectedValue="{Binding RewardRuleId, Mode=TwoWay}"
SelectionChanged="cboReward_SelectionChanged">
</itimControls:ComboBox>
.CS :
private void cboReward_Loaded(object sender, RoutedEventArgs e)
{
Itim.Framework.Silverlight.UI.Controls.ComboBox cboReward = ((Itim.Framework.Silverlight.UI.Controls.ComboBox)sender);
int row = (int)cboReward.GetValue(Grid.RowProperty);
if (Model.ListRewardRule.Count > 0)
{
var rewardGroups = Model.RewardGroupAndTier.RewardGroups;
if(rewardGroups.Count > 1)
{
cboReward.ItemsSource = Model.ListRewardRule[row];
}
}
}
The way I understand this is, you have a “grid” (I suppose you mean a DataGrid) and each row in the grid has, among other things, a set of combo boxes.
What I’d do is bind that grid to an ObservableCollection of a custom class, call it CustomRowClass. CustomRowClass should have an ObservableCollection that will be bound to the combo boxes.
The magic is to define a DataTemplate for CustomRowClass. Once you set up the XAML this way, all you need to do is create an instance of CustomRowClass, and then add it to the ItemsSource of the grid.
What I'm trying to achieve is:
Have a ListView bound to an ObservableCollection of ItemRecords.
Have a TabControl that contains detailed view for all the ItemRecords in the ListView that were selected for editing.
Each TabItem contains a UserControl ("ItemInfo") that uses ItemInfoViewModel as its VM (and, not so coincidentally, DataContext).
ItemInfo UserControl needs to be populated with the data from the corresponding ItemRecord.
To achieve that, I'm trying to pass the ItemRecord (selected in the ListView) to ItemInfoViewModel.
Finally, the question: what do you think would be the best way to do this, without breaking the MVVM pattern?
The not-so-elegant way that I see (and it actually doesn't exactly follow the MVVM principles) is to have a DependencyProperty ItemRecord defined in the UserControl, provide its value via binding, and in the constructor (in the UserControl's code-behind) pass the ItemRecord to the VM (which we get by casting the DataContext).
The other problem is with how to actually pass the ItemRecord via binding.
Once I set the VM as the UserControl's DataContext, I cannot just use {Binding} to specify the current item in TabControl's source collection.
At the moment I am binding to the TabControl's SelectedItem using ElementName - but this doesn't sound too robust :-(
<localControls:TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer>
<localControls:ItemInfo ItemRecord="{Binding ElementName=Tabs, Path=SelectedItem}"/>
</ScrollViewer>
</DataTemplate>
</localControls:TabControl.ContentTemplate>
Any good advice will be greatly appreciated!
Alex
I think your problem is you're not quite understanding the MVVM pattern here; you're still looking at this as the different controls talking to each other. Where in MVVM, they should not be, each control is communicating with the view model independently of all the others. And the view model controls (and supplies) the logic which tells the controls how to behave.
So, ideally you would have something like:
public ObservableCollection<ItemRecord> ListViewRecords
{
get { ... }
set { ... }
}
public IEnumerable<ItemRecord> SelectedListViewRecords {
{
get { ... }
set { ... }
}
The ListViewRecords would be bound to the ItemsSource property of your ListView (the actual properties might vary based on the specific controls you're using, I'm used to the Telerik suite at the moment so that's where my head is). And the SelectedListViewRecords would be bound to the SelectedItems property of the ListView. Then for your TabControl you would have:
public ObservableCollection<MyTabItem> Tabs
{
get { ... }
set { ... }
}
public MyTabItem SelectedTab
{
get { ... }
set { ... }
}
Again, you would bind the Items property to the Tabs and SelectedItem to the SelectedTab on your TabControl. Now your view model contains all the logic, so in your SelectedListViewRecords you might do something like this:
public IEnumerable<ItemRecord> SelectedListViewRecords {
{
get { ... }
set
{
_selectedRecords = value;
NotifyPropertyChanged("SelectedListViewRecords");
Tabs.Clear(); // Clear the existing tabs
// Create a new tab for each newly selected record
foreach(ItemRecord record in value)
Tabs.Add(new MyTabItem(record));
}
}
So the idea here is that the controls do nothing more than send and receive property changes, they know nothing of the underlying data, logic, etc. They simply show what their bound properties tell them to show.
I have two TreeView´s in a TabControl, databound to a xmlDataProvider. If i add nodes to my Xml and save it:
xmlDataProvider.Document.Save(fullPathToXml);
xmlDataProvider.Refresh();
Only the TreeView that is not in the open Tab refresh. Both TreeView´s look like this:
<TreeView Name="DIFFERENT_NAMES" ItemsSource="{Binding Source={StaticResource dataxml}, XPath=./*}"/>
If your ItemsSource is binded to a property implementing OnPropertyChanged, you can add the attribute "UpdateSourceTrigger=PropertyChanges" to your binding in the XAML.
Hence, the control will update itself each time OnPropertyChanged is called
EDIT
I assume your ViewModel already implements OnPropertyChanged
Therefore, all you have to do is, when you declare your property:
private XmlDataProvider _xmlDataProvider;
public XmlDataProvider XmlDataProvider
{
get { return xmlDataProvider; }
set
{
xmlDataProvider = value;
OnPropertyChanged("XmlDataProvider");
}
}
Initialize the XmlDataProvider in your constructor, and then, each time the object is modified, it will call the method OnPropertyChanged, on the property you specify (here "XmlDataProvider"), and each time OnPropertyChanged is called, your view bound to this object will refresh automatically :)
I'm trying to figure out if its possible to update an IValueConverter through the code behind.
My situation is that I've got two ComboBoxes. Once the first one is updated, I change the ItemsSource property of the second to be one of a variety of enums. I've grabbed an EnumToFriendlyNameConverter from CodeProject, but I'm not sure how to set it.
If I set the converter in the ItemsSource (see below) then it gets ignored when I next set the items source.
ItemsSource="{Binding Converter={StaticResource enumItemsConverter}}"
I found that it is possible by using an ItemTemplate but then I have to manually place in a label, which then has a different style to my other combobox. Getting the styles right just seems like a lot of work...
When you change the ItemsSource you just have to apply the converter again or modify the ItemsSource instead of replacing it.
e.g. create a new binding:
private void ChangeItemsSouce(IEnumerable newItems)
{
Binding binding = new Binding();
binding.Source = newItems;
binding.Converter = new EnumToFriendlyNameConverter();
comboBox.SetBinding(ComboBox.ItemsSourceProperty, binding);
}
Or modify the existing binding:
private void ChangeItemsSouce(IEnumerable newItems)
{
var binding = comboBox.GetBindingExpression(ComboBox.ItemsSourceProperty);
binding.ParentBinding.Source = newItems;
}
I'm trying to bind to a collection of controls I generate dynamically:
<ItemsControl ItemsSource="{Binding CustomFields}">
And the code:
public ObservableCollection<Control> CustomFields
{
get
{
return GetCustomFields();
}
}
The Getcustomfields just generates some controls like a ComboBox, textbox etc. The binding seems to work, but the window doesn't show any of my controls. Probably because I need an datatemplate in the itemscontrol. My question is what kind of datatemplate do I need?
Thanks for any help
The following property like with the same XAML as you use:
public ObservableCollection<UIElement> Controls
{
get
{
var collection = new ObservableCollection<UIElement>();
collection.Add(new Button { Content = "Hello world" });
return collection;
}
}
Maybe your problem comes from somewhere else... Can you give us the code needed to reproduce the problem ?