So, I have this ListView that needs to use some custom compare functions depending on what is bound.
Right now the only solution I have found so far is to have a custom property to declare (SortablePropertyName) what has been used as binding source, when using CellTemplates for binding more complex objects, such as object with both icon and text.
...
<ui:MyListView Grid.Row="1" ItemsSource="{Binding SubComponents}" SelectionChanged="SubComponentSelectionChanged" SelectionMode="Extended" VirtualizingStackPanel.IsVirtualizing ="False" Margin="2" DefaultSortingColumnHeader="Label" Grid.ColumnSpan="2">
<ui:MyListView.View>
<GridView>
<ui:MyGridViewColumn Header="Solution" Width="200" SortBy="Context" SortablePropertyName="SolutionVisualizationViewModel">
<GridViewColumn.CellTemplate>
<DataTemplate>
<bcp:MyObjectVisualizationView DataContext="{Binding SolutionVisualizationViewModel}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</ui:MyGridViewColumn>
...
Because later on when dealing with sorting I need information of what property of the ViewModel that has been used for current column.
foreach (MyGridViewColumn column in columns)
{
//Sort by context
if (column.SortBy == MyListViewSorting.SortOption.Context)
{
if (column.SortDirectionType == MyListViewSorting.SortDirectionType.Ascending)
{
listViewCollection.CustomSort = new ContextComparer(column.SortablePropertyName);
}
...
I can by adding DependencyObject data = column.CellTemplate.LoadContent() as DependencyObject; get hold of what view has been used, but still not what I want.
Is there away to find out this binding 'DataContext="{Binding VisualizationViewModel}' associated with a column without having to use a property?
Is there any "links" to be found between bindings and a GridViewColumn to hopefully solve this problem?
Is there away to find out this binding 'DataContext="{Binding VisualizationViewModel}' associated with a column without having to use a property?
You could realize the template using the LoadContent() method and check the DataContext property of the root element in it.
Or, assuming that the template has already been applied, you could use GetCellContent method to get a reference to the root element.
You may also override the GenerateElement method.
But using a property is probably easier.
A template is just a template and there is no element instantiated, binding applied och source value being resolved until it's actually applied. The column doesn't care/know what's in its CellTemplate. It just realizes the template.
Related
I have a user control that has one dependency property. In my window I have a list of objects, and I am creating a uniform grid consisting of my user control. I am setting the ItemsSource to my list of objects, but I need to pass each respective object to the user control. Please see the code below - I need to pass in the Participant object to the LadderControl.
<ItemsControl Grid.Row="2" Name="Participants" ItemsSource="{Binding Path=MyEvent.Participants}">
// more code here, irrelevant
<ItemsControl.ItemTemplate>
<DataTemplate>
<ladder:LadderControl Participant="CURRENT_ITEM_IN_PARTICIPANTS_LIST"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Is there a way I can do this ? Should I be thinking about using a different pattern ?
Thanks
Just do the below, as the Participant is the context of each item
<ladder:LadderControl Participant="{Binding}"/>
You can simply access the DataContext Property in LadderControl to access the currrent participant.
There is no need for a separate dependency property.
class LadderControl
{
...
public IParticipant Participant
{
get{ return DataContext as IParticipant; }
}
...
One solution is to simply do:
<ladder:LadderControl Participant="{Binding Path=.}"/>
{Binding Path=.} should bind to the current element in the ItemsSource list.
I was wandering if someone can explain to me how the Dependency Property DisplayMemberPath works?
I am trying to create Custom ItemsControl that has property like DisplayMemberPath of a ComboBox, in otherwords after setting the ItemsSource I want to be able to specify the Property to Display.
At the moment if I do somthing like:
<cc:MyControl ... DisplayMemberPath="MyObjectDescription" ... >
(Yes I have overridden the DisplayMemberPath, its besides the point).
It displays a list of items, but they each Display "MyObjectDescription", instead of the value that that Property holds for each object in the ItemsSource.
And I believe its because I am missing something in regards to how DisplayMemberPath Property works.
Thanks All. :)
There are two types of DisplayMemberPath. One that supports Binding and one where you have to set a string value. In your case as I can see you wish to implement the second one. To do so create a property inside your custom control of type string and name it DisplayMemberPath. Override the methode OnInitialized in your container with your custom logic where you tell the container to manipulate the path of the binding to DataContext by changing binding's path to the string value as you specified in DisplayMemeberPath. WPF calls OnInitalized once any control is completely initalized but before its about to get rendered. I hope this helps you any futher.
I'm assuming your control is like MyControl and MyControlItem like ListBox and ListBoxItem.
You can access the DisplayMemberPath of MyControl when the MyControlItem is being created and use it to get the data from the DataContext.
Bit late to party, but maybe other could be helped
If your purpose is barely to use Itemscontrol over ListBox/View, you may consider to define the Datatemplate for the itemscontrol's Items instead of packing this in a Usercontrol:
<ItemsControl ItemsSource="{Binding myObjectCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding myObjectProp}"/> (or whatever...)
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I've got a DataGrid whose main purpose is to allow the user to enter data in its cells.
However, the first field in this grid should display the contents of a list.
How would I go about setting the data source for just one column?
EDIT: I want to achieve something like this:
in addition to my comment, one easy way would be to wrap your itemssource collection and add a list for every item - with the data you expect.
the good thing is you do not have to set a different source for your first column, you just have to bind to the new list property
EDIT:
i hope i got your problem.
lets say you have a itemssource for your grid:
List<MyObject> _list;
your myobject contains Asc/Desc, GroupBy, Having, Dispplayorder properties.
so i would create a MyObjectWrapper and add the Field property
public class MyObjectWrapper
{
public MyObject WrappedOject {get;set;}
public string Fields {get;set}
}
you end up with a new
List<MyObjectWrapper> _wrapperlist;
these collection have all information you need to display.
Specify your own DataGridTemplateColumn in DataGrid.Columns, and set the DataGridTemplateColumn.CellTemplate to whatever it is you're looking to place in that column.
For example, if you wanted it to be a ComboBox pointing to some other list of fields:
<DataGrid.Columns>
<DataGridTemplateColumn Header="Fields">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ElementName=MyWindow, Path=DataContext.SomeCategoryList}"
SelectedItem="{Binding SomePropertyOnDataItemInRow}" />
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
I'm using a property called SomeCategoryList that's on MyWindow.DataContext, however you can set the binding to point to wherever your field list is stored
I have a datagrid where i use a foreach(DataGridRow gvr in myDataGrid) and I need to be able to take the info from specific cells in the row and put them into their respective class properties i.e.(a.MessageName = gvr.column["MessageName"].value.ToString()). But I haven't figured out how to get at the info based on the column. Here's what i have so far...
foreach (DataGridRow gvr in dgAnnouncement.Items)
{
Announcement a = new Announcement();
a.MessageName = gvr.Column["MessageName"].Value.ToString();
a.Message = gvr.Column["Message"].Value.ToString();
}
And here's my XAML...
<DataGrid AutoGenerateColumns="False" Height="631" ItemsSource="{Binding}" HorizontalAlignment="Left" SelectionMode="Single" SelectionUnit="FullRow" Margin="12,124,0,0" Name="dgAnnouncement" VerticalAlignment="Top" Width="976" >
<DataGrid.Columns>
<DataGridTextColumn Header="MessageName"></DataGridTextColumn>
<DataGridTextColumn Header="Message"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
After searching the web I still havent found a solution that works for me so thanks in advance for any help.
Ok so it sounds like you want to have a bound list of items that the user can add to and fill in values on
If you want to do this, the best way is via binding on your columns:
<DataGrid AutoGenerateColumns="False" Height="631" ItemsSource="{Binding}" HorizontalAlignment="Left" SelectionMode="Single" SelectionUnit="FullRow" Margin="12,124,0,0" Name="dgAnnouncement" VerticalAlignment="Top" Width="976" >
<DataGrid.Columns>
<DataGridTextColumn Header="MessageName" Binding="{Binding MessageName, Mode=TwoWay}"></DataGridTextColumn>
<DataGridTextColumn Header="Message" Binding="{Binding Message, Mode=TwoWay}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
The question is - what do you have ItemsSource set to at the moment?
Ideally this should be a strongly typed collection of Appointment objects (ObservableCollection<Appointment> maybe). Do you want the users to be able to add new rows? If so you need to either provide a button which performs the Add on the source collection or let the datagrid do it (I think it supports an 'empty row' where you can type values... though I usually use Telerik's RadGridView). Generally when you have a grid that has an empty row for the user to add a new value, the grid will look at the underlying collection that's bound and call the appropriate method to add an item. If this collection doesn't support an Add method (such as IBindingList does) I think the default is to create a new item using the parameterless constructor for the type (not too sure on this, might be worth doing some reading)
Basically, by binding these properties TwoWay it means that each item in the list can be edited by the user directly in the grid. If the user changes a property, that property on the underlying object will be affected*. This means you don't need to write any code to wire this all up. Binding can also be done from control->control so for instance you can bind another grids ItemsSource to the SelectedItems property on your first grid, and it will automatically update with which items you have selected.
Check out my answer here for more info on DataBinding
How does data binding work?
Edit:
I might add that any changes to the underlying object without going through the grid will still show up in the grid but only if the object implements a property changed notification mechanism e.g. INotifyPropertyChanged (in System.ComponentModel namespace)
I have a datagrid with a column containing a ComboBox. I've set the Name for my combobox, but this name is not visible in code, why?
<DataGrid ...>
<DataGrid.Columns>
<DataGrid.TemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Name="mex" Style="{DynamicResource ComboBoxStyle}"
ItemsSource="{Binding Path=combolist}"
SelectionChanged="status_SelectionChanged" Height="auto" Width="Auto">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGrid.TemplateColumn>
...
</DataGrid.Columns>
</DataGrid>
In C# code mex is empty, not visible, why?
I tried x:Name="mex" as well, but it is still not visible.
c#:
mex.ItemsSource = dt;
undifined mex
A DataGridColumn is never actually in the Logical or Visual Tree; it is always a DataGridRow with DataGridCells, since they are automatically created for each row in the DataGrid.
The only way to reach your component is to build a complex Binding or find it using a Logical or Visual Tree helper.
BTW you should set your ItemsSource of your ComboBox through Bindings to available data from your row. You can't create bindings using ElementName within a DataGridTemplateColumn as again it is not in the Logical or Visual Tree.
I found an interesting link that explains the Visual Tree of a DataGrid: http://blogs.msdn.com/b/vinsibal/archive/2008/08/14/wpf-datagrid-dissecting-the-visual-layout.aspx.
You cannot directly reference elements when they are stored within an items template. Normally you'd want to allow the viewmodel to handle the bindings by setting the datacontext to the parent object and then allow the elements within the items template to pick this up. However based upon your question it looks as if you are attempting to do this directly from code behind.
Here are two similar questions and solutions for setting up the datacontext of an item as well as referencing an element within an items template. Hope this helps
Access parent DataContext from DataTemplate
and
WPF - ItemsControl - How do I get find my "CheckBox" item that is in the ItemTemplate?
because template is used by all rows.if name is usable .must have the same name in visual tree at one time.