Use Custom Control binding in DataTemplate - c#

I just want make some of my custom control for the render performance.
And Bind my Data
making custom control is OK, but i can't set dependancyProperty for data bind.
I made a Custom Control File
CustomCotrol1.cs
public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(string), typeof(CustomControl1), new PropertyMetadata(0));
}
And set my Generic.xml
<Style TargetType="{x:Type views:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type views:CustomControl1}">
<Button
Width="50"
Height="50"
Content="{TemplateBinding MyProperty}"
>
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And use it in my view
<ListBox x:Name="TestListBox" Grid.Row="0"
ItemsSource="{Binding DataList}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<RichTextBox
Grid.Row="0"
TextChanged="rtb_TextChanged"
HorizontalAlignment="Left"
>
<RichTextBox.Resources>
<Style TargetType="{x:Type Paragraph}">
<Setter Property="TextAlignment" Value="Right"/>
<Setter Property="Margin" Value="0" />
</Style>
</RichTextBox.Resources>
<FlowDocument>
<Paragraph>test <Bold>test111</Bold></Paragraph>
</FlowDocument>
</RichTextBox>
<local:CustomControl1
MyProperty="{Binding MSG}"
/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
also it is my viewmodel
public class TestListViewModel : ViewModelBase
{
private ObservableCollection<TestMsgModel> _dataList = new ObservableCollection<TestMsgModel>();
public ObservableCollection<TestMsgModel> DataList
{
get => _dataList;
set
{
_dataList = value;
OnPropertyChanged("DataList");
}
}
public void OnPropertyChanged(string PropertyName)
{
if (PropertyChangedHandler != null)
{
PropertyChangedHandler(this, new PropertyChangedEventArgs(PropertyName));
}
}
public TestListViewModel()
{
TestMsgModel testMsgModel = new TestMsgModel();
testMsgModel.MSG = "TEST MSG 1";
DataList.Add(testMsgModel);
}
}
When i remove the DependencyProperty in CustomControl, it works!
But if not remove, there are some error.
How do i???

Thank you, Clemens
I just changed "new PropertyMetadata(0));" to "new PropertyMetadata(null));"
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(string), typeof(CustomControl1), new PropertyMetadata(0));
Change to
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(string), typeof(CustomControl1), new PropertyMetadata(null));
It is solved.

Related

Databinding with User Control not working for button background image source

I have added a user control to App.xml
<Grid>
<Button Style="{StaticResource PlayerButtonsStyle}"
Width="{Binding ElementName=UC, Path=ImageWidth}"
Height="{Binding ElementName=UC, Path=ImageHeight}">
<Button.Background>
<ImageBrush ImageSource="{Binding ElementName=UC, Path=Image}" />
</Button.Background>
</Button>
</Grid>
In my main window I add following to add the button. And this does not display the image which I have added as a resource.
<local:ImageButton HorizontalAlignment="Left"
Height="25"
Margin="474,430,0,0"
VerticalAlignment="Top"
Width="25"
Image="images/play.png">
</local:ImageButton>
But if I do following the image will display but this defeats the purpose of making it as a user control.
<local:ImageButton HorizontalAlignment="Left"
Height="25"
Margin="474,430,0,0"
VerticalAlignment="Top"
Width="25"
Image="images/forward.png">
<local:ImageButton.Background>
<ImageBrush ImageSource="images/play.png"/>
</local:ImageButton.Background>
</local:ImageButton>
Here is the User Control
public partial class ImageButton : UserControl
{
public ImageButton()
{
InitializeComponent();
}
public ImageSource Image
{
get { return (ImageSource)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
// Using a DependencyProperty as the backing store for Image. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ImageProperty =
DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageButton), new UIPropertyMetadata(null));
public double ImageWidth
{
get { return (double)GetValue(ImageWidthProperty); }
set { SetValue(ImageWidthProperty, value); }
}
// Using a DependencyProperty as the backing store for ImageWidth. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ImageWidthProperty =
DependencyProperty.Register("ImageWidth", typeof(double), typeof(ImageButton), new UIPropertyMetadata(16d));
public double ImageHeight
{
get { return (double)GetValue(ImageHeightProperty); }
set { SetValue(ImageHeightProperty, value); }
}
// Using a DependencyProperty as the backing store for ImageHeight. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ImageHeightProperty =
DependencyProperty.Register("ImageHeight", typeof(double), typeof(ImageButton), new UIPropertyMetadata(16d));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ImageButton), new UIPropertyMetadata(""));
}
The style definition
<Style x:Key="PlayerButtonsStyle" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<!--<Setter Property="Margin" Value="5"/>-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border" BorderThickness="1" BorderBrush="DarkGray" CornerRadius="3" Background="{TemplateBinding Background}" >
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="Black" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="CornerRadius" Value="3" />
</Trigger>
<Trigger Property="Button.IsPressed" Value="True" >
<Setter TargetName="border" Property="BorderBrush" Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
What am I missing ?

Can I bind/set a dependency property of type Type to DataType of a DataTemplate

I am creating Custom User Control. My goal is to make the control reusable.
I am using ItemsControl, here is XAML
<ItemsControl ItemsSource="{Binding Path=ItemSource , RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls:MyItemsControlWithButtons}}}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type Type=typeOf(DataTemplateType)????}">
<ContentControl x:Name="instruction" Content="{Binding Path=DataTemplateControl, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type controls:MyItemsControlWithButtons}}}"/>
<DataTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="#DDDDDD" TargetName="instruction" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="#EEEEEE" TargetName="instruction" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Here is control:MyItemsControlWithButtons
public partial class DraggableItemsControlWithButtons : UserControl
{
public DraggableItemsControlWithButtons()
{
InitializeComponent();
}
public static readonly DependencyProperty DataTemplateTypeProperty =
DependencyProperty.Register(nameof(DataTemplateType), typeof(Type), typeof(DraggableItemsControlWithButtons), new UIPropertyMetadata(null));
public Type DataTemplateType
{
get { return (Type)GetValue(DataTemplateTypeProperty); }
set { SetValue(DataTemplateTypeProperty, value); }
}
public static readonly DependencyProperty ItemSourceProperty =
DependencyProperty.Register(nameof(ItemSource), typeof(IEnumerable), typeof(DraggableItemsControlWithButtons), new UIPropertyMetadata(null));
public IEnumerable ItemSource
{
get { return (IEnumerable)GetValue(ItemSourceProperty); }
set { SetValue(ItemSourceProperty, value); }
}
public static readonly DependencyProperty DataTemplateControlProperty =
DependencyProperty.Register(nameof(DataTemplateControl), typeof(Control), typeof(DraggableItemsControlWithButtons), new UIPropertyMetadata(null));
public Control DataTemplateControl
{
get { return (Control)GetValue(DataTemplateControlProperty); }
set { SetValue(DataTemplateControlProperty, value); }
}
}
As you can see I want to bind/set DataTemplateType to DataType of the ItemsControl.ItemTemplate's DataTemplate
How can I achieve it?
Thank you
You could probaby simplify your control by replacing the DataTemplateControl property by an ItemTemplate property. And to complete the similarity with an ItemsControl, rename the ItemSource property to ItemsSource.
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register(
nameof(ItemsSource), typeof(IEnumerable),
typeof(DraggableItemsControlWithButtons));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemTemplateProperty =
DependencyProperty.Register(
nameof(ItemTemplate), typeof(DataTemplate),
typeof(DraggableItemsControlWithButtons));
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemSourceProperty); }
set { SetValue(ItemSourceProperty, value); }
}
The ItemsControl in the UserControl's XAML would look like this:
<ItemsControl
ItemsSource="{Binding ItemsSource,
RelativeSource={RelativeSource AncestorType=UserControl}}"
ItemTemplate="{Binding ItemTemplate,
RelativeSource={RelativeSource AncestorType=UserControl}}" />
You would then assign the ItemTemplate just like in any other control with an ItemTemplate property:
<local:DraggableItemsControlWithButtons ItemSource="{Binding ...}">
<local:DraggableItemsControlWithButtons.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</local:DraggableItemsControlWithButtons.ItemTemplate>
</local:DraggableItemsControlWithButtons>

AutomationProperties.AutomationId on custom control not exposed

I've been banging my head against this problem for 3 days and haven't been able to find an answer.
I've got an application written in WPF (dot Net 4.5) and I'm working with Teststack.White trying to write some automated GUI test cases. The developers have given x:Names to some of the controls and they show up through Inspect/WPF Inspector/Visual UI Automation Verify as the AutomationId just fine.
There are other controls that are buried a bit deeper that I've been tasked with giving automation ids to (mostly as an exercise so I can get more familiar with the back-end). This is where I've been banging my head against things.
I've tried giving the controls the AutomationProperties.AutomationId (and .Name) attribute. I've given AutomationProperties a name space definition. As well I've made sure SWA.Peers is referenced.
I haven't tried using property setters in XAML as they don't make much sense currently and I'm hoping don't need to write stuff in C# to set them (if I do, I'll do it but just hoping).
One of my co-workers sat down and we pulled out the bare minimum setup that isn't exposing the Automation ID property (unfortunately he as well as the other devs are drawing a blank as to why this isn't happening). It looks like:
MainWindow.xaml:
<Window x:Class="TestAutomationUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:autoProp="clr-namespace:System.Windows.Automation;assembly=PresentationCore"
xmlns:common="clr-namespace:Asi.Ui.Common"
Title="Test UI (Pick me)" Height="455.075" Width="525">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/IconLabelButton.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel x:Name="PresentationRoot">
<common:IconLabelButton x:Name="TestButton" autoProp:AutomationProperties.AutomationId="TestButtonClick" Text="Stuff" Margin="245,0,214.4,0" RenderTransformOrigin="4.648,0.588" Height="32">
</common:IconLabelButton>
</StackPanel>
</Window>
IconLabelButton.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:autoProp="clr-namespace:System.Windows.Automation;assembly=PresentationCore"
xmlns:common="clr-namespace:Asi.Ui.Common">
<Style TargetType="common:IconLabelButton">
<Setter Property="Template" Value="{DynamicResource Asi.Ui.Common.IconLabelButton}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="FontWeight" Value="{DynamicResource Mobius.UI.Resources.Fonts.WeightLight}"/>
<Setter Property="Spacing" Value="10" />
</Style>
<ControlTemplate x:Key="Asi.Ui.Common.IconLabelButton" TargetType="common:IconLabelButton">
<Border Background="{TemplateBinding Background}" Height="30">
<Button Style="{DynamicResource Mobius.UI.Resources.Styles.IconButton}" Margin="0" Padding="0" HorizontalContentAlignment="Stretch" HorizontalAlignment="Left"
Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}" Foreground="{TemplateBinding Foreground}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22" />
<ColumnDefinition Width="{TemplateBinding Spacing}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="22" Height="22">
<Path Margin="1" Height="20" Width="20" Fill="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ContentControl}}}" Data="{TemplateBinding Icon}" Stretch="Fill"/>
<Path Margin="1" Height="20" Width="20" Fill="{TemplateBinding AdornerIconFill}" Data="{TemplateBinding AdornerIcon}" Stretch="Fill"/>
</Grid>
<TextBlock Grid.Column="2" Text="{TemplateBinding Text}" VerticalAlignment="Center" Foreground="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ContentControl}}}" FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" FontStretch="{TemplateBinding FontStretch}" FontWeight="{TemplateBinding FontWeight}"/>
</Grid>
</Button>
</Border>
</ControlTemplate>
</ResourceDictionary>
IconLabelButton.xaml.cs:
using System;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace Asi.Ui.Common
{
public class IconLabelButton : Control
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(IconLabelButton), new PropertyMetadata(default(string)));
public static readonly DependencyProperty AdornerIconProperty =
DependencyProperty.Register("AdornerIcon", typeof(object), typeof(IconLabelButton), new PropertyMetadata(default(object)));
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(object), typeof(IconLabelButton), new PropertyMetadata(default(object)));
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(IconLabelButton), new PropertyMetadata(default(ICommand)));
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(IconLabelButton), new PropertyMetadata(default(ICommand)));
public static readonly DependencyProperty SpacingProperty =
DependencyProperty.Register("Spacing", typeof(GridLength), typeof(IconLabelButton), new PropertyMetadata(default(GridLength)));
public static readonly DependencyProperty IconButtonSizeProperty =
DependencyProperty.Register("IconButtonSize", typeof(GridLength), typeof(IconLabelButton), new PropertyMetadata(default(GridLength)));
public static readonly DependencyProperty AdornerIconFillProperty =
DependencyProperty.Register("AdornerIconFill", typeof(Brush), typeof(IconLabelButton), new PropertyMetadata(default(Brush)));
static IconLabelButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(IconLabelButton), new FrameworkPropertyMetadata(typeof(IconLabelButton)));
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public object AdornerIcon
{
get { return GetValue(AdornerIconProperty); }
set { SetValue(AdornerIconProperty, value); }
}
public object Icon
{
get { return GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public GridLength Spacing
{
get { return (GridLength)GetValue(SpacingProperty); }
set { SetValue(SpacingProperty, value); }
}
public GridLength IconButtonSize
{
get { return (GridLength)GetValue(IconButtonSizeProperty); }
set { SetValue(IconButtonSizeProperty, value); }
}
public Brush AdornerIconFill
{
get { return (Brush)GetValue(AdornerIconFillProperty); }
set { SetValue(AdornerIconFillProperty, value); }
}
}
}
I apologize if this is an easy question (or if I'm not asking the right one). I'm an entry-level programmer who only has a cursory familiarity with WPF/XAML.
Thanks in advance for the help! (Hopefully it's any easy fix!)
Update: After doing some further digging on UI Automation Providers, it looks like all custom controls have to be written to support AutomationProperties. Of course talking with the devs that isn't case.
I'll post more information when I get the solution figured out.
There is no AutomationPeer for your control. So your AutomationId setup does not set anything.
Override OnCreateAutomationPeer in your control codebehind like this:
protected override AutomationPeer OnCreateAutomationPeer()
{
return new IconLabelButtonAutomationPeer(this);
}
where your new IconLabelButtonAutomationPeer looks like this:
public class IconLabelButtonAutomationPeer : FrameworkElementAutomationPeer
{
public IconLabelButtonAutomationPeer(IconLabelButton owner)
: base(owner)
{
}
}

WPF Dependency Property In Nested User Control

I have the following WPF Control which is used to Show A Text With An Image Beside it
XAML Code
<UserControl x:Class="WFWorkSpaceWPF.UserControls.StackedImageTextCtl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Name="StackedImageText"
>
<Grid>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ElementName=StackedImageText, Path=ImageSource}" />
<TextBlock Text="{Binding ElementName=StackedImageText, Path=Text}" />
</StackPanel>
</Grid>
CS
public partial class StackedImageTextCtl : UserControl
{
public StackedImageTextCtl()
{
InitializeComponent();
}
#region "Properties"
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(StackedImageTextCtl), new UIPropertyMetadata(""));
public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(StackedImageTextCtl), new UIPropertyMetadata(null));
#endregion
}
In my project i want to reuse this control in other three user controls where it will be added as a part of these controls, As you see that the StackedImageTextCtl exposes Two Properties (Text and Image Source) that the parent User Controls needs to provide to it and these three controls will take the value from the container window throw XAML, I know that One of the ways to do so is to replicate defining the properties in each of these three user control and Using AddOwner functionality, but i am looking for a more better approach that won't require any repeat in code, can anyone please direct me to such way?.
This is your UserControl:
<UserControl ...>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}" Width="16"/>
<TextBlock Text="{Binding Text}" />
</StackPanel>
</UserControl>
and its code:
in addition to Text and ImageSource, there is State which represents the Add/Edit/delete state of this control, and there is StackCtlState which is an attached property and when attached to a FrameworkElement it represents the Add/Edit/delete state of that control.
public StackedImageTextCtl()
{
InitializeComponent();
DataContext = this;
}
//Text Dependency Property
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(StackedImageTextCtl), new UIPropertyMetadata(null));
//ImageSource Dependency Property
public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(StackedImageTextCtl), new UIPropertyMetadata(null));
//State Dependency Property
public AddEditDelete State
{
get { return (AddEditDelete)GetValue(StateProperty); }
set { SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty =
DependencyProperty.Register("State", typeof(AddEditDelete), typeof(StackedImageTextCtl), new UIPropertyMetadata(AddEditDelete.Add));
public static AddEditDelete GetStackCtlState(DependencyObject obj)
{
return (AddEditDelete)obj.GetValue(StackCtlStateProperty);
}
public static void SetStackCtlState(DependencyObject obj, AddEditDelete value)
{
obj.SetValue(StackCtlStateProperty, value);
}
public static readonly DependencyProperty StackCtlStateProperty =
DependencyProperty.RegisterAttached("StackCtlState", typeof(AddEditDelete), typeof(StackedImageTextCtl), new UIPropertyMetadata(AddEditDelete.Add));
I also define an enum:
public enum AddEditDelete { Add, Edit, Delete }
In Window xaml:
Each Button or ToggleButton have their attached property StackCtlState set to the desired value and also have their style set to one of styles for Button or ToggleButton.
Then these styles add a StackedImageTextCtl to the contents of styled button/togglebutton in the proper way that resources can be reused. (if you set just Content and don't set Template instead it will only show the contents of the last Button or last ToggleButton) The added StackedImageTextCtl has a State equal to the attached value of its TemplatedParent which is Button or ToggleButton.
At last the style uses Trigger to set the values for Text and Image, based on State of the StackedImageTextCtl.
<Window...
xmlns:myNamespace="clr-namespace:WpfApplication1">
<Window.Resources>
<Style TargetType="{x:Type myNamespace:StackedImageTextCtl}">
<Style.Triggers>
<Trigger Property="State" Value="Add">
<Setter Property="Text" Value="ADD"/>
<Setter Property="ImageSource" Value="/blue_1.jpg"/>
</Trigger>
<Trigger Property="State" Value="Edit">
<Setter Property="Text" Value="EDIT"/>
<Setter Property="ImageSource" Value="/blue_2.jpg"/>
</Trigger>
<Trigger Property="State" Value="Delete">
<Setter Property="Text" Value="DELETE"/>
<Setter Property="ImageSource" Value="/blue_3.jpg"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="stackButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Button>
<myNamespace:StackedImageTextCtl State="{TemplateBinding myNamespace:StackedImageTextCtl.StackCtlState}"/>
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="stackToggleButtonStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ToggleButton>
<myNamespace:StackedImageTextCtl State="{TemplateBinding myNamespace:StackedImageTextCtl.StackCtlState}"/>
</ToggleButton>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<Button Style="{StaticResource stackButtonStyle}" myNamespace:StackedImageTextCtl.StackCtlState="Add"/>
<Button Style="{StaticResource stackButtonStyle}" myNamespace:StackedImageTextCtl.StackCtlState="Edit"/>
<ToggleButton Style="{StaticResource stackToggleButtonStyle}" myNamespace:StackedImageTextCtl.StackCtlState="Delete"/>
</StackPanel>

How to specify the "Mode" and "UpdateSourceTrigger" in my "CustomControl's" markup?

Have a have CustomControl that consists of a ComboBox and a Button.
The binding works fine, but the Set only happens on LostFocus it seems.
This is my CustomControl's markup:
<Style TargetType="{x:Type cba:CustomComboBoxEditView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type cba:CustomComboBoxEditView}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<dxe:ComboBoxEdit x:Name="ComboBoxEdit"
Height="Auto"
Width="Auto"
Grid.Column="0"
ImmediatePopup="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ImmediatePopup}"
AutoComplete="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=AutoComplete}"
IsEnabled="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsEnabled}"
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Visibility}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemsSource}"
DisplayMember="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisplayMember}"
ValueMember="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ValueMember}"
EditValue="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=EditValue}"/>
<dxe:ButtonEdit ShowText="False"
Grid.Column="1"
AllowDefaultButton="False"
IsEnabled="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsEnabled}"
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Visibility}">
<dxe:ButtonInfo x:Name="PART_btnView" GlyphKind="Search" ToolTipService.ToolTip="View" />
</dxe:ButtonEdit>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
For a normal ComboBoxEdit. the binding would look as follow:
EditValue="{Binding Path=SomePath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
This is what my markup looks like when i use the CustomControl:
<cba:CustomComboBoxEditView Name="someName"
ItemsSource="{Binding Path=SomeSource, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMember="DisplayMember"
ValueMember="ValueMember"
EditValue="{Binding Path=SomePath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=False}"/>
How to specify the "Mode" and "UpdateSourceTrigger" in my CustomControl's markup?
What am i doing wrong in my CustomControl for the Set to only happen on LostFocus?
EDIT:
Code behind for CustomControl:
public class CustomComboBoxEditView : Control
{
#region Fields
public static readonly DependencyProperty ImmediatePopupProperty;
public static readonly DependencyProperty AutoCompleteProperty;
public static readonly DependencyProperty ItemsSourceProperty;
public static readonly DependencyProperty DisplayMemberProperty;
public static readonly DependencyProperty ValueMemberProperty;
public static readonly DependencyProperty EditValueProperty;
public static readonly DependencyProperty SystemAppEntityViewCodeProperty;
#endregion
#region Constructor
/// <summary>
/// Default constructor.
/// </summary>
static CustomComboBoxEditView()
{
// Initialize as lookless control
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomComboBoxEditView), new FrameworkPropertyMetadata(typeof(CustomComboBoxEditView)));
// Initialize dependency properties
ImmediatePopupProperty = DependencyProperty.Register("ImmediatePopup",
typeof(bool), typeof(CustomComboBoxEditView), new UIPropertyMetadata(null));
AutoCompleteProperty = DependencyProperty.Register("AutoComplete", typeof(bool),
typeof(CustomComboBoxEditView), new UIPropertyMetadata(null));
ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(object),
typeof(CustomComboBoxEditView), new UIPropertyMetadata(null));
DisplayMemberProperty = DependencyProperty.Register("DisplayMember", typeof(string),
typeof(CustomComboBoxEditView), new UIPropertyMetadata(null));
ValueMemberProperty = DependencyProperty.Register("ValueMember", typeof(string),
typeof(CustomComboBoxEditView), new UIPropertyMetadata(null));
EditValueProperty = DependencyProperty.Register("EditValue", typeof(object),
typeof(CustomComboBoxEditView), new UIPropertyMetadata(null));
SystemAppEntityViewCodeProperty = DependencyProperty.Register("SystemAppEntityViewCode", typeof(string),
typeof(CustomComboBoxEditView), new UIPropertyMetadata(null));
}
#endregion
#region Custom Control Properties
public bool ImmediatePopup
{
get { return (bool)GetValue(ImmediatePopupProperty); }
set { SetValue(ImmediatePopupProperty, value); }
}
public bool AutoComplete
{
get { return (bool)GetValue(AutoCompleteProperty); }
set { SetValue(AutoCompleteProperty, value); }
}
public object ItemsSource
{
get { return (object)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public string DisplayMember
{
get { return (string)GetValue(DisplayMemberProperty); }
set { SetValue(DisplayMemberProperty, value); }
}
public string ValueMember
{
get { return (string)GetValue(ValueMemberProperty); }
set { SetValue(ValueMemberProperty, value); }
}
public object EditValue
{
get { return (object)GetValue(EditValueProperty); }
set { SetValue(EditValueProperty, value); }
}
public string SystemAppEntityViewCode
{
get { return (string)GetValue(SystemAppEntityViewCodeProperty); }
set { SetValue(SystemAppEntityViewCodeProperty, value); }
}
#endregion
}
Found a work around:
Register for the PopupClosed Event and then set the Property.
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var btnComboBoxEdit = Template.FindName("ComboBoxEdit", this) as ComboBoxEdit;
btnComboBoxEdit.PopupClosed +=new ClosePopupEventHandler(btnComboBoxEdit_PopupClosed);
}
private void btnComboBoxEdit_PopupClosed(object sender, ClosePopupEventArgs e)
{
EditValue = e.EditValue;
}

Categories

Resources