问题
I have an attached property I defined.
namespace Controls
{
public class StateManager : DependencyObject
{
public static string GetVisualState(DependencyObject obj)
{
return (string)obj.GetValue(VisualStateProperty);
}
public static void SetVisualState(DependencyObject obj, string value)
{
obj.SetValue(VisualStateProperty, value);
}
// Using a DependencyProperty as the backing store for VisualStateProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VisualStateProperty =
DependencyProperty.RegisterAttached("VisualState", typeof(string), typeof(StateManager),
new PropertyMetadata(null,
(s, e) => {
var stateName = (string)e.NewValue;
var ctrl = s as Control;
if (ctrl == null) throw new InvalidCastException("You can only attach VisualState properties to Controls");
if (!string.IsNullOrEmpty(stateName))
VisualStateManager.GoToState(ctrl, stateName, true);
}));
}
}
I can bind to this property in XAML Like this:
<controls:TitleStrip
controls:StateManager.VisualState=
"{Binding (controls:StateManager.VisualState), ElementName=pageRoot}"
Grid.Column="1"/>
Now, I need to create a binding dynamically in code behind to the same property, so I tried this:
var pp = new PropertyPath("(controls:StateManager.VisualState)");
var binding = new Binding() { Path= pp, Source=this };
BindingOperations.SetBinding(ct, StateManager.VisualStateProperty, binding);
Unfortunately, setting the Path property of the binding, throws an ArgumentException stating: "Value does not fall within the expected range."
If instead, I substitute "(Grid.Row)" for my property, no exception is thrown.
回答1:
Further investigation on windows 10 shows that this appears to work in C# codebehind, if trying to bind to the attached property Controls.StateManager.VisualState onto the Attached Property of the same name on the control ct:
string bindingxaml =
@"<ResourceDictionary
xmlns:controls=""using:Controls""
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
>
<Binding x:Key=""binding"" Path=""(controls:StateManager.VisualState)"" />
</ResourceDictionary>";
ResourceDictionary dict = XamlReader.Load(bindingxaml) as ResourceDictionary;
Binding binding = dict["binding"] as Binding;
binding.Source = this;
BindingOperations.SetBinding(ct, StateManager.VisualStateProperty, binding);
Strangely, this throws exceptions if you don't enclose it in a ResourceDictionary, and try to create the Binding object as the only child.
回答2:
To debug this, I thought maybe my syntax was wrong for the namespace, so in my xaml resources section, I added this:
<Binding x:Key="yuck" Path="(controls:StateManager.VisualState)" ElementName="pageRoot" />
When I examined the Path of the property path, it was exactly as I specified it.
As a workaround, I'm currently getting the binding like this from code behind:
BindingOperations.SetBinding(ct, StateManager.VisualStateProperty,
Resources["yuck"] as Binding);
This appears to be working, however why can't I create the object from code behind?
Update This worked on Windows 8 apps, but now gives errors on UWP.
To get it to work on UWP, I had to databind to the Tag of my ParentGrid.
<Grid x:Name="ParentGrid" Tag="{Binding ElementName=pageRoot, Path=(controls:StateManager.VisualState)}">
Then I can create a Binding to the Tag, like this:
var pp3 = new PropertyPath("Tag");
barf = new Binding() { Path = pp3, Source = ParentGrid };
来源:https://stackoverflow.com/questions/30287091/how-can-i-bind-to-a-custom-attached-property-in-c-sharp-from-code-behind-in-a-wi