Create a custom ListViewItem (subclass ListViewItem) - wpf

I derived a class from ListViewItem, it has some custom dependency properties:
public class CustomListViewItem : ListViewItem
{
public static DependencyProperty CustomDependencyProperty;
...
}
There is also a ControlTemplate for this class.
<Style TargetType="{x:Type local:CustomListViewItem}">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomListViewItem}">
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Now I want to use this CustomListViewItem in a ListView instead of ListViewItem. But when I try to do something like:
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type local:CustomListViewItem}">
...
</Style>
</ListView.ItemContainerStyle>
compiler says: "A style intended for type 'CustomItem' cannot be applied to type 'ListViewItem".
I know that I can use ControlTemplate with ListViewItem TargetType to customize ItemContainerStyle or DataTemplate to customize ItemTemplate, but how can I subclass ListViewItem to substitute my own Item type?
Any help will be appreciated.

I found the answer after considering this question. The core idea is that it is necessary to create not only a custom ListViewItem, but also a custom ListView and override GetContainerForItemOverride() method for it:
public class CustomListView : ListView
{
static CustomListView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomListView), new FrameworkPropertyMetadata(typeof(CustomListView)));
}
protected override DependencyObject GetContainerForItemOverride()
{
return new CustomListViewItem();
}
}
Of course, it's also necessary to provide a proper ControlTemplate for a CustomListView.
Also PrepareContainerForItemOverride method will be useful.

Related

Height setter ignored on custom Window

I added a Custom Control to my project and changed the parent type to Window. I show it on a button click.
I have style setters for height and width, but only the one defined first in the xaml has effect. The other shows larger than styled.
Anyone know what's happening here?
In generic.xaml:
<Style TargetType="{x:Type local:ChildWindow}">
<Setter Property="Width" Value="300"/>
<Setter Property="Height" Value="300"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ChildWindow}">
<TextBlock Background="White">Child window</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ChildWindow.cs is default except the parent is now "Window":
public class ChildWindow : Window
{
static ChildWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ChildWindow), new FrameworkPropertyMetadata(typeof(ChildWindow)));
}
}
MainWindow.xaml.cs shows the ChildWindow:
private void Button_Click(object sender, RoutedEventArgs e)
{
var childWindow = new ChildWindow();
childWindow.Show();
}
Workaround:
I haven't found why it behaves like that, or how to make the style setters work, but a workaround is to get rid of the style setters and set the default values for the Width and Height dependency properties. I did this in the static constructor:
static ChildWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ChildWindow), new FrameworkPropertyMetadata(typeof(ChildWindow)));
// Get rid of the style setters and add this:
WidthProperty.OverrideMetadata(typeof(ChildWindow), new FrameworkPropertyMetadata(300.0));
HeightProperty.OverrideMetadata(typeof(ChildWindow), new FrameworkPropertyMetadata(300.0));
}

How to style child of a UserControl in XAML in Silverlight?

I have a UserControl MyParentControl which has another control inside (TreeView). I expose this control as a dep property say TreeView MyChildControl.
Then in XAML which uses MyParentConrol I want to access all the TreeView properties, for example Style.
I want to write something like:
<my:MyParentControl>
<my:MyParentControl.MyChildControl.Style>
<Style />
</my:MyParentControl.MyChildControl.Style>
</my:MyParentControl>
Is there a way to achieve that?
By exposing the DependencyProperty for your inner control you have solved half of the problem - ie you can set individual properties in xaml.
The next step is to have those property setters affect the child control.
There are two options to achieve that.
In your control template, define your child control and use Bindings on each property you want to set.
Define a container element in your parent control template and set it's content to your child whenever the dependency property changes.
Although both of these methods could work, you may find that the solution involving the least amount of code, and the greatest amount of flexibility, is to expose a Style property for your child control and apply that in the control template.
public class ParentControl : Control
{
public Style ChildControlStyle
{
get { return (Style)GetValue(ChildControlStyleProperty); }
set { SetValue(ChildControlStyleProperty, value); }
}
public static readonly DependencyProperty ChildControlStyleProperty =
DependencyProperty.Register("ChildControlStyle",
typeof(Style),
typeof(ParentControl),
new PropertyMetadata(null));
}
<Style TargetType="ParentControl">
<Setter Property="ChildControlStyle">
<Setter.Value>
<Style TargetType="ChildControl">
<!-- setters -->
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ParentControl">
<Grid>
<ChildControl Style="{TemplateBinding ChildControlStyle}" />
<!-- other stuff -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You would get that effect by writing XAML like this:
<my:MyParentControl>
<my:MyParentControl.Resources>
<Style TargetType="my:MyChildControl">
<Setter Property="Background" Value="Red"/>
</Style>
</my:MyParentControl.Resources>
<my:MyParentControl>
In this example, this XAML creates a MyParentControl in which all the children of type MyChildControl have red backgrounds.

How to override base style control template in derived style in WPF?

I have a style for button. That style contains the ControlTemplate for Button. The ControlTemplate contains an Image with name "ImgButton".
I want to make this style as base style for other Buttons and want to override the "Source" property of Image control for different buttons.
Any ideas?
You may create attached behavior that will offer a property to assign Source. You should bind your image to this property in a template using TemplatedParent as RelativeSource. In derived styles you can simply use Setter(s) to specify a different Source.
Attached behavoir:
public static class ImageSourceBehavior
{
public static readonly DependencyProperty SourceProperty = DependencyProperty.RegisterAttached(
"Source", typeof(ImageSource), typeof(ImageSourceBehavior),
new FrameworkPropertyMetadata(null));
public static ImageSource GetSource(DependencyObject dependencyObject)
{
return (ImageSource)dependencyObject.GetValue(SourceProperty);
}
public static void SetSource(DependencyObject dependencyObject, ImageSource value)
{
dependencyObject.SetValue(SourceProperty, value);
}
}
Styles:
<Style x:Key="Style1"
TargetType="Button">
<Setter Property="local:ImageSourceBehavior.Source"
Value="..."/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Image Source="{Binding Path=(local:ImageSourceBehavior.Source),RelativeSource={RelativeSource TemplatedParent}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="Style2"
BasedOn="{StaticResource Style1}"
TargetType="Button">
<Setter Property="local:ImageSourceBehavior.Source"
Value="..."/>
</Style>

Silverlight element to element binding in generic.xaml

Is there a way to have element to element binding in Silverlight templated controls?
Example: I have two custom controls, SomeControl and CustomSlider. SomeControl has a dependency property called someValue. I want to bind the value of CustomSlider to this property, so my generic.xaml file looks like this:
<Style TargetType="local:SomeControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SomeControl">
<...>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:CustomSlider">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CustomSlider">
<Slider Value="{Binding someValue, ElementName=local:SomeControl}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and this is my dependency property:
public int someValue,
{
get { return (int)GetValue(someValueProperty); }
set { SetValue(someValueProperty, value); }
}
public static readonly DependencyProperty (someValueProperty) =
DependencyProperty.Register(someValue); typeof(int), typeof(SomeControl,
new PropertyMetadata(0));
This throws an "BindingExpression_CannotFindElementName" exception.
You can't use it like this. A binding through ElementName should be used to specific element instance, not style. You can create other dependency property, say SliderValue in your CustomSlidercontrol and bind to it.
<local:SomeControl x:Name="SomeControl"/>
<local:CustomSlider SliderValue="{Binding someValue, ElementName=SomeControl}"/>
And change your Slider Value from template when your SliderValue property changes;

WPF Setting on a Control Template

General question. I have a ControlTemplate that is reasonably complex. Several TextBoxes etc.
I can't use TemplateBinding to bring all the properties to the surface so that I can set all the styles.
Is there a way for a Style to 'delv' into the controls within a control to set values?
Hope my question is clear without an example.
Thanks
The short answer is no. The ControlTemplate is essentially a black box, at least where XAML is concerned (there are ways to dig down the visual tree in code).
When you say you "can't use TemplateBinding", why not? If you just don't have enough available properties that can be fixed by creating some attached properties for the values you want to pass through. This is assuming you're templating a control that you can't change, otherwise you can just add new dependency properties.
Attached property:
public static class CustomProps
{
public static readonly DependencyProperty MyNewBrushProperty = DependencyProperty.RegisterAttached(
"MyNewBrush",
typeof(Brush),
typeof(CustomProps),
new UIPropertyMetadata(Brushes.Green));
public static Brush GetMyNewBrush(DependencyObject target)
{
return (Brush)target.GetValue(MyNewBrushProperty);
}
public static void SetMyNewBrush(DependencyObject target, Brush value)
{
target.SetValue(MyNewBrushProperty, value);
}
}
And usage in Style and Template:
<Style TargetType="{x:Type Button}">
<Setter Property="local:CustomProps.MyNewBrush" Value="Red" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:CustomProps.MyNewBrush)}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Using this method also still allows overriding values on individual instances.

Resources