I have a user control called TitleBar which contains this DependencyProperty:
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(TitleBar), new PropertyMetadata(null));
public string Title
{
get
{
return (string)GetValue(TitleProperty);
}
set
{
SetValue(TitleProperty, value);
}
}
The xaml for the user control looks like:
<Label Content="{Binding Title, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
And my xaml of the View looks like:
<Components:TitleBar x:Name="customTitleBar" Title="Test" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3"/>
When I set Title="Test" on the View that holds the TitleBar usercontrol, the changes do not show up in the designer, nor at runtime. How can I fix this?
Figured it out -- I was incorrectly handling the OnPropertyChanged event due to being confused about the parameters.
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(TitleBar), new PropertyMetadata(null
() => { (sender, e) ... }))
Worked after casting the parameters and calling view updates directly on them.
I don't have full code but my guess is that the problem is in binding context for Label, which by default will be DataContext and not UserControl.
<Label Content="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=Title}"
Changing binding source to be your UserControl should help and you shouldn't have to handle property updates from callback
Related
I have a custom class derived from ContentPresenter which has a DepenedencyProperty. However, when I attempt to bind it, nothing happens (Source's getter is not called, content is not updated, no errors are logged in Trace):
public class IsReadOnlyCellPresenter : ContentPresenter
{
[Bindable(true)]
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(IsReadOnlyCellPresenter), new FrameworkPropertyMetadata(null));
}
xaml:
<local:IsReadOnlyCellPresenter Text="{Binding Path=MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<local:IsReadOnlyCellPresenter.ContentTemplate>
<DataTemplate>
<TextBox Text="{Binding Text, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</DataTemplate>
</local:IsReadOnlyCellPresenter.ContentTemplate>
</local:IsReadOnlyCellPresenter>
If I use static value (e.g. Text="Foo") it works as expected. If I derive from ContentControl (class IsReadOnlyCellPresenter : ContentControl), the Text binding works but not Mode=TemplatedParent which points to nowhere.
What is the issue with ContentPresenter here? Can ContentPresenter be derived from?
This worked in UWP but I can't get the image to show using WPF XAML.
I start by defining a UserControl which binds the path of the image file:
<Grid Height="70" Width="70">
<Border Style="{StaticResource border}">
<Button Style="{StaticResource button}">
<Image Source="{Binding prop_image}"/>
</Button>
</Border>
</Grid>
I define the dependency property as:
public static readonly DependencyProperty prop_image =
DependencyProperty.Register("prop_image_path", typeof(string),
typeof(user_control), null);
public string prop_image_path
{
get { return (string)GetValue(prop_image); }
set { SetValue(prop_image, value); }
}
I then try to consume it as:
<local:user_control Grid.Column="1" Grid.Row="2"
prop_image_path="/Assets/my.png"/>
which is the exact same as UWP but with Binding instead of x:bind. when I create a button and set the image it works . . . but it doesn't display the alpha channel(which I guess means I have to use an alpha mask and have two files.) aside from this, moving a bunch of stuff from UWP to WPF XAML was a snap.
At first, you are using the wrong property path in {Binding prop_image}, which should be {Binding prop_image_path}. Since this Binding is in a UserControl's XAML to one of its own properties, you should also specify the source object of the Binding to be the UserControl instance, like:
<Image Source="{Binding prop_image_path,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
Besides that, the WPF dependency property system requires that you adhere to naming conventions for the dependency property identifier field.
It must be named like the property with a Property suffix:
public static readonly DependencyProperty prop_image_pathProperty =
DependencyProperty.Register(
"prop_image_path",
typeof(string),
typeof(user_control),
null);
You may also notice that your naming scheme is a little uncommon. According to widely accepted conventions, C#/.NET type and property names should use Pascal Casing, i.e.
public class MyUserControl
{
public static readonly DependencyProperty ImagePathProperty =
DependencyProperty.Register(
nameof(ImagePath),
typeof(string),
typeof(MyUserControl));
public string ImagePath
{
get { return (string)GetValue(ImagePathProperty); }
set { SetValue(ImagePathProperty, value); }
}
}
I have a simple usercontrol with a button in it which i modified.
When I add this usercontrol to my mainwindow, I can only access the usercontrol's properties. How can I access the button content ? Ideally I'd like to have a custom property let's say "TheText" and I changed it like that
<local:MyButtonControl TheText="My text here will be the button content">
This is what I have in the usercontrol "MyButtonControl"
public object TheText
{
get => (object)GetValue(_text);
set => SetValue(_text, value);
}
public static readonly DependencyProperty _text =
DependencyProperty.Register("Text", typeof(object), typeof(MyButton), new UIPropertyMetadata(null));
But what Am I supposed to put for binding ? Can't figure it out. Here's the concerned button.
<Button x:Name="button" Content="{Binding ??? }" Style="{StaticResource RoundedButton}"/>
The Binding should look like this:
<Button Content="{Binding Text,
RelativeSource={RelativeSource AncestorType=UserControl}}" .../>
Note that a correct dependency property declaration would have to use the same name for both the dependency property and the CLR wrapper. There is also a convention to name the identifier field as <PropertyName>Property.
public object Text
{
get => (object)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(object), typeof(MyButton));
You should certainly also use string as type of a property that is called Text. Or you call the property ButtonContent or something like that.
I have a custom control called EnhancedTextBox which is a UserControl that has a TextBox and a Button. To the consumer I want it to mostly look like a TextBox, so I did the following:
<UserControl.Template>
<ControlTemplate TargetType="textBoxes:EnhancedTextBox">
...
<TextBox Text="{TemplateBinding Text}"...
And in EnhancedTextBox I have
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof (String), typeof (EnhancedTextBox));
public String Text
{
get { return (String) GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
Yet, when I use it as the following:
<EnhancedTextBox Text="{Binding MyText, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}}" />
Then, MyText is never updated, as well as I inspect EnhancedTextBox.Text and it is null. What am I missing? I have been staring at this for a bit and can't figure out what is wrong. I even thought it might be the fact that I was using the same name, so create a property called Text1 which did not work....
Also of note, if I use a regular TextBox, then this all works. So, I am fairly certain the problem is with the EnhancedTextBox itself
I figured it out after reading this MSDN about TemplateBinding. Specifically,
A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with {Binding RelativeSource={RelativeSource TemplatedParent}}.
So, I decided to do this explicitly...which would allow me to set the UpdateSourceTrigger (still not sure why it doesn't default to PropertyChanged)
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text, UpdateSourceTrigger=PropertyChanged}"....
And, now it is working. TemplateBinding does not even expose these properties....again, not sure why
You are missing the CallBack when you register the property.
Here's a sample code.
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set { SetValue(IsSelectedProperty, value); }
}
public void IsSelectedChangedCallback()
{
//actions when property changed
}
private static void OnSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
userControl.IsSelectedChangedCallback();
}
public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register("IsSelected", typeof(bool), typeof(MyUserControl), new PropertyMetadata(new PropertyChangedCallback(OnSelectedChanged)));
I have a base class and another class that inherits from the base.
The base class has a DependencyProperty (say "MyDPProperty"):
public int MyDPProperty
{
get { return (int)GetValue(MyDPPropertyProperty); }
set { SetValue(MyDPPropertyProperty, value); }
}
public static readonly DependencyProperty MyDPPropertyProperty =DependencyProperty.Register("MyDPProperty", typeof(int), typeof(ownerclass), new UIPropertyMetadata(0));
in Window's Constructor i wrote:
SomeWpfWindow.DataContext = new ChildClass();
and in my Window's XAML code i have:
<TextBox x:Name="txt"
Text="{Binding Path=MyDPProperty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
Now, the binding does not work,Although when I bind it in code behind it works :
SomeWpfWindow.txt.SetBinding(TextBox.TextProperty
, new Binding("MyDPProperty")
{
Source = InstanceOfChildClass,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Mode = BindingMode.TwoWay
});
You are binding a property in code behind. you can give your window a name (for example Name="winName") and define the ElementName in the binding:
x:Name="txt" Text="{Binding ElementName=winName, Path=MyDPProperty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
there are other ways, for example you can add a StaticResource. this link might help:
http://blog.jayway.com/2011/05/17/bind-from-xaml-to-property-defined-in-code-behind/