Passing Generic lists to a WPF usercontrol - wpf

I want to create a usercontrol that takes lists of different objects. These objects would be assigned to the control at design time. Now I want to be able to use linq to object to sort this list inside the usercontrol. Can anyone give me any ideas as how to go about it?

Add a DependencyProperty of type ObservableCollection<T> to your user control class (call it MyItemsSource for example). In your containing XAML, bind that property to your Linq collection, and inside your user control, bind your ListBox (or other ItemsControl) to the property as follows:
{Binding
RelativeSource={RelativeSource
Mode=FindAncester,
AncestorType=UserControl},
Path=MyItemsSource}
Alternatively, you can set the Name property inside the user control on the top level element (the UserControl element) to for example MyUserControl, and bind against an ElementName instead of a RelativeSource as such:
{Binding ElementName=MyUserControl, Path=MyItemsSource}

Related

trying to bind datagrid item source to a property in another class

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.

Binding from usercontrol to property of parent usercontrol

Let's say I have a user control called Graph in a window. This user control contains a grid, within which there is another user control, called Toolbar. Now Graph exposes a public property called Mode, which uses a dependency property called ModeProperty as a backing store. I want an element in the Toolbar user control to bind to the Mode property in its ancestor Graph. How can I do this? Even just getting a reference to Graph is proving to be harder than I expected, this.parent gets a reference to the grid rather than the Graph.
You can bind it in xaml only like this -
<Toolbar Mode="{Binding Path=Mode, RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType = UserControl, AncestorLevel =2}}"/>
Also you can use the ElementName in your binding like this -
<Toolbar Mode="{Binding Path=Mode, ElementName=GraphUserControl}"/>
You have to set x:Name property on your userControl to which you want to bind to -
<UserControl x:Name="GraphUserControl"></UserControl>
Or in case you won't to do in code behind, you can look at this useful post for travelling to ancestor parent - Visual Tree Navigator

How to get rid of using ElementName in WPF bindings in XAML

I am building a WPF application and I have some DependencyProperties in my window's codebehind (actually a big bunch of them). I want to bind a textbox to one of these string values. If I use {Binding ObjectName} it just doesn't work and it complains about not finding the property in the output. If I use {Binding ObjectName, ElementName=window} (where window is my Window's instance name), it works. But I have lots of bindings and I don't want to use the ElementName property each time. Is there any shortcut that will default all the element names to the window objects, as all of my bindings have the same element?
Thanks,
Can.
The default source of a binding is FrameworkElement.DataContext so you have to set the DataContext property of your window to the instance of your window e.g. DataContext = this;

How to make my WPF UserControl work with CompositeCollection

I have a wpf user control which exposes an IEnumerable ItemsSource DependencyProperty. I bind this property to a ListBox control in my UserControl.
I would like to know how I can make my user control work when a CompositeCollection is given. Currently I'm utilising my control like this:
<my:uc>
<my:uc.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{My Binding}"></CollectionContainer>
<CollectionContainer Collection="{My Binding}"></CollectionContainer>
</CompositeCollection>
</my:uc.ItemsSource>
</my:uc>
I would like this to display the contents of these CollectionContainers in the list box, but at the moment its not enumerating through the containers. The only items my listbox shows is two "System.Data.CollectionContainer" items.
[b]Edit:[/b]
The XAML designer informs me that "Property 'ItemsSource' does not support values of type 'CompositeCollection'." I think this is my problem.. but how do I make it "support" CompositeCollection?
I think that what you are getting is the ToString method of your object, which by default returns the name of the type.
Try overriding ToString and returning the value you want to see in your list.
The correct answer was to create a class that extends ItemsControl. You can not use any XAML when designing the control, but it does give you the special ItemsSource property which supports CollectionContainers. The view of the control should be defined in its ContentTemplate property.

WPF access info from the containing Control

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).

Resources