Inf*_*ris 77 data-binding wpf xaml readonly
我正在尝试Readonly
使用OneWayToSource
as模式绑定到属性,但似乎无法在XAML中完成:
<controls:FlagThingy IsModified="{Binding FlagIsModified,
ElementName=container,
Mode=OneWayToSource}" />
Run Code Online (Sandbox Code Playgroud)
我明白了:
无法设置属性"FlagThingy.IsModified",因为它没有可访问的set访问器.
IsModified
是只读DependencyProperty
的FlagThingy
.我想将该值绑定到FlagIsModified
容器上的属性.
要明确:
FlagThingy.IsModified --> container.FlagIsModified
------ READONLY ----- ----- READWRITE --------
Run Code Online (Sandbox Code Playgroud)
这可能只使用XAML吗?
更新:嗯,我通过在容器上设置绑定而不是在容器上修复此情况FlagThingy
.但我仍然想知道这是否可行.
ale*_*2k8 43
OneWayToSource的一些研究成果......
选项1.
// Control definition
public partial class FlagThingy : UserControl
{
public static readonly DependencyProperty IsModifiedProperty =
DependencyProperty.Register("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());
}
Run Code Online (Sandbox Code Playgroud)
<controls:FlagThingy x:Name="_flagThingy" />
Run Code Online (Sandbox Code Playgroud)
// Binding Code
Binding binding = new Binding();
binding.Path = new PropertyPath("FlagIsModified");
binding.ElementName = "container";
binding.Mode = BindingMode.OneWayToSource;
_flagThingy.SetBinding(FlagThingy.IsModifiedProperty, binding);
Run Code Online (Sandbox Code Playgroud)
选项#2
// Control definition
public partial class FlagThingy : UserControl
{
public static readonly DependencyProperty IsModifiedProperty =
DependencyProperty.Register("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());
public bool IsModified
{
get { return (bool)GetValue(IsModifiedProperty); }
set { throw new Exception("An attempt ot modify Read-Only property"); }
}
}
Run Code Online (Sandbox Code Playgroud)
<controls:FlagThingy IsModified="{Binding Path=FlagIsModified,
ElementName=container, Mode=OneWayToSource}" />
Run Code Online (Sandbox Code Playgroud)
选项#3(真正的只读依赖属性)
System.ArgumentException:'IsModified'属性不能是数据绑定的.
// Control definition
public partial class FlagThingy : UserControl
{
private static readonly DependencyPropertyKey IsModifiedKey =
DependencyProperty.RegisterReadOnly("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());
public static readonly DependencyProperty IsModifiedProperty =
IsModifiedKey.DependencyProperty;
}
Run Code Online (Sandbox Code Playgroud)
<controls:FlagThingy x:Name="_flagThingy" />
Run Code Online (Sandbox Code Playgroud)
// Binding Code
Same binding code...
Run Code Online (Sandbox Code Playgroud)
反射器给出了答案:
internal static BindingExpression CreateBindingExpression(DependencyObject d, DependencyProperty dp, Binding binding, BindingExpressionBase parent)
{
FrameworkPropertyMetadata fwMetaData = dp.GetMetadata(d.DependencyObjectType) as FrameworkPropertyMetadata;
if (((fwMetaData != null) && !fwMetaData.IsDataBindingAllowed) || dp.ReadOnly)
{
throw new ArgumentException(System.Windows.SR.Get(System.Windows.SRID.PropertyNotBindable, new object[] { dp.Name }), "dp");
}
....
Run Code Online (Sandbox Code Playgroud)
Fre*_*lad 20
这是WPF的限制,它是设计的.据此在Connect上报告:
来自readonly依赖属性的OneWayToSource绑定
我做了一个动态的解决方案,能够将只读依赖属性推送到PushBinding
我在这里写博客的源.下面的例子不OneWayToSource
绑定从只读DP的ActualWidth
和ActualHeight
到的宽度和高度属性DataContext
<TextBlock Name="myTextBlock">
<pb:PushBindingManager.PushBindings>
<pb:PushBinding TargetProperty="ActualHeight" Path="Height"/>
<pb:PushBinding TargetProperty="ActualWidth" Path="Width"/>
</pb:PushBindingManager.PushBindings>
</TextBlock>
Run Code Online (Sandbox Code Playgroud)
PushBinding
通过使用两个依赖属性,侦听器和镜像来工作.侦听器绑定OneWay
到TargetProperty并在PropertyChangedCallback
其中更新Mirror属性,该属性绑定OneWayToSource
到Binding中指定的任何内容.
演示项目可以在这里下载.
它包含源代码和简短的示例用法,或者如果您对实现细节感兴趣,请访问我的WPF博客.
写道:
用法:
<TextBox Text="{Binding Text}"
p:OneWayToSource.Bind="{p:Paths From={x:Static Validation.HasErrorProperty},
To=SomeDataContextProperty}" />
Run Code Online (Sandbox Code Playgroud)
码:
using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
public static class OneWayToSource
{
public static readonly DependencyProperty BindProperty = DependencyProperty.RegisterAttached(
"Bind",
typeof(ProxyBinding),
typeof(OneWayToSource),
new PropertyMetadata(default(Paths), OnBindChanged));
public static void SetBind(this UIElement element, ProxyBinding value)
{
element.SetValue(BindProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static ProxyBinding GetBind(this UIElement element)
{
return (ProxyBinding)element.GetValue(BindProperty);
}
private static void OnBindChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((ProxyBinding)e.OldValue)?.Dispose();
}
public class ProxyBinding : DependencyObject, IDisposable
{
private static readonly DependencyProperty SourceProxyProperty = DependencyProperty.Register(
"SourceProxy",
typeof(object),
typeof(ProxyBinding),
new PropertyMetadata(default(object), OnSourceProxyChanged));
private static readonly DependencyProperty TargetProxyProperty = DependencyProperty.Register(
"TargetProxy",
typeof(object),
typeof(ProxyBinding),
new PropertyMetadata(default(object)));
public ProxyBinding(DependencyObject source, DependencyProperty sourceProperty, string targetProperty)
{
var sourceBinding = new Binding
{
Path = new PropertyPath(sourceProperty),
Source = source,
Mode = BindingMode.OneWay,
};
BindingOperations.SetBinding(this, SourceProxyProperty, sourceBinding);
var targetBinding = new Binding()
{
Path = new PropertyPath($"{nameof(FrameworkElement.DataContext)}.{targetProperty}"),
Mode = BindingMode.OneWayToSource,
Source = source
};
BindingOperations.SetBinding(this, TargetProxyProperty, targetBinding);
}
public void Dispose()
{
BindingOperations.ClearAllBindings(this);
}
private static void OnSourceProxyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.SetCurrentValue(TargetProxyProperty, e.NewValue);
}
}
}
[MarkupExtensionReturnType(typeof(OneWayToSource.ProxyBinding))]
public class Paths : MarkupExtension
{
public DependencyProperty From { get; set; }
public string To { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var provideValueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
var targetObject = (UIElement)provideValueTarget.TargetObject;
return new OneWayToSource.ProxyBinding(targetObject, this.From, this.To);
}
}
Run Code Online (Sandbox Code Playgroud)
尚未在样式和模板中进行测试,猜测它需要特殊的外壳.
归档时间: |
|
查看次数: |
53018 次 |
最近记录: |