我的总体目标是创建一个 TwoWay Attached DependencyProperty (或 OneWayToSource),始终将其绑定源更新为特定值。在我的现实世界场景中,这是一个不恒定的对象,取决于它所附加的对象。
我的示例涉及以下模型和视图:
public class ViewModel : ViewModelBase
{
public ViewModel()
{
firstContainer = new Container();
otherContainer = new Container();
TestContainer = firstContainer;
SwitchContainersCommand = new DelegateCommand(SwitchContainers);
}
private Container firstContainer;
private Container otherContainer;
public Container TestContainer
{
get { return testContainer; }
set { Set(ref testContainer, value); }
}
private Container testContainer;
public ICommand SwitchContainersCommand { get; }
private void SwitchContainers()
{
if (TestContainer == firstContainer)
TestContainer = otherContainer;
else
TestContainer = firstContainer;
}
}
public class Container : ViewModelBase
{
public object TestTarget
{
get { return testTarget; }
set { Set(ref testTarget, value); }
}
private object testTarget = new SampleValue();
}
public class SampleValue
{
public override string ToString()
{
return "unprovided value";
}
}
View:
<Window>
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel local:ProvideToSource.Target="{Binding TestContainer.TestTarget, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBlock><Run Text="ToString: "/><Run Text="{Binding TestContainer.TestTarget}"/></TextBlock>
<Button Command="{Binding SwitchContainersCommand}" HorizontalAlignment="Left">
<TextBlock Text="Switch"/>
</Button>
</StackPanel>
</Window>
值得注意的是,我们有一个附加财产local:ProvideToSource.Target
,它绑定到TestContainer.TestTarget
双向。
现在,代码为ProvideToSource
并不太复杂。在强制值上,它会尝试将属性设置为其所需的值。在初次运行时,这工作得很好。
public static class ProvideToSource
{
private const string Target = nameof(Target);
public static DependencyProperty TargetProperty = DependencyProperty.RegisterAttached(nameof(Target), typeof(object), typeof(ProvideToSource), new PropertyMetadata(null, null, CoerceValue));
public static object GetTarget(DependencyObject dependent)
{
return dependent.GetValue(TargetProperty);
}
public static void SetTarget(DependencyObject dependent, object value)
{
dependent.SetValue(TargetProperty, value);
}
private static readonly object TestValue = new ProvidedObject();
private static object CoerceValue(DependencyObject dependent, object value)
{
if (value != TestValue)
{
dependent.SetValue(TargetProperty, TestValue);
}
return TestValue;
}
}
public class ProvidedObject
{
public override string ToString()
{
return "provided me";
}
}
理想情况下,当绑定设置为新源(不是最新的)时,它应该将源更新为我们想要的值。
然而,它只是在初始创建时这样做。
当应用程序启动并显示窗口时,文本显示所需的“由我提供”;但是,当单击按钮并交换 TestContainer 时,绑定会重新评估它的强制值(因为它检测到更改),但是当SetValue
被调用,后备属性未更新,文本显示“未提供的值”
这种行为有原因吗?我该如何解决它?我尝试过很多事情;但是,在初始化绑定后,我似乎无法从附加属性中成功设置源值。请注意,我已经在使用和不使用 PropertyChangedCallback 的情况下尝试过此操作,但我似乎也无法帮助解决问题。
此外,显式调用BindingOperations.GetBindingExpression(dependent, TargetProperty)?.UpdateSource();
CoerceValue 或 PropertyChanged 回调中也无法执行。