I have a custom control that has a dependency property that should fill a datagrid's ItemsSource property in the control. For some reason the collection never gets filled and the ItemsSource always ends up empty.
Public Shared ReadOnly ItemsSourceProperty As DependencyProperty = DependencyProperty.Register("ItemsSource", GetType(ObservableObjectCollection), GetType(HomePageControl), New PropertyMetadata(New ObservableObjectCollection, New PropertyChangedCallback(AddressOf ItemsSourceCallback)))
Public Property ItemsSource As ObservableObjectCollection
Get
Return DirectCast(GetValue(HomePageControl.ItemsSourceProperty), ObservableObjectCollection)
End Get
Set(value As ObservableObjectCollection)
SetValue(HomePageControl.ItemsSourceProperty, value)
End Set
End Property
Xaml:
<Controls:HomePageControl x:Name="myControl"
Margin="0,25,0,0"
Grid.Row="1"
HeaderText="{Binding Source={StaticResource MainViewModel}, Path=CurrentUser, Mode=TwoWay, UpdateSourceTrigger=Default}"
HeaderCount="30"
HeaderLinkText="This is optional."
HeaderLinkURI="/Projects"
ItemsSource="{Binding Source={StaticResource MainViewModel}, Path=TaskList, Mode=TwoWay, UpdateSourceTrigger=Default}"
GridViewStyle="{StaticResource RadGridViewStyleNoFlag}"
/>
I have five other DPs that work just fine, 3 strings and one style (to set up the columns of the datagrid) and a URI. I can either set them directly, as in "This is optional", or by binding them like the HeaderText, but the ItemsSource property never seems to get bound... a gridview outside of the control that uses the same binding as used in the ItemsSource binding inside the control gets filled... so the binding does return a filled collection, but it is not making it to the datagrid inside the custom control.
If I change ObservableObjectCollection to the object type that I'm using in the collection that I bind, then it works fine. The reason I want to use ObservableObjectCollection is because I want to be able to bind any object to the datagrid, just like a datagrid can... it doesn't care what type you bind to it - how can I get my user control to not care?
Related
I have a WPF control inheriting from ComboBox whose ItemsSource is bound to a list of elements, and whose SelectedItem is bound to another field. I have two references to the same list in my application: one resides in my MainWindow class, and one resides in my App class.
The list of elements used as the ItemsSource is assigned to the ComboBox at the time it is created. Thus, I expect to get an ItemsSourceChanged event.
The strange thing is, if the ItemsSource is bound to the MainWindow's list, then the ComboBox becomes populated with the correct SelectedItem drawn from the bound field. However, if I bind the ItemsSource to the App's copy of the list, then the SelectedItem becomes overwritten with null due to the ItemsSourceChanged event.
Here is the XAML for the ComboBox when it's binding to the App copy of the list:
<local:TagSelectionComboBox FilteredTagsList="{Binding Path=TagsList, Source={x:Static Application.Current}}" SelectedItem="{Binding TagValue}"></local:TagSelectionComboBox>
Here is the XAML for the ComboBox when it's binding to the MainWindow copy of the list:
<local:TagSelectionComboBox FilteredTagsList="{Binding TagsList, RelativeSource={RelativeSource AncestorType=Window}}" SelectedItem="{Binding TagValue}"></local:TagSelectionComboBox>
Here is the MainWindow's property used for binding:
public ObservableCollection<Tag> TagsList
{
get { return proj.Sim.Tags; }
}
And here is the App's property used for binding:
public ObservableCollection<Tag> TagsList
{
get { return proj.Sim.Tags; }
}
So these two properties on App and MainWindow are returning the same list. Stepping through in the debugger confirms: proj.Sim.Tags contains the same list in both cases.
Why does changing from one binding source to another alter the binding behavior? Is something else going on?
I've found that if I explicitly set IsSynchronizedWithCurrentItem="True", then the behavior is the same in both cases. So it's almost like IsSynchronizedWithCurrentItem="True" is the default behavior when I use the MainWindow (RelativeSource) binding but IsSynchronizedWithCurrentItem="False" is the default behavior when I use the App (x:Static) binding.
Background: the ComboBox-derived control in this question is basically the same as YantingChen's answer for this question:
Dynamic filter of WPF combobox based on text input
I am designing a UserControl that contains a datagrid. The datagrid is not displaying any rows despite my best efforts to bind it to the ItemsSource.
Here is the basic flow of the binding:
A window that contains the UserControl.
The window viewmodel contains an instance of the viewmodel designed for the user control.
I bind the UserControl's ViewModel to this viewmodel via dependency property.
The datagrid is then binded to the observable collection inside the view model, but nothing is showing.
Code (Xaml and VB.Net):
The window view model, binded to all window controls:
Public Class WindowVM
...
Public Property UserControlViewModel as New UserControlVM
End Class
Window Xaml:
<local:MyUserControl ViewModel="{Binding UserControlViewModel, Mode=OneWay}"/>
User Control code:
Public Shared ReadOnly ViewModelProperty As DependencyProperty = DependencyProperty.Register("ViewModel", GetType(UserControlVM), GetType(MyUserControl), New PropertyMetadata(Nothing))
...
Public Property ViewModel As UserControlVM
Get
Return CType(Me.GetValue(ViewModelProperty), UserControlVM)
End Get
Set(value As UserControlVM)
Me.SetValue(ViewModelProperty, value)
End Set
End Property
....
Public Class UserControlVM
Public Property RunItems As New ObservableCollection(Of RunVM)
End Class
User control xaml, datagrid binding:
<DataGrid DataContext="{Binding ViewModel}"
ItemsSource="{Binding RunItems}" ...
It seems a lot of steps, but to my knowledge this is the correct MVVM way to snake the binding to the DataGrid. So far, nothing.
Looks like I might have solved it. The DataGrid's DataContext needed to be pointed at the UserControl.
Just a simple oversight:
<DataGrid DataContext="{Binding ViewModel, RelativeSource={RelativeSource AncestorType=UserControl}}"
ItemsSource="{Binding RunItems}"
I have a WPF app with a MainWindow. The MainWindow consists of several CLR properties of type ObservableCollection. The MainWindow has a datagrid, whose ItemsSource property is bound to one of the observable collections (works fine). Next, I have a dialog. Its purpose is to display one of the observable collections from the main window in a datagrid. The dialog gets instantiated in the MainWindow. Initially I was passing the ObservableCollection to the dialog's constructor, and copying it into the dialog's CLR property. Then I would set the DataContext of the dialog to itself, and bind the ItemsSource property in the datagrid to the name of the CLR property. This worked fine.
Is there a better way to do this instead of passing the observable collection through the constructor? I tried setting the ItemsSource property of the Datagrid in the dialog to the observable collection in the MainWindow by using the GUI editor, which generated a binding using RelativeAncestor, but the data did not show. The problem is I have a bunch of dialogs that are meant to display data from the MainWindow, and I feel like there should be a simpler solution rather than passing everything to dialog's constructor. Also, would the dialogs be considered SubViews? The main window is a view.
Let's say your Dialog control is named DialogControl and has a DependencyProperty named Items defined in its code behind. In the XAML, I would bind this property to the DataGrid like this:
<DataGrid ItemsSource="{Binding Items, RelativeSource={RelativeSource Mode=
FindAncestor, AncestorType={x:Type DialogControl}}" />
This RelativeSource binding will go off and search through the properties of your DialogControl class and find the Items property. Note: Do NOT set the DataContext of the UserControl to itself.
Now in your MainWindow.xaml.cs file where you instantiate your DialogControl, you can set the Items property:
DialogControl dialogControl = new DialogControl();
dialogControl.Items = someCollection;
dialogControl.Show();
UPDATE >>>
Oh I see what you're after now... you want to bind from your UserControl to the actual collection in the MainWindow.xaml.cs file. You can still follow my advice, but instead of having the DependencyProperty in your DialogControl, you need to have it in your MainWindow.xaml.cs file. In that case, your binding in the UserControl would be:
<DataGrid ItemsSource="{Binding Items, RelativeSource={RelativeSource Mode=
FindAncestor, AncestorType={x:Type MainWindow}}" />
For this to work, the Items property must be a DependencyProperty.
I'm trying to bind combobox editor in a PropertyGrid to a list.
<dxprg:PropertyGridControl SelectedObject="{Binding SelectedEmployee}">
<dxprg:PropertyDefinition Path="EmployeeCountryID">
<dxprg:PropertyDefinition.EditSettings>
<dxe:ComboBoxEditSettings
ItemsSource="{Binding Path=DataContext.Countries, ElementName=rootWindow}"
ValueMember="CountryId" DisplayMember="CountryName" />
</dxprg:PropertyDefinition.EditSettings>
</dxprg:PropertyDefinition>
</dxprg:PropertyGridControl>
This example is from a third-party control but the problem may be just general.
The "rootWindow" DataContext has been set to a ViewModel which holds a property List(of Country) that I want have as ItemsSource in a Combobox.
I was trying to access that list by setting the Combobox ItemsSource to the rootWindow.DataContext.Countries property but I don't get any data.
Tried also all those RelativeSource FindAncestor bindings but no data appeared either.
Why can't I bind through a DataContext of a given element like this?
This became solved. The problem was not with the binding at all but realated to how I defined the third-party control: Instead of EditSettings I should have defined CellTemplate -> DataTemplate.
I have a working ListView like this
<ListView Name="passageListView" ItemsSource="{Binding Path=Passages, NotifyOnTargetUpdated=True}" TargetUpdated="PassageListViewTargetUpdated">
where Passages is an ObservableCollection<>.
Now, how I do the same binding in code? (note that NotifyOnTargetUpdated=True has to be set)
I have tried to assign a Binding to passageListView.ItemsSource but this is not allowed and I can't use SetBinding() since passageListView.ItemsSourceis not a DependencyProperty?
Any ideas?
try this in the constructor of the control where the ListView is:
passageListView.SetBinding(ListView.ItemsSourceProperty,
new Binding
{
Path = new PropertyPath("Passages"),
NotifyOnTargetUpdated = true
});
If the DataContext is set properly, this should work.
The DependencyProperty could also be ItemsControl.ItemsSourceProperty, because that is the base class.