I have a self-made button that has image and text.
<ButtonImageApp:ButtonImage
BText="Button"
This works fine. But when I try to to do binding my button code is broken.
This wont work.
BText="{Binding Path=LocalizedResources.PlayButton, Source={StaticResource LocalizedStrings}}"
XAML
<Button x:Class="ButtonImageApp.ButtonImage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
IsEnabledChanged="ButtonIsEnabledChanged"
MouseEnter="ButtonMouseEnter"
MouseLeave="ButtonMouseLeave">
<Grid>
<Image Stretch="None"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Row="0" Grid.Column="0"
x:Name="image" />
<TextBlock x:Name="txtButtonText"
Foreground="Black"
Text="{Binding Path=BText}"
Grid.Row="0" Grid.Column="0"
Margin="20,51,0,-51" TextAlignment="Center"></TextBlock>
</Grid>
</Button>
The Code:
public static readonly DependencyProperty ButtonText = DependencyProperty.Register("BText", typeof(string), typeof(ButtonImage), null);
public string BText
{
get { return (string)GetValue(ButtonText); }
set
{
SetValue(ButtonText, value);
txtButtonText.Text = value;
}
}
The problem is that when using binding the setter of the property is not called.
Instead you need to register for the dependency property changed:
public static readonly DependencyProperty ButtonText = DependencyProperty.Register("BText", typeof(string), typeof(ButtonImage), new PropertyMetadata(ButtonTextChanged));
private static void ButtonTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
txtButtonText.Text = e.NewValue;
}
Related
This question already has an answer here:
XAML binding not working on dependency property?
(1 answer)
Closed 2 years ago.
I would like to display my score point in a textbox, even if the textbox.Text get the value, in GUI i can't see my score.
<UserControl x:Class="WpfCyberPunk.UserControls.UserControlPlaying"
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"
xmlns:local="clr-namespace:WpfCyberPunk.UserControls"
mc:Ignorable="d"
d:DesignHeight="350" Width="Auto" d:DataContext="{d:DesignData }">
<Grid Name="PlayingGrid" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Row="0" HorizontalAlignment="Left">
<StackPanel Name="SkPn_Score" Orientation="Horizontal">
<TextBlock HorizontalAlignment="Left" Margin="10,1,0,0" TextWrapping="Wrap" Text="Point de départ" VerticalAlignment="Center" Height="25" Width="100"/>
<TextBox x:Name = "tBx_StartPt" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=ScoreText,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged }" TextChanged="TBx_StartPt_OnTextChanged" FontSize="10" HorizontalAlignment="Left" Margin="10,1,0,0" TextWrapping="Wrap" VerticalAlignment="Center" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Height="25" Width="50"/>
</StackPanel>
</Grid>
IN cs, I have
public partial class UserControlPlaying : UserControl
{
private string _score;
private int _point;
//public event DependencyProperty PropertyChanged;
public string Score
{
get => _score;
set
{
_score = value;
SetValue(ValueProperty, _score);
}
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Score", typeof(string), ownerType: typeof(UserControlPlaying), new PropertyMetadata(""));
And in my class, i have made an event to see, the new value
private void TBx_StartPt_OnTextChanged(object sender, TextChangedEventArgs e)
{
string newScore = tBx_StartPt.Text;
}
In debug, newScore get the new value.
I don't understand, anything does not display in GUI.
Thank you for your help.
You dependency property declaration is wrong. It must look like this:
public string Score
{
get { return (string)GetValue(ScoreProperty); }
set { SetValue(ScoreProperty, value); }
}
public static readonly DependencyProperty ScoreProperty =
DependencyProperty.Register(
nameof(Score),
typeof(string),
typeof(UserControlPlaying),
new PropertyMetadata(""));
And fix the binding in the textbox:
<TextBox Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl},
Path=Score,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" .../>
This user control I am developing was working and now it has quit working and I cannot figure out what changed. (I've closed and re-opened VS2019 several times, it shows no errors when building or running.) For clarity, I've included the pertinent code sections below but I've included all the code at bottom.
MessagePanel.xaml.cs
public string MessageResponse
{
get { return (string)GetValue(MessageResponseProperty); }
set { SetValue(MessageResponseProperty, value); }
}
// Using a DependencyProperty as the backing store for MessageResponse. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MessageResponseProperty =
DependencyProperty.Register("MessageResponse", typeof(string), typeof(MessagePanel), new PropertyMetadata(""));
private void ButtonProceed_Click(object sender, RoutedEventArgs e)
{
MessageResponse = "Proceed";
}
private void ButtonHalt_Click(object sender, RoutedEventArgs e)
{
MessageResponse = "Halt";
}
MessagePanel.xaml
<TextBox Text="{Binding MessageResponse, RelativeSource={RelativeSource AncestorType=UserControl}}" />
MainWindow.xaml
<uc:MessagePanel MessageResponse="{Binding MainMessageResponse}" />
MainVM.cs
private string mainMessageResponse;
public string MainMessageResponse
{
get => mainMessageResponse;
set
{
mainMessageResponse = value;
NotifyPropertyChanged();
}
}
As far as I can tell, the DependencyProperty MessageResponse in MessagePanel should be propagated to the MainMessageResponse property in the view model MainVM.cs. Certainly, if I insert code in the view model to set the MainMessageResponse value, the NotifyPropertyChanged() fires and the value appears in the bound TextBox in MainWindow.xaml. But when I click on either button of the user control, though the value appears in the bound TextBox in MessagePanel.xaml, the value no longer propagates through to MainMessageResponse.
What am I missing here?
Full code follows (stripped to the bare necessities):
MessagePanel.xaml
<UserControl x:Class="Common.UserControls.MessagePanel"
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"
d:DesignHeight="100" d:DesignWidth="400"
Visibility="Visible" >
<Grid>
<Border
MinWidth="50" MinHeight="50"
Background="LightCoral"
BorderBrush="Black"
BorderThickness="1"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<StackPanel>
<StackPanel Width="400" Margin="5,5,5,0">
<TextBox x:Name="Title" TextWrapping="Wrap" MinHeight="16" Background="LightPink" HorizontalAlignment="Center" />
<TextBox x:Name="Message" IsReadOnly="True" TextWrapping="Wrap" MinHeight="42" Background="LightPink" HorizontalAlignment="Stretch" />
</StackPanel>
<DockPanel >
<CheckBox x:Name="CheckBoxConfirm" Checked="CheckBoxConfirm_Checked" Unchecked="CheckBoxConfirm_Unchecked" FontStyle="Italic" FontWeight="Bold" HorizontalAlignment="Center" />
</DockPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="ButtonProceed" Click="ButtonProceed_Click" Width="50" Margin="5,5" />
<Button x:Name="ButtonHalt" Click="ButtonHalt_Click" Width="50" Margin="5,5" />
</StackPanel>
<TextBox Visibility="Visible" Name="Response" Text="{Binding MessageResponse, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</StackPanel>
</Border>
</Grid>
</UserControl>
MesssagePanel.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace Common.UserControls
{
/// <summary>
/// Interaction logic for MessagePanel.xaml
/// </summary>
public partial class MessagePanel : UserControl
{
public enum MessageType
{
Ok,
OkCancel,
YesNo
}
public MessagePanel()
{
InitializeComponent();
Title.Text = "This is a title";
Message.Text = "This is a test message with title and [Yes] and [No] buttons and requires a confirmation.";
ButtonProceed.Content = "Yes";
ButtonHalt.Content = "No";
CheckBoxConfirm.Visibility = Visibility.Collapsed;
}
#region Dependeny Properties
public string MessageResponse
{
get { return (string)GetValue(MessageResponseProperty); }
set { SetValue(MessageResponseProperty, value); }
}
// Using a DependencyProperty as the backing store for MessageResponse. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MessageResponseProperty =
DependencyProperty.Register("MessageResponse", typeof(string), typeof(MessagePanel), new PropertyMetadata(""));
#endregion
#region Event Handlers
private void ButtonProceed_Click(object sender, RoutedEventArgs e)
{
// User wants to proceed
MessageResponse = "Proceed";
}
private void ButtonHalt_Click(object sender, RoutedEventArgs e)
{
// User wants to not proceed
MessageResponse = "Halt";
}
private void CheckBoxConfirm_Checked(object sender, RoutedEventArgs e)
{
ButtonProceed.IsEnabled = true;
}
private void CheckBoxConfirm_Unchecked(object sender, RoutedEventArgs e)
{
ButtonProceed.IsEnabled = false;
}
#endregion
}
}
MainWindow.xaml
<Window x:Class="WpfUserControl.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uc="clr-namespace:Common.UserControls;assembly=Common"
xmlns:local="clr-namespace:WpfUserControl"
mc:Ignorable="d"
Title="Demo"
Height="300" Width="600">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox Text="{Binding MainMessageResponse}" Width="50" Height="22" />
</StackPanel>
</Grid>
<uc:MessagePanel MessageResponse="{Binding MainMessageResponse}" />
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using WpfUserControl.ViewModels;
namespace WpfUserControl.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MainVM vm = new MainVM();
DataContext = vm;
}
}
}
MainVM.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WpfUserControl.ViewModels
{
public partial class MainVM : INotifyPropertyChanged
{
public MainVM()
{
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
#region MessagePanel
private string mainMessageResponse;
public string MainMessageResponse
{
get => mainMessageResponse;
set
{
mainMessageResponse = value;
NotifyPropertyChanged();
}
}
#endregion
}
}
You should set the Mode of the Binding to TwoWay. You can do this for an individual binding in the XAML markup:
<uc:MessagePanel MessageResponse="{Binding MainMessageResponse, Mode=TwoWay}" />
Or you can specify the default value for all bindings when you register the dependency property in the control:
public static readonly DependencyProperty MessageResponseProperty =
DependencyProperty.Register("MessageResponse", typeof(string), typeof(MessagePanel),
new FrameworkPropertyMetadata("") { BindsTwoWayByDefault = true });
I have created several UserControls like a HeaderedDatePicker.
The XAML of this UserControl looks like:
<UserControl x:Class="Book.CustomControls.HeaderedDatePicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Width="200" Height="50">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="2,2" VerticalAlignment="Center" Text="{Binding Header}" FontWeight="{Binding HeaderFontWeight}"/>
<DatePicker Grid.Row="1" Margin="2,2" VerticalAlignment="Center" SelectedDate="{Binding Date, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</UserControl>
The Code-Behind with the registered DependencyPropertys is:
public partial class HeaderedDatePicker : UserControl
{
public HeaderedDatePicker()
{
this.InitializeComponent();
this.HeaderFontWeight = FontWeights.Normal;
this.Date = DateTime.Now;
}
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(HeaderedDatePicker));
public static readonly DependencyProperty HeaderFontWeightProperty = DependencyProperty.Register("HeaderFontWeight", typeof(FontWeight), typeof(HeaderedDatePicker));
public static readonly DependencyProperty DateProperty = DependencyProperty.Register("Date", typeof(DateTime), typeof(HeaderedDatePicker));
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public FontWeight HeaderFontWeight
{
get { return (FontWeight)GetValue(HeaderFontWeightProperty); }
set { SetValue(HeaderFontWeightProperty, value); }
}
public DateTime Date
{
get { return (DateTime)GetValue(DateProperty); }
set { SetValue(DateProperty, value); }
}
}
Everything is working fine. Now I want to create another HeaderedControl like a HeaderedComboBox or so. My question now is:
Do I have to write the HeaderProperty and HeaderFontWeightProperty in each Code-Behind-File or is there a way to do this in a base-class?
I tried to create a base-class where the properties are registered, but in the code-behind of the HeaderedDatePicker I couldn't inherit from my class
public class main : UserControl
{
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(main));
public static readonly DependencyProperty HeaderFontWeightProperty = DependencyProperty.Register("HeaderFontWeight", typeof(FontWeight), typeof(main));
public static readonly DependencyProperty DateProperty = DependencyProperty.Register("Date", typeof(DateTime), typeof(main));
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public FontWeight HeaderFontWeight
{
get { return (FontWeight)GetValue(HeaderFontWeightProperty); }
set { SetValue(HeaderFontWeightProperty, value); }
}
public DateTime Date
{
get { return (DateTime)GetValue(DateProperty); }
set { SetValue(DateProperty, value); }
}
}
Then in every UserControl you are supposed to derive from previously declared main.
public partial class HeaderedComboBox : main
{
public HeaderedComboBox()
{
this.InitializeComponent();
this.DataContext = this;
}
}
Finally
<local:main x:Class="WpfApplication5.HeaderedComboBox"
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"
xmlns:local ="clr-namespace:WpfApplication5"
mc:Ignorable="d"
Width="200" Height="50">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="2,2" VerticalAlignment="Center" Text="{Binding Header}" FontWeight="{Binding HeaderFontWeight}"/>
<ComboBox Grid.Row="1" Margin="2,2" VerticalAlignment="Center" ItemsSource="{Binding ItemsSource, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
Let me know whether it works.
You can register attached property. See this link. Attached property can be used for any dependency object.
There are similar questions to this one on here however I have tried the mentioned solutions to no avail!
Let me just run you through the setup - I have a model which implements IDataErrorInfo, a viewmodel which exposes the model to the view, within the view I have a usercontrol which is simply a labelled textbox, the model properties are binded to the usercontrol's inner textbox via a dependency property... and everything is binding correctly, all validation is fired and the correct errors returned! However, the usercontrol appears to be intercepting the error and thus the errortemplate of the usercontrol is displayed and not the textbox.
So, I know I can stop the usercontrol's error template from being displayed by setting the property to x:Null, however how do I trigger the textbox's error template to be displayed?! I have tried implementing IDataErrorInfo within the usercontrol (as advised by some) and explicitly defining the validation error template within the user control but I just can't get the darn thing to display. At this point I am thinking that the usercontrol is simply intercepting the error, holding onto it and not passing it onto the textbox, hence the errortemplate not being shown as it isn't aware of the error.
I have been pulling my hair out for the past day and really don't want to resort to not using the usercontrol as I know this can be achieved but I really don't know how to fix it! So if there are any wizards out there that can help I would be very grateful!
UserControl XAML:
<UserControl x:Class="PIRS_Client.Control.LabelTextBox"
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" Height="40.541" Width="321.027">
<Grid Height="41" VerticalAlignment="Top" HorizontalAlignment="Left" Width="321">
<StackPanel Orientation="Horizontal" Margin="0,8,50,9">
<Label Content="Label" Height="28" Name="BaseLabel" VerticalAlignment="Top" HorizontalContentAlignment="Right" Width="116" FontSize="11" />
<TextBox Height="22" Width="100" Margin="0,0,0,0" x:Name="BaseTextBox" VerticalContentAlignment="Center" VerticalAlignment="Top" FontSize="11"/>
</StackPanel>
</Grid>
UserControl Code:
public partial class LabelTextBox : UserControl
{
public static readonly DependencyProperty TextBoxTextProperty = DependencyProperty.Register("TextBoxText", typeof(string), typeof(LabelTextBox), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
public LabelTextBox()
{
InitializeComponent();
Binding textBoxText = new Binding("TextBoxText") { Source = this, Mode = BindingMode.TwoWay };
BaseTextBox.SetBinding(TextBox.TextProperty, textBoxText);
}
[Browsable(true)]
public string LabelText
{
get { return BaseLabel.Content.ToString(); }
set
{
BaseLabel.Content = value;
}
}
[Browsable(true)]
public string TextBoxText
{
get { return (string)GetValue(TextBoxTextProperty); }
set { SetValue(TextBoxTextProperty, value); }
}
[Browsable(true)]
public double TextBoxWidth
{
get { return BaseTextBox.Width; }
set
{
BaseTextBox.Width = value;
}
}
}
View - UserControl delcaration:
<control:LabelTextBox HorizontalAlignment="Left" LabelText="Email" TextBoxText="{Binding UpdateSourceTrigger=LostFocus, Path=NewFosterCarerInfo.partner_email, ValidatesOnDataErrors=true, NotifyOnValidationError=true}" TextBoxWidth="120" Margin="190,182,-61,0" VerticalAlignment="Top" Height="41" Width="321"/>
For anyone with my problem, here is the working code
UserControl xaml:
<UserControl x:Class="PIRS_Client.Control.LabelTextBox"
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" Height="40.541" Width="321.027"
x:Name="Parent" Validation.ErrorTemplate="{x:Null}">
<Grid Height="41" VerticalAlignment="Top" HorizontalAlignment="Left" Width="321" DataContext="{Binding ElementName=Parent, ValidatesOnDataErrors=True}">
<StackPanel Orientation="Horizontal" Margin="0,8,50,9">
<Label Content="Label" Height="28" Name="BaseLabel" VerticalAlignment="Top" HorizontalContentAlignment="Right" Width="116" FontSize="11" />
<TextBox Height="22" Text="{Binding Path=TextBoxText, ValidatesOnDataErrors=True}" Width="100" Margin="0,0,0,0" x:Name="BaseTextBox" VerticalContentAlignment="Center" VerticalAlignment="Top" FontSize="11"/>
</StackPanel>
</Grid>
UserControl code behind:
public partial class LabelTextBox : UserControl, IDataErrorInfo
{
public LabelTextBox()
{
InitializeComponent();
}
public static readonly DependencyProperty TextBoxTextProperty =
DependencyProperty.Register(
"TextBoxText",
typeof(string),
typeof(LabelTextBox),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
);
#region IDataErrorInfo Members
public string Error
{
get
{
if (Validation.GetHasError(this))
return string.Join(Environment.NewLine, Validation.GetErrors(this).Select(e => e.ErrorContent));
return null;
}
}
public string this[string columnName]
{
get
{
// use a specific validation or ask for UserControl Validation Error
if (Validation.GetHasError(this))
{
var error = Validation.GetErrors(this).FirstOrDefault(e => ((BindingExpression)e.BindingInError).TargetProperty.Name == columnName);
if (error != null)
return error.ErrorContent as string;
}
return null;
}
}
#endregion
[Browsable(true)]
public string LabelText
{
get { return BaseLabel.Content.ToString(); }
set { BaseLabel.Content = value; }
}
[Browsable(true)]
public string TextBoxText
{
get { return (string)GetValue(TextBoxTextProperty); }
set {
SetValue(TextBoxTextProperty, value);
}
}
[Browsable(true)]
public double TextBoxWidth
{
get { return BaseTextBox.Width; }
set { BaseTextBox.Width = value; }
}
}
Using the UserControl:
<control:LabelTextBox HorizontalAlignment="Left" LabelText="Email" TextBoxText="{Binding Path=NewFosterCarerInfo.partner_email, ValidatesOnDataErrors=true}" TextBoxWidth="120" Margin="190,182,-61,0" VerticalAlignment="Top" Height="41" Width="321"/>
And in case you wanted a nice Validation.ErrorTemplate:
`<Style TargetType="{x:Type TextBox}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,2,40,2" />
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="true">
<Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white">
</TextBlock>
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
<Border BorderBrush="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>`
I derived ImageButton from Button class. I want to be able to set text on it using custom property.
ImageButton XAML
<Button x:Class="MyProject.ImageButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="50" Width="75" Template="{DynamicResource BlueButton}">
<StackPanel>
<TextBlock Text="{Binding Path = ImageButton.ButtonText}" TextWrapping="Wrap" Foreground="White"/>
</StackPanel>
</Button>
ImageButton code behind
public partial class ImageButton : Button
{
public string ButtonText
{
get { return (string)GetValue(ButtonTextProperty); }
set { SetValue(ButtonTextProperty, value); }
}
public static readonly DependencyProperty ButtonTextProperty =
DependencyProperty.Register("ButtonText", typeof(string), typeof(ImageButton), new UIPropertyMetadata(string.Empty));
public ImageButton()
{
InitializeComponent();
}
}
Client code:
<local:ImageButton Margin="114,15.879,96,15.878" Grid.Row="2" ButtonText="test"/>
No text is being shown on the button. For some reason the binding doesn't seem to be taking place. What am I doing wrong?
You don’t have a DataContext set, so the data binding doesn’t know which source object it should bind to.
I find that the easiest way to resolve this is to give your outer control a name, and reference it using ElementName in your binding:
<Button x:Class="MyProject.ImageButton"
x:Name="myImageButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="50" Width="75" Template="{DynamicResource BlueButton}">
<StackPanel>
<TextBlock Text="{Binding ElementName=myImageButton, Path=ButtonText}"
TextWrapping="Wrap" Foreground="White"/>
</StackPanel>
</Button>
Change this
<TextBlock Text="{Binding Path = ImageButton.ButtonText}"
to
<TextBlock Text="{Binding Path = ButtonText}"