I'm attempting to essentially wrap the contents of a DataTemplate in a ListView GridViewColumn with a border. What I want to know is if it's possible to supply an adorner that will surround that template so that I don't have to specify the border in every single DataTemplate on every column (which is what I'm doing now). I've got something like this, but I know it's not right:
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="TemplateContent">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<Border BorderBrush="Green" BorderThickness="1">
<AdornedElementPlaceholder />
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This complains that the TemplateContent is not a valid type. I've also tried with DataTemplate and that doesn't work either (understandably so).
I know I could just create a DataTemplate, however the content for each column is different. At the very least, it binds to different fields. I'm wondering if there's a solution using a dynamic resource, but I don't know much about it. Thanks for your help
EDIT: here's a sample of my ListView:
<ListView ItemsSource="{Binding Path=OrderLines}"
ItemContainerStyle="{StaticResource ResourceKey=ListViewItemContainerStyle}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox MaxWidth="30" Width="30" MaxLength="2"
Text="{Binding Path=Quantity,ValidatesOnDataErrors=True}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridView>
<ListView.View>
</ListView>
Essentially I want to wrap that text box in the DataTemplate and any other items in additional columns.
The property needs to be "Template". See here for an example: http://msdn.microsoft.com/en-us/library/ms750821.aspx
Related
ComboBox items were not displaying, if we try to keep that combobox in an ItemsCotrol. Please click here for understanding my requirement
My requirement is to keep a combobox in an ItemsControl, so that the ItemsControl qill be having 5 Comboboxes in it and each combox will be having a collection of items which we can select. So for that i tried with the below code and able to get the comboboxes in the ItemsControl, but the comboboxes collection is getting filled, any suggestions or workaround please..
<xamDataPresenter:Field Label="Reqs" BindingType="Unbound" Row="0" Column="4">
<xamDataPresenter:Field.CellValuePresenterStyle>
<Style TargetType="{x:Type xamDataPresenter:CellValuePresenter}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type xamDataPresenter:CellValuePresenter}">
<ItemsControl Name="I" ItemsSource="{Binding Path=DataItem.CollectionCount}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataItem.Collection}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</xamDataPresenter:Field.CellValuePresenterStyle>
</xamDataPresenter:Field>
Ok, I've written up the most basic of ItemsControl to try and explain how these things work, which you can hopefully adapt for whatever your using for your dataitems.
So in your window's resources i've created a datatemplate. This respresents a repeating step and will be based on a DataItem. In this case my DataItem has 2 properties: DataItemProperty(string) and SelectedItem. The SelectedItem will have the same DataType of whatever it is your planning on showing in the combobox.
<DataTemplate x:Key="StepTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<TextBlock Text="{Binding Path=DataItemProperty}" Grid.Column="0"/>
<ComboBox Grid.Column="1" ItemsSource="{Binding Path=DataContext.ItemsToSelectFrom, Mode=OneWay, RelativeSource={RelativeSource AncestorType=Window}}"
SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</DataTemplate>
The combobox in this example will be getting a list of available options from the code behind/viewmodel and not the DataItem, but when you select something it updates the SelectedItem property on the DataItem.
Then to show your items:
<ItemsControl
Focusable="False"
ItemTemplate="{StaticResource StepTemplate}"
ItemsSource="{Binding Path=Steps, Mode=OneWay}" />
So Steps is a property in my codebehind/viewmodel that will determine how many 'rows' get displayed.
The itemsControl allows you to add repeating sets of data easily, without having to write the same xaml multiple times.
Hope that helps?
I have a problem which it seemed, many other people had before. I try to use a style, which contains a GridView by several controls.
I searched the web for answers and got two solutions:
Change StaticResource with DynamicResource
Use x:shared="False" on the GridView
I tried both solutions (even at the same time) but the error still appears as soon as I'm applying the style to a second control.
The style looks like this
<Style x:Key="MyCustomStyle" TargetType="{x:Type MyUserControl}" BasedOn="{StaticResource MyUserControlBaseStyle}">
<Setter Property="Watermark" Value="{x:Static LabelResources.Caption}"/>
<Setter Property="ErrorText" Value="{Binding Converter={StaticResource FormatStringConverter}, ConverterParameter={x:Static LabelResources.Caption}}"/>
<Setter Property="LookupTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type LookupResult}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="0,0,2,0"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="SuggestionsView" Value="{DynamicResource CustomGridView}"/>
</Style>
and here the GridView
<GridView x:Key="CustomGridView" x:Shared="False">
<GridViewColumn Header="{x:Static resources:LabelResources.Name}" Width="Auto" HeaderContainerStyle="{DynamicResource GridViewHeaderStyle}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Left"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
What can I do?
It sounds like you only have one single instance of CustomGridView created, and you are trying to assign it to multiple places, which is causing the exception.
According to the MSDN page on x:Shared
In WPF, x:Shared is only valid under the following conditions:
The ResourceDictionary that contains the items with x:Shared must be compiled. The ResourceDictionary cannot be within loose XAML or used
for themes.
The ResourceDictionary that contains the items must not be nested within another ResourceDictionary. For example, you cannot use
x:Shared for items in a ResourceDictionary that is within a Style that
is already a ResourceDictionary item.
I'm not exactly sure what it means to be a Compiled ResourceDictionary, but you could try changing the Build Action to Page instead of Resource, like this answer suggests.
If you can't get x:Shared working, then perhaps consider making SuggestionsView a ContentTemplate or DataTemplate instead so each use of it will create it's own GridView.
<ContentTemplate x:Key="CustomGridView">
<GridView>
<GridViewColumn Header="{x:Static resources:LabelResources.Name}" Width="Auto" HeaderContainerStyle="{DynamicResource GridViewHeaderStyle}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Left"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ContentTemplate>
I have a WPF ListView/GridViwe in a MVVM application. GridView is bound to a List in the ViewModel.
The requirement is that the users should be able to select multiple rows of the gridview, right-click on it and see a context menu "Group These Together". Once selected, all these items should be collapsed into one group with a expander or + sign added at the beginning.
Can somebody please help me in getting this working?
I was working on similar problem, but I had to group items by their let's say name. What I've done was create DataTrigger or MultiDataTrigger depending on your data requirements and then when conditions are true i.e. item selected change the container for GroupItem. What I mean is when you create your list view, you have to create it with grouped view, which btw is not grouped as you can declare it without expander and just use the StackPanel. After that you need 3 lines of Code to set the grouping. Here is an example for you:
MAIN.xaml
<ListView
ScrollViewer.CanContentScroll="False"
x:Name="lsvProducts"
ItemsSource="{Binding Products, NotifyOnSourceUpdated=True}"
MouseDown="lsvProducts_MouseDown">
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" Header="Code" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Width="Auto" Header="Description" DisplayMemberBinding="{Binding Desc}"></GridViewColumn>
<GridViewColumn Width="Auto" Header="Qty" DisplayMemberBinding="{Binding Qty}"></GridViewColumn>
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource GroupedView}"/>
</ListView.GroupStyle>
</ListView>
As you can see I have declared an empty container for the grouped style, reson why is because you can't assign it without previous declaration. After this declaration you need this in your generic.xaml
<Style x:Key="GroupedView" TargetType="{x:Type GroupItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=chbx, Path=IsChecked}" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="False">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="Gray" FontSize="22" VerticalAlignment="Bottom" />
<TextBlock Text="{Binding ItemCount}" FontSize="16" Foreground="DimGray" FontWeight="Bold" FontStyle="Italic" Margin="10,0,0,0" VerticalAlignment="Bottom" />
<TextBlock Text=" item(s)" FontSize="16" Foreground="Silver" FontStyle="Italic" VerticalAlignment="Bottom" />
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
After you declared your style for the true value you need to declare one for without expander
<!--This goes in the same style as the prevoius sample code -->
<DataTrigger Binding="{Binding ElementName=chbx, Path=IsChecked}" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<ItemsPresenter />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
Next step is to define the grouping:
//lsvProducts is our ListView
view = (CollectionView) CollectionViewSource.GetDefaultView(lsvProducts.ItemsSource);
//in the creation parameter you should put field that you want to group by :-)
PropertyGroupDescription grouping = new PropertyGroupDescription("FieldToGroupBy");
view.GroupDescriptions.Add(grouping);
Which should apper in your ViewModel.
Good luck!
Let us know if you need any more help, I'll try my best with my English ;-)
EDIT
I forgot to mention when you assign the grouping you need to check the number of groups already in the collection and only apply it when there is non or 0, otherwise you'll apply the grouping multiple times and the expander will be repeeated in the result window as many times as you added the grouping :-)
What in my mind to select multiple row Ctrl+click
It will select multiple row and on right click open a context menu after setting its Isopen to true
You should also bind selected item to list and Use this item to make an expander
I have some ListView's which bind to collections in the ViewModel. The type of items in those collections are the same (let's call them TypeA) which is a class exposing multiple simple type properties. I would like to display them in a GridView inside the ListView. Naturally, I would want to define a DataTemplate for this TypeA so that I don't have to duplicate the same XAML for each of the ListView's. All of the examples I've found so far define the ItemTemplate inside the ListView. How can I make a resource and let different ListView's refer to this single resource?
UPDATE:
I am posting my XAML code for better clarification. My original XAML code (simplified) looks like this:
<ListView ItemsSource="{Binding MYCOLLECTION}" SelectionMode="Extended" >
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Prop1}" >
<GridViewColumn.Header>
<Border >
<TextBlock Text="Prop1" />
</Border>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Prop2}" >
<GridViewColumn.Header>
<Border >
<TextBlock Text="Prop2" />
</Border>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Prop3}" >
<GridViewColumn.Header>
<Border >
<TextBlock Text="Prop3" />
</Border>
</GridViewColumn.Header>
</GridViewColumn>
...
</GridView>
</ListView.View>
</ListView>
I have many dependency properties set to the headers and that's why I put individual Header items as well as why my code is really long--hence why I'm seeking to use a datatemplate.
So my idea is that I can show different selections of the same type in the same way in different GridView's (because we want the column headers to display the names of the properties so we use GridView).
BTW those are not the only places I am presenting this data type, so I definitely need to specify a Resource key and restrict this to be used only for GridView. And because I want to display in a Grid way, I assume can't define a DataTemplate for my type and use it as ItemTemplate in a ListView.
You do not even have to define a resource key just set the DataType because that will be used as a key internally by WPF. Just make sure your datatemplates are visible from any control where you want to use it, they will be automatically applied. (Just for example you can define them at application level in the resources of App.xaml, but you probably have separate resource dictionaries):
<Application x:Class="WpfTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dataModel="clr-namespace:DataModel"
StartupUri="MainWindow.xaml">
<Application.Resources>
<DataTemplate DataType="{x:Type dataModel:GreekGod}">
<TextBlock Text="{Binding Path=Name}" Foreground="Gold"/>
</DataTemplate>
</Application.Resources>
</Application>
For your code you need to define templates for each property because you are using it as a grid and you need to set the cell template for each column after removing the DisplaymemberBinding:
<GridViewColumn CellTemplate="{StaticResource prop1Template}">
<GridViewColumn.Header>
<Border >
<TextBlock Text="Prop1" />
</Border>
</GridViewColumn.Header>
</GridViewColumn>
...
And put the resource in a visible place just as mentioned before like in the Application resources:
<Application.Resources>
<DataTemplate x:Key="prop1Template">
<TextBlock Text="{Binding Prop1}" Foreground="Red"/>
</DataTemplate>
</Application.Resources>
You can use a ColumnHeaderTemplate and a ColumnContainerStyle like this:
<GridView
ColumnHeaderTemplate="{StaticResource myHeaderTemplate}"
ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}"
>
<GridViewColumn Header="Prop1" CellTemplate="{StaticResource prop1Template}"/>
...
where the resources are for example:
<Style x:Key="myHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Background" Value="LightBlue"/>
</Style>
<DataTemplate x:Key="myHeaderTemplate">
<DockPanel>
<CheckBox/>
<TextBlock FontSize="16" Foreground="DarkBlue">
<TextBlock.Text>
<Binding/>
</TextBlock.Text>
</TextBlock>
</DockPanel>
</DataTemplate>
Just create the DataTemplate in the Controls/Windows resources as you would do in the ListViews ItemTemplate and add x:Key="someKey" to it.
Now you can refer to it like so:
<ListView ItemTemplate="{StaticResource someKey}"/>
Ok, this is an embarassingly simple-looking problem, but is driving me crazy. I'm learning about DataTemplating and am trying to apply a very VERY simple ItemTemplate to a ListBox.
However, when I run my app, the template is completely ignored and I just get the standard-looking listbox, whereas in fact I'd expect to see a list of checkboxes with 'Test' along side.
I've tried this several times and always the same result. I've checked several resource on Google and all have the same kind of syntax for defining and ItemTemplate on a ListBox, so I really cannot see where I'm going wrong.
Code...
<Grid x:Name="LayoutRoot">
<ListBox x:Name="TestList"
SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox Content="Check this checkbox!"/>
<TextBlock>Test</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<ListBoxItem>Bob</ListBoxItem>
<ListBoxItem>Jim</ListBoxItem>
<ListBoxItem>Dave</ListBoxItem>
<ListBoxItem>Larry</ListBoxItem>
<ListBoxItem>Tom</ListBoxItem>
</ListBox.Items>
</ListBox>
</Grid>
Any help greatly appreciated. Sorry for such a dumb-seeming question, but I've really fallen at the first hurdle here :(
AT
ItemTemplate wont work when you put ListBoxItem directly as items. General concept is you databind a CRL collection to the ListBox.ItemsSource and then specify the ItemTemplate. Check the below code.
<Grid x:Name="LayoutRoot">
<ListBox x:Name="TestList" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox Content="Check this checkbox!"/>
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<sys:String>Bob</sys:String>
<sys:String>Jim</sys:String>
<sys:String>Dave</sys:String>
<sys:String>Larry</sys:String>
<sys:String>Tom</sys:String>
</ListBox.Items>
</ListBox>
</Grid>
where sys is xmlns:sys="clr-namespace:System;assembly=mscorlib"
In this way, there are 5 ListBoxItems getting generated in the background and added to the ListBox.
You can use ItemContainerStyle instead of ItemTemplate if you want to add ListBoxItems directly to the ListBox.
Doing so, however, is only recommended when you need unique characteristics on a per item level.
If you are planning on all the items looking the same or making a dynamic list using ItemsSource, I would recommend you add strings (or another custom object) to your list and use ItemTemplate to display your items. (see Jobi Joy's answer)
Here's an example using ItemContainerStyle:
<ListBox
x:Name="TestList"
SelectionMode="Multiple">
<ListBox.ItemContainerStyle>
<Style
TargetType="ListBoxItem">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="ListBoxItem">
<StackPanel>
<CheckBox
Content="Check this checkbox!" />
<TextBlock
Text="{TemplateBinding Content}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Items>
<ListBoxItem>Bob</ListBoxItem>
<ListBoxItem>Jim</ListBoxItem>
<ListBoxItem>Dave</ListBoxItem>
<ListBoxItem>Larry</ListBoxItem>
<ListBoxItem>Tom</ListBoxItem>
</ListBox.Items>
</ListBox>
For some reason DataTemplate can still be ignored if the ListBox is populated using ItemsSource e.g:
<ListBox Name="Test" x:FieldModifier="public" ItemsSource="{Binding UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note that this is bound to an ObservableCollection containing objects (TextAdapter : INotifyPropertyChanged) with one property: string Text {...}