I'm binding a collection of collections to a WPF datagrid component(external library) and the underlying DataSource has the following structure. This basically gives me a datagrid with hierarchical records
class DataGridItemType
{
public string weightType;
public string SourceType;
private BindingList<DataGridItem> typeCollection = new BindingList<DataGridItem>();
}
BindingList<DataGridItemType> list = new BindingList<DataGridItemType>();
list is the datagrids DataSource and this performs hierarchical binding. Now, I tried binding a component(The header label of the records one level into the hierarchy whose datasource is typeCollection) to the variable weightType by using, Text="{Binding Path=weightType, Mode=TwoWay, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type btm:DataGridItemType}}} but the binding doesn't work. Am I missing something?
AncestorType should be the UI Element in the UI hierarchy whose DataContext (which would be an object of DataGridItemType - your custom class) you want to bind to.
There is no code snippet here but read the remarks section here
Related
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.
This is the scenario:
I have a telerik gridview on my page, this is bound to a PagedCollectionView
with items of class "GekoppeldeOntvangstRegel",
this class implements INotifyPropertyChanged
Several columns have a CellTemplate with a TextBlock bound to an object of this class, like this:
<TextBlock Text="{Binding ConverterParameter='aantal', Converter={StaticResource GekoppeldeRegelDecimalFormatConverter}, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, ValidatesOnNotifyDataErrors=True}" HorizontalAlignment="Right" ToolTipService.ToolTip="{Binding ConverterParameter='aantal', Converter={StaticResource GekoppeldeRegelToolTipDecimalFormatConverter}}" />
This converter converts the "Aantal" property to a string with a specific number of decimals.
When I update the "Aantal" property from code with the OnPropertyChanged("Aantal") of course the binding isn't updated (since the textblock is bound to the entire object, not the property) so the old value is still visible.
How can I refresh the column contents from my viewmodel or object when the property changes?
When I bind directly to the "Aantal" property everything works perfectly (besides the converter not being applied, which is necessary)
As a workaround I now have created several extra properties on the "GekoppeldeOntvangstRegel" class.
These properties call the converter and return the right value with the right number of decimals.
On these properties raising OnPropertyChanged does work to refresh the bindings.
I'm not really happy with this solution but it works for now.
I have a list of objects which i want to bind to a ListView control in my WPF application.
The Objects have a DataTemplate already, so no need to define that.
The list of objects is a property in the codebehind file in the format list<object>
When i add one object programatically, it appears fine. But when i try to bind the ItemSource of the ListBox to the list of objects, nothing shows up.
I am using the following binding:
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Portfolios}"/>
where the name of the property i am trying to bind to is Portfolios and exists on the parent window
List<> objects don't automatically report when a new item is added. Try using an ObservableCollection<> instead, and see if that helps.
The subject line says it all really! I have a user control which can be bound successfully to, say, a Fullname object - i.e. it works ok.
I now need to show a list of these and, again, this works ok when the control is in a DataTemplate within ItemsControl.Template.
But, the control has a property (InEditMode) that is not a property of the Fullname object but of the object that has the FullnameList property to which the ItemsControl is bound, via ItemsSource. This InEditMode property works fine when the control is not in a list and is bound to parent sibling properties named, say, ParentInEditMode and ParentFullname.
The question is - what style of binding expression is required to 'get at' the edit mode property of the parent object when the control is an ItemsControl?
Or, should I re-design the Fullname object to contain an EditMode property?
Many thanks in advance!
Update:
The item (i.e. that which is in collection bound to the ItemsControl) does NOT have such a property. Code is very simple:
<ItemsControl ItemsSource="{Binding Path=FullnameList}">
...then...
<ItemsControl.ItemTemplate>
<DataTemplate>
<jasControls:NameView
NameValue="{Binding Path=.}"
InEditMode= ??????? />
The overall parent (the viewmodel for the window) has properties:
FullnameList
ParentInEditMode
Fullname (single item for testing NameView which works perfectly with this xaml outside of any list control using:
<jasControls:NameView NameValue="{Binding Path=Fullname}" InEditMode="{Binding Path=ParentInEditMode}"/>
I would like to apply the edit mode to the entire collection - making that flag part of Fullname does not seem right!?
I have found an answer to my own question, which I hope will help others.
The working syntax I have is this:
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=FullnameList}">
...then...
<ItemsControl.ItemTemplate>
<DataTemplate>
<jasControls:NameView
NameValue="{Binding Path=.}"
InEditMode= "{Binding DataContext.ParentInEditMode,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}}" />
This correctly picks up the property that is a sibling of FullnameList and passes it to the data template item. More by luck than judgement, but I hope this is a valid way to do this!
For each Item in ItemsSource, ItemsControl creates the specified DataTemplate and to its DataContext it assigns the respective Item. Now every DataTemplate can bind to its item in its data context.
So I suppose your item does have a property "ParentInEditMode"; there should be no issue with binding to that property.
If it doesn't work, please update your question with some code.
I have a UserControl(a) with a stackpanel which has its ItemSource set to a collection.
The StackPanel then contains a set of UserControl(b) that contain a few buttons and a datagrid control.
Is there a way from the code behind in the UserControl(b) to access properties in the code behind of the parent UserControl(a).
Basically when UserControl(a) loaded into a window a parameter is passed in that contains whether the form will be considered read only or not. I would like bind the visibility of the buttons in Usercontrol(b) to the readonly property in the codebehind of the parent UserControl(a).
Normally with WPF I'd suggest you implement the Model-View-ViewModel pattern (see MSDN).
With this pattern you'd create a ViewModel with all of the data in that you want to bind. This would be set as the data context for the (a) usercontrol. That control would then bind all of it's controls to properties on the datacontext.
The child (b) usercontrol would inherit this datacontext and could therefore bind it's controls to the same properties as (a) uses. This is because datacontexts are inherited down the logical (and visual) tree until such point as it's overridden.
So for you I'd be looking at creating a ViewModel that contains the property ReadOnly. You can then set this ViewModel object as the datacontext for the (a) usercontrol. The (b) usercontrol, since it's under the (a) usercontrol hierarchy will inherit the same datacontext. This will then allow you to bind controls within (b) to the same properties as (a) as shown below.
<Button IsEnabled="{Binding ReadOnly}"
Context="Click me!"
Command="{Binding ClickMeCommand}" />
To set the datacontext in the view code-behind I do something like this constructor shown below.
public MyView(IMyViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
MyView is the class that inherits from UserControl in your instance. You don't have to get the viewmodel in the way I have, I'm using Unity to inject the viewmodel into the views that are constructed automatically since I'm using Prism but you can just create it as a normal object and assign it to the datacontext.
Note that I've also bound the command to the button using the datacontext as I usually expose those via the ViewModel too, this is easy if you create a wrapper class that implements ICommand and proxies to a delegate. See DelegateCommand blog article or look at the DelegateCommand class in Prism if you are interested.
If for some reason you do override the datacontext, which can happen when using a master/details view where you change the datacontext of the details section of the view to be the currently selected item in the list, then you can still access the parent datacontext by using a relative source binding.
E.g.
<ComboBox Grid.Row="1" Grid.Column="1" x:Name="Unit" IsReadOnly="True"
ItemsSource="{Binding Path=DataContext.AvailableUnits, RelativeSource=
{RelativeSource Mode=FindAncestor,
AncestorType={x:Type Window}}}"
DisplayMemberPath="Name" SelectedItem="{Binding Unit}" />
Note the ItemsSource binding uses a relative source to find the parent window and then bind to a property of it's datacontext. I've also split the ItemsSource binding within the quotes across multiple lines for clarity here but don't do that in your xaml, I'm not sure it'll work there (not tried to see if markup extensions are that tolerant of whitespace).