I have an enum:
public enum ImageTextLocation
{
Left,
Top,
Right,
Bottom
}
And a custom UserControl
that contains dependency property of that enum.
<Button Content="{Binding ButtonText}"
Command="{Binding Command}"
Style="{StaticResource ImageButtonStyle}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border x:Name="border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<ContentPresenter DockPanel.Dock="{Binding Path=TextLocation, Converter={StaticResource EnumToDockConvert}}"
Margin="2,6,0,2"/>
</DockPanel>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
public partial class ImageButtonControl : UserControl
{
public ImageTextLocation TextLocation
{
get => (ImageTextLocation)GetValue(TextLocationProperty);
set => SetValue(TextLocationProperty, value);
}
public static readonly DependencyProperty TextLocationProperty =
DependencyProperty.Register(
"TextLocation",
typeof(ImageTextLocation),
typeof(ImageButtonControl),
new FrameworkPropertyMetadata(ImageTextLocation.Left,
PropertyChangedCallback) { BindsTwoWayByDefault = true, }
);
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var imageButton = (ImageButtonControl)d;
var newLocation = (ImageTextLocation)e.NewValue;
switch (newLocation)
{
case ImageTextLocation.Left:
imageButton.SetCurrentValue(TextLocationProperty, ImageTextLocation.Left);
break;
case ImageTextLocation.Right:
imageButton.SetCurrentValue(TextLocationProperty, ImageTextLocation.Right);
break;
}
}
}
I have added created a converter that converts from ImageTextLocation
to Dock
:
public class EnumToDockConverter : IValueConverter
{
public object Convert(object value,
Type targetType,
object parameter,
CultureInfo culture)
{
if(value == null)
return Dock.Left;
ImageTextLocation location = (ImageTextLocation)value;
var dock = Enum.Parse(typeof(Dock), location.ToString());
return dock;
}
public object ConvertBack(object value,
Type targetType,
object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}
And added an instance of the converter to the resources of my UserControl
:
<coverter:EnumToDockConverter x:Key="EnumToDockConvert"/>
Then, I try to set the DockPanel.Dock
of the custom control using TextLocation="{Binding ImageTextPosition}"
, where ImageTextPosition
is the string property of my view model bound to the UserControl
.
<controls:ImageButtonControl TextLocation="{Binding ImageTextPosition}"/>
DockPanel's Dock does not set when I set the dependency property.
CodePudding user response:
I don't see any need to use a converter. In your property changed callback, call DockPanel.SetDock()
directly to change the dock position of the content presenter. I would also define ImageTextLocation
in terms of Dock
so that you can cast it.
UPDATE: OP clarified that ImageButtonControl
overrides the default ControlTemplate
of the Button
, so I have updated my answer to work in that scenario. Derive directly from Button
, instead of UserControl
, so the contents of the template are accessible without jumping through hoops.
ImageButton.xaml
<!-- bound the content of the Button to TextLocation for testing -->
<Button x:Class="TestApp.ImageButton"
Content="{Binding TextLocation, RelativeSource={RelativeSource Self}}"
Command="{Binding Command}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<ContentPresenter x:Name="contentPresenter"
Margin="2,6,0,2"
DockPanel.Dock="Left"/>
<!-- Put something the DockPanel for the content
presenter to dock relative to. Presumably this
would be an image -->
<Button Content="Main Content"/>
</DockPanel>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
Code Behind
public enum ImageTextLocation
{
Left = (int)Dock.Left,
Top = (int)Dock.Top,
Right = (int)Dock.Right,
Bottom = (int)Dock.Bottom
}
public partial class ImageButton : Button
{
private ContentPresenter _contentPresenter;
public ImageButton()
{
InitializeComponent();
}
public ImageTextLocation TextLocation
{
get => (ImageTextLocation)GetValue(TextLocationProperty);
set => SetValue(TextLocationProperty, value);
}
public static readonly DependencyProperty TextLocationProperty =
DependencyProperty.Register(
nameof(TextLocation),
typeof(ImageTextLocation),
typeof(ImageButton),
new FrameworkPropertyMetadata((d, e) => ((ImageButton)d).SetDock((Dock)e.NewValue)));
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_contentPresenter = (ContentPresenter)GetTemplateChild("contentPresenter");
SetDock((Dock)TextLocation);
}
public void SetDock(Dock newLocation)
{
if (_contentPresenter == null) return; //template not yet applied
DockPanel.SetDock(_contentPresenter, newLocation);
}
}
Demo:
<Window x:Class="TestApp.MainWindow">
<UniformGrid>
<local:ImageButton TextLocation="Left" />
<local:ImageButton TextLocation="Right" />
<local:ImageButton TextLocation="Top" />
<local:ImageButton TextLocation="Bottom"/>
</UniformGrid>
</Window>