I used for the first time a custom Control (wpf). Here is what I want:
I want a Custom ListView with Custom ListViewItem (the challenge is I don’t know what’s on the “Form”, I just know it’s a Panel
- I call "Form" what's on the ListViewItem ).
I have a CustomListView and a CustomListViewItem :
EDIT : CustomListView.cs
public class CustomListView : ItemsControl
{
public static readonly DependencyProperty ListContentProperty = DependencyProperty.Register("ListContent", typeof(IList), typeof(CustomListView), new PropertyMetadata());
public IList ListContent
{
get { return (IList)GetValue(ListContentProperty); }
set { SetValue(ListContentProperty, value); }
}
public CustomListView(ContentControl contentControl, IList list)
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomListView), new FrameworkPropertyMetadata(typeof(CustomListView)));
DataContext = list;
ItemsSource = list;
CustomListViewItem customListViewItem = new CustomListViewItem();
customListViewItem.Content = contentControl;
string xamlTemplate = XamlWriter.Save(customListViewItem);
string template =
"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>" +
xamlTemplate +
"</DataTemplate>";
ItemTemplate = (DataTemplate)XamlReader.Parse(template);
SetValue(TemplateContentProperty, contentControl);
}
}
EDIT : CustomListViewItem .cs
public class CustomListViewItem : ContentControl
{
public static readonly DependencyProperty MyEventProperty = DependencyProperty.Register("MyEvent", typeof(EventHandler), typeof(CustomListViewItem));
public static readonly DependencyProperty ListContentItemProperty = DependencyProperty.Register("ListContentItem", typeof(IList), typeof(CustomListViewItem), new PropertyMetadata());
public IList ListContentItem
{
get { return (IList)GetValue(ListContentItemProperty); }
set { SetValue(ListContentItemProperty, value); }
}
public EventHandler MyEvent
{
get { return (EventHandler)GetValue(MyEventProperty); }
set { SetValue(MyEventProperty, value); }
}
public CustomListViewItem()
{
DefaultStyleKey = typeof(CustomListViewItem);
}
//Some method for the Event on my button
The DataContext
of the CustomListView is an ObservableCollection. When I create the “Form” directly on my CustomListViewItem, everything is perfect. I can sort with my button, add a new empty Form…
Now here is my problem.
Let’s say we have a class Person (with only a name) who implements INotifyPropertyChanged
. We create some “Person” and add them to an ObservableCollection
. On a new xaml element, we create a Template (PersonEditor) the “Form”, with some Binding.
What I want on the MainWindows
is something like that:
CustomListView customListView = new CustomListView(new PersonEditor(), _person);
myContentControl.Content = customListView;
Where _person is the ObservableCollection
. We give the Template of the Form to the CustomListViewItem and add it to a content of a ContentControl
EDIT : Generics.xaml :
<Style x:Key="{x:Type customControl:CustomListView}" TargetType="customControl:CustomListView" BasedOn="{StaticResource {x:Type ItemsControl}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type customControl:CustomListView}">
<Border>
<ItemsPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Type customControl:CustomListViewItem}" TargetType="customControl:CustomListViewItem" BasedOn="{StaticResource {x:Type ContentControl}}">
<Setter Property="ListContentItem">
<Setter.Value>
<Binding Path="ListContent" RelativeSource="{RelativeSource FindAncestor,AncestorType=customControl:CustomListView}"></Binding>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="customControl:CustomListViewItem">
<Border Background="White" x:Name="borderSelect" Padding="0" Width="Auto" Height="Auto">
<DockPanel Width="Auto" Height="Auto" VerticalAlignment="Stretch">
<ContentPresenter/>
<StackPanel Orientation="Horizontal">
<StackPanel SnapsToDevicePixels="true" Orientation="Vertical" Margin="0">
<StackPanel SnapsToDevicePixels="true" Orientation="Horizontal" Margin="0">
<Button SnapsToDevicePixels="true" Style="{StaticResource SquareCorner}" Opacity="0.0" Margin="0 7 0 0" Height="30" Width="12" VerticalAlignment="top" HorizontalAlignment="Right" Content="x" Padding="0" x:Name="DeleteButton" Command="{TemplateBinding MyEvent}"/>
<StackPanel SnapsToDevicePixels="true" Orientation="Vertical">
<Button Style="{StaticResource RoundUpCorner}" Opacity="0.0" Margin="0 7 0 0" Height="15" Width="15" VerticalAlignment="top" HorizontalAlignment="Right" Content="^" Padding="0 0 0 5" x:Name="UpButton" Command="{TemplateBinding MyEvent}"/>
<Button Style="{StaticResource RoundDownCorner}" Opacity="0.0" Height="15" Width="15" VerticalAlignment="top" HorizontalAlignment="Right" Content="v" Padding="0" x:Name="DownButton" Command="{TemplateBinding MyEvent}"/>
</StackPanel>
</StackPanel>
</StackPanel>
<DockPanel VerticalAlignment="Stretch">
<Button Style="{StaticResource SquareLittleCorner}" DockPanel.Dock="Top" Opacity="0.0" Height="15" Width="15" VerticalAlignment="top" HorizontalAlignment="Right" Margin="1 0 0 0" Content="+" Padding="0" x:Name="AddUpButton" Command="{TemplateBinding MyEvent}"/>
<Button Style="{StaticResource SquareLittleCorner}" DockPanel.Dock="Bottom" Opacity="0.0" Height="15" Width="15" VerticalAlignment="bottom" HorizontalAlignment="Right" Margin="1 0 0 0" Content="+" Padding="0" x:Name="AddButton" Command="{TemplateBinding MyEvent}"/>
</DockPanel>
</StackPanel>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The result is I only have one element that has the good Template, the other ones are created but empty.
I think the problem comes from the binding. But I don’t know what to do. I tried to create a new “Form” with xamlReader/xamlLoad (How can you clone a WPF object?) but with the binding again it’s not good. I also tried to clone the xaml but again, no binding and no event on button.
I don’t know what else I can do to solve this problem ? It’s my first time with a custom control so if I made a mistake (anything) just share please.
EDIT
I think my custom is better now, I follow the idea of the DataTemplate
and ContentControl
mix with xamlReader/xamlLoad. The Binding is good (same for Event). But, why when I used it before (like a Content not a Template) the Binding wasn't good ? And I don't know if xamlReader/xamlLoad is a good way to do that (I mean it looks more like some cheat).