I'm trying to bind from Button's ContentTemplate to attached property. I read all the answers for question similar to "binding to attached property" but I had no luck resolving the problem.
Please note that example presented here is a dumbed down version of my problem to avoid cluttering the problem with business code.
So, I do have static class with attached property:
using System.Windows;
namespace AttachedPropertyTest
{
public static class Extender
{
public static readonly DependencyProperty AttachedTextProperty =
DependencyProperty.RegisterAttached(
"AttachedText",
typeof(string),
typeof(DependencyObject),
new PropertyMetadata(string.Empty));
public static void SetAttachedText(DependencyObject obj, string value)
{
obj.SetValue(AttachedTextProperty, value);
}
public static string GetAttachedText(DependencyObject obj)
{
return (string)obj.GetValue(AttachedTextProperty);
}
}
}
and a window:
<Window x:Class="AttachedPropertyTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AttachedPropertyTest"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button local:Extender.AttachedText="Attached">
<TextBlock
Text="{Binding
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button},
Path=(local:Extender.AttachedText)}"/>
</Button>
</Grid>
</Window>
That's pretty much it. I would expect t see "Attached" in the middle of the button.
Instead it crashes with: Property path is not valid. 'Extender' does not have a public property named 'AttachedText'.
I've set breakpoints on SetAttachedText and GetAttachedText, and SetAttachedText is executed, so attaching it to button works. GetAttachedText is never executed though, so it does not find property when resolving.
My problem is actually more complicated (I'm trying to do binding from inside of Style in App.xaml) but let's start with the simple one.
Did I miss something?
Thanks,
Your attached property registration is wrong. The ownerType is Extender, not DependencyObject.
public static readonly DependencyProperty AttachedTextProperty =
DependencyProperty.RegisterAttached(
"AttachedText",
typeof(string),
typeof(Extender), // here
new PropertyMetadata(string.Empty));
See the MSDN documentation for RegisterAttached:
ownerType - The owner type that is registering the dependency property
Related
I have a WPF window which I have changed its borders, title bar and buttons for a custom one. Separately in a ResourceDictionary I have defined the Style that I want to apply to my WPF window.
Then I bind that style to my WPF Window using below line of code:
Style="{DynamicResource CustomWindowStyle}"
Please see all my code posted in another thread that I created to ask for other things. Refer to this thread to see the code (I want to avoid repeating here again).
Now what I am trying to do is to create some custom properties (MyCustomProperty01, MyCustomProperty02) to that WPF Window, some like below:
myDialogView.xaml:
<Window x:Class="myApp.Views.myDialogView"
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:v="clr-namespace:myApp.Views"
xmlns:vm="clr-namespace:myApp.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
ResizeMode="NoResize"
SizeToContent="WidthAndHeight"
Style="{StaticResource CustomWindowStyle}"
WindowStyle="None"
MyCustomProperty01 = "true"
MyCustomProperty02 = "true">
...and then in the code-behind of this WPF window (xaml.cs) I want to define those dependency properties MyCustomProperty01 and MyCustomProperty02, the ones you see above in the code snippet for the Window.
So I create those dependency properties in the code-behind as below.
myDialogView.xaml.cs (code-behind):
namespace myApp.Views
{
public partial class myDialogView: Window
{
public myDialogView()
{
InitializeComponent();
}
public static readonly DependencyProperty MyCustomProperty01Property =
DependencyProperty.Register("MyCustomProperty01",
typeof(bool),
typeof(myDialogView),
new FrameworkPropertyMetadata(false));
public bool MyCustomProperty01
{
get => (bool)GetValue(MyCustomProperty01Property );
set => SetValue(MyCustomProperty01Property , value);
}
public static readonly DependencyProperty MyCustomProperty02Property =
DependencyProperty.Register("MyCustomProperty02",
typeof(bool),
typeof(myDialogView),
new FrameworkPropertyMetadata(false));
public bool MyCustomProperty02
{
get => (bool)GetValue(MyCustomProperty02Property );
set => SetValue(MyCustomProperty02Property , value);
}
}
}
So when I start typing these dependency properties MyCustomProperty01 and MyCustomProperty01 for the window in the xaml view, intellisense looks like it is not recognizing those dependency properties. So what am I doing wrong? Could some tell me how I can achieve this with some code snippet?
You need to registerattached for this to work.
I'm not 100% sure why, I just know it won't work with the usual dependency property.
I think it's because it's in a window tag and it's "really" a myDialogView causes the issue.
Here's an example attached property I have:
public static readonly DependencyProperty TakeMapPictureProperty =
DependencyProperty.RegisterAttached(
"TakeMapPicture",
typeof(bool),
typeof(MainWindow),
new FrameworkPropertyMetadata(false
, new PropertyChangedCallback(TakeMapPictureChanged)
));
private static async void TakeMapPictureChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public static void SetTakeMapPicture(UIElement element, bool value)
{
element.SetValue(TakeMapPictureProperty, value);
}
public static bool GetTakeMapPicture(UIElement element)
{
return (bool)element.GetValue(TakeMapPictureProperty);
}
And in the window tag
local:MainWindow.TakeMapPicture="{Binding CaptureMap}"
Where you might want to use the one dependency property in several user controls or windows, you can define the attached properties in a separate class. There are a couple of ways to do this but the one I prefer looks like:
public class MainWin : DependencyObject
{
public static readonly DependencyProperty MapFileProperty = DependencyProperty.RegisterAttached(
"MapFile",
typeof(string),
typeof(MainWin),
new FrameworkPropertyMetadata(string.Empty
, new PropertyChangedCallback(MapFileChanged)
));
And that is used inside a window tag:
local:MainWin.MapFile="{Binding Path=MapFile}"
You are trying to set the property on the wrong element (locally/attribute syntax):
<Window ... MyCustomProperty01="True" />
Of course, Window does not have a MyCustomProperty01 property.
But myDialogView has this property.
To set this property, either use a Style:
<Window>
<Window.Resources>
<Style TargetType="myDialogView">
<Setter Property="MyCustomProperty01" Value="True" />
</Style>
</Window.Resources>
</Window>
Or set it locally on the proper myDialogView element. But you would have to create a derived type (e.g., myExtendedDialogView), so that you can define myDialogView (the base type) as the root element.
Note how the root element is always the base type of the actual extending type: for example <Window /> of MainWindow or <UserControl /> of MyUserControl or <Page /> of MyPage or <Application /> of App.
Specify the partial class (the derived type that provides the code-behind file) using the x:Class directive on the root element:
<myDialogView x:Class="myExtendedDialogView"
MyCustomProperty01="True">
</myDialogView >
// Define the extended class as partial (with code-behind)
// and the base class that contains the custom properties as a simple class (no code-behind)
partial class myExtendedDialogView : myDialogView
{
public myExtendedDialogView() => InitializeComponent();
}
// Base class used as XAML root element.
// This type has no code-behind file (not partial)
class myDialogView : Window
{
// Dependency properties
}
I want to use xaml to build my workflow like this to split the workflow design and functions.
<Command x:Class="MyCommand">
<Step1 Name="">
<Step2 />
</Step1>
</Command/>
it works.
but when I want to get a value may be updated, i must write a event:
<Command x:Class="MyCommand">
<Step1 GetName="OnGetName">
<Step2 />
</Step1>
</Command/>
void OnGetName(out string name){name = "xxx";}
I think wpf's binding is very well for me ,but sine there are no window, my classes are not inherit from control, It cannot work, event I make my classes inherit from DependencyObject.
Is there any way to import a binding like method?
I update my question as maybe a complete new question.
My real request is use xaml binding without window.
at beginning, I don't want to inherit from Control or FrameworkElement. bug I find it is impossible.
now I update my code to inherit from FrameworkElement, it can work by write binding, but event not with xaml.
public class Command : FrameworkElement
{
public static readonly DependencyProperty Test1Property = DependencyProperty.Register(
nameof(Test1), typeof(string), typeof(UserControl1), new PropertyMetadata(default(string)));
public string Test1
{
get { return (string)GetValue(Test1Property); }
set { SetValue(Test1Property, value); }
}
public static readonly DependencyProperty Test2Property = DependencyProperty.Register(
nameof(Test2), typeof(string), typeof(UserControl1), new PropertyMetadata(default(string)));
public string Test2
{
get { return (string)GetValue(Test2Property); }
set { SetValue(Test2Property, value); }
}
}
I add a window:
<Window x:Class="WpfApp2.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:local="clr-namespace:WpfApp2"
mc:Ignorable="d" x:Name="Main"
DataContext="{x:Reference Main}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:UserControl1 x:Name="Control" Test1="{Binding TestStr, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></local:UserControl1>
</Grid>
</Window>
and init the Test2 binding by code:
public MainWindow()
{
InitializeComponent();
var binding = new Binding("TestStr")
{
Source = this,
};
BindingOperations.SetBinding(Control, UserControl1.Test2Property, binding);
TestStr = "XXS";
MessageBox.Show($"ONLoad: Test1: {Control.Test1}, Test2: {Control.Test2}");
}
then if I new the MainWindow, without Show(), I get the MessageBox show
Test1:, Test2:XXS
I want to find a way to make the xaml binding work before show()!
I'm working on a "simple" case. I like to create a new custom control which implements a DependencyProperty. In the next step I like to create a binding for updating the properties in both directions. I've builded a simple sample for this case, but the binding doesn't seem to work. I've found a way for updating the DPControl's property by using the FrameworkPropertyMetadata, but I don't know whether it's also a good idea to use the OnPropertyChanged event.
HERE is my sample project:
My control contains simply a Label
<UserControl x:Class="WPF_MVVM_ListBoxMultiSelection.DPControl"
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:WPF_MVVM_ListBoxMultiSelection"
mc:Ignorable="d" Height="84.062" Width="159.641">
<Grid Margin="0,0,229,268">
<Label Content="TEST" x:Name="label" Margin="0,0,-221,-102"/>
</Grid>
</UserControl>
and implement a custom dependency property. Currently, I have also implemented the PropertyChanged method for the FramePropertyMetadata and set in this method the label's content, but I like to get it work in both directions.
public partial class DPControl : UserControl
{
public DPControl()
{
InitializeComponent();
}
public string MyCustomLabelContent
{
get { return (string)GetValue(MyCustomLabelContentProperty);}
set
{
SetValue(MyCustomLabelContentProperty, value);
}
}
private static void OnMyCustomLabelContentPropertyChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
DPControl control = (DPControl)source;
control.label.Content = e.NewValue;
}
public static readonly DependencyProperty MyCustomLabelContentProperty = DependencyProperty.Register(
"MyCustomLabelContent",
typeof(string),
typeof(DPControl),
new FrameworkPropertyMetadata(null,
OnMyCustomLabelContentPropertyChanged
)
);
I use this control simply in a Window by:
<local:DPControl MyCustomLabelContent="{Binding MyLabelContent, Mode=TwoWay}" Margin="72,201,286,34"/>
MyLabelContent is a property in the ViewModel, which has implemented also the INotifyPropertyChanged interface.
public class ViewModel_MainWindow:NotifyPropertyChanged
{
private string _myLabelContent;
public string MyLabelContent
{
get { return _myLabelContent; }
set { _myLabelContent = value;
RaisePropertyChanged();
}
}...
So how can I get it work: Using the binding feature with my new control on custom properties.
In your UserControl:
<Label
Content="{Binding MyCustomLabelContent, RelativeSource={RelativeSource AncestorType=UserControl}}"
x:Name="label" Margin="0,0,-221,-102"/>
And get rid of that property-changed callback. All you need is the Binding.
I like to get it work in both directions
To make the dependency property two-way by default:
public static readonly DependencyProperty MyCustomLabelContentProperty =
DependencyProperty.Register(
"MyCustomLabelContent",
typeof(string),
typeof(DPControl),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
);
I omitted the unnecessary property change handler.
It can't usefully be two-way now, because Label.Content can't generate its own value. If you want your UserControl to set the value in its codebehind, that's easy:
MyCustomLabelContent = "Some arbitrary value";
If you did the binding like I showed you, that will update the Label in the UserControl XAML as well as the viewmodel property bound to the UserControl's dependency property.
If you want the XAML to set it, you'll need to
Lastly, this:
Margin="0,0,-221,-102"
Is not a good way to do layout. WPF layout with Grid, StackPanel, etc. is much easier and more robust.
I'm trying to create a simple Bindable property called MyBoolValue in my UserControl class
First, here the xaml
<UserControl x:Class="TMDE.Controls.SimNaoRadioPicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="16"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" Content="Teste" IsChecked="{Binding Path=MyBoolValue}" x:Name="chk" />
</Grid>
</UserControl>
And here the code-behind:
public partial class SimNaoRadioPicker : UserControl
{
public SimNaoRadioPicker()
{
InitializeComponent();
}
public bool? MyBoolValue
{
get
{
return (bool?)GetValue(MyCustomPropertyProperty);
}
set
{
SetValue(MyCustomPropertyProperty, value);
}
}
// Using a DependencyProperty as the backing store for MyCustomProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyCustomPropertyProperty =
DependencyProperty.Register("MyBoolValue",
typeof(bool?), typeof(SimNaoRadioPicker),
new UIPropertyMetadata(MyPropertyChangedHandler));
public static void MyPropertyChangedHandler(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
// Get instance of current control from sender
// and property value from e.NewValue
// Set public property on TaregtCatalogControl, e.g.
((SimNaoRadioPicker)sender).chk.IsChecked = (bool?)e.NewValue;
}
}
Now, when a try to use this control in another Window, like this:
<my:SimNaoRadioPicker x:Name="test" MyBoolValue="{Binding QCV_Localizacao_Reutilizacao}" Height="16" HorizontalAlignment="Left" Margin="287,456,0,0" VerticalAlignment="Top" Width="167" />
the Binding doesnt working, the property QCV_Localizacao_Reutilizacao doesnt get update and vice-versa.
The DataContext of the Window its a class that implements INotifyPropertyChanged, so the
property "QCV_Localizacao_Reutilizacao" should work ok.
Also if I use a regular CheckBox instead of my UserControl, its works okay
What I'm doing wrong?
I would remove the nullable part of the boolean and just make it a boolean, then set binding modes to two way.
There are two major issues -
First, your binding mode needs to be TwoWay which you can achieve in two ways -
Either specifed it to be TwoWay in xaml like this -
<my:SimNaoRadioPicker MyBoolValue="{Binding QCV_Localizacao_Reutilizacao,
Mode=TwoWay}"/>
The drawback with above apporach is that you have to explicitly set the mode whenever you are using the UserControl's instance.
Another approach would be to modify your DP itself to say that it always be bind by default in a TwoWay mode like this using FrameworkPropertyMetadata -
public static readonly DependencyProperty MyCustomPropertyProperty =
DependencyProperty.Register("MyBoolValue",
typeof(bool?), typeof(SimNaoRadioPicker),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
MyPropertyChangedHandler));
Secondly, QCV_Localizacao_Reutilizacao property lies in your Window's DataContext. But, by default any control will look for binding in its own dataContext so you explicilty need to tell it to look into Window's DataContext using RelativeSource like this -
<my:SimNaoRadioPicker MyBoolValue="{Binding QCV_Localizacao_Reutilizacao,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Window}/>
I have a UserControl in my Silverlight application and for some reason, the DependencyProperty of a UserControl is not set if I bind it to a value in the view model. I spent several hours of debugging in a trial-and-error fashion now and I'm all out of ideas what to try next.
I can reproduce the issue in a new Silverlight project with
MainPage.xaml
<UserControl x:Class="SilverlightApplication1.MainPage"
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:local="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel>
<local:MyCtrl HeaderText="{Binding HeaderText}"/>
<TextBlock Text="{Binding HeaderText}"/>
</StackPanel>
</Grid>
</UserControl>
MainPage.xaml.cs
using System.Windows.Controls;
namespace SilverlightApplication1
{
public class Vm
{
public string HeaderText
{ get; set; }
}
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
DataContext = new Vm() { HeaderText = "My Header" };
}
}
}
MyCtrl.xaml (added as new "Silverlight User Control")
<UserControl x:Class="SilverlightApplication1.MyCtrl"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="txtHeader" />
</Grid>
</UserControl>
MyCtrl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication1
{
public partial class MyCtrl : UserControl
{
public MyCtrl()
{
InitializeComponent();
}
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
"HeaderText", typeof(string), typeof(MyCtrl), null);
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set
{
// NEVER CALLED
SetValue(HeaderTextProperty, value);
this.txtHeader.Text = value;
}
}
}
}
The rest of the project is used "as is", i.e. no compiler options were changed and the server part is also left "as is".
Observations:
I see that the getter of Vm.HeaderText is called during a binding
operation but the setter of the DependencyProperty MyCtrl.HeaderText is never called.
The TextBlock in MainPage below the custom control displays the bound value correctly.
There are no compiler warnings.
There are no exceptions thrown.
There are no debug outputs while the application runs.
This feels like something important is silently failing where it shouldn't.
Maybe I can shed some light on your observations and assumptions:
You can update child controls inside a DependencyProperty setter. Call your setter and see for yourself, the update will be performed. You falsely assume the binding engine is obliged to call your setter. Well, it just calls SetValue(HeaderTextProperty, newValue); on your control, no need to call the setter.
Your observation is specified behaviour.
As you figured out, the right way to do it is to use a propertyChanged callback.
The property getter on your viewmodel Vm.HeaderText is called by the binding engine, because your viewmodel is no DependencyObject and HeaderText is no DependencyProperty so there is no SetValue(...) and no GetValue(...)
You can't see any compiler warnings or exceptions, nor is anything silently failing, because there is nothing wrong with your scenario.
Well, seems like you cannot update the child controls inside a DependencyProperty setter (would be interesting to know why and if this is specified behaviour...)
Using this instead works:
public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
"HeaderText", typeof(string), typeof(MyCtrl), new PropertyMetaData(OnHeaderTextChanged));
public string HeaderText
{
get { return (string)GetValue(HeaderTextProperty); }
set { SetValue(HeaderTextProperty, value); }
}
private static void OnHeaderTextChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var ctrl = d as MyCtrl;
ctrl.txtHeader.Text = (string)e.NewValue;
}