我创建了一些附加的依赖项属性,让几个元素在集中管理器上设置一些信息,以跟踪“活动信息”。
这是附加行为:
public class ActiveItemBehavior
{
public static readonly DependencyProperty ManagerProperty = DependencyProperty.RegisterAttached("Manager", typeof(ActiveItemManager), typeof(ActiveItemBehavior), new UIPropertyMetadata(ManagerChanged));
public static readonly DependencyProperty ItemProperty = DependencyProperty.RegisterAttached("Item", typeof(object), typeof(ActiveItemBehavior));
public static ActiveItemManager GetManager(DependencyObject depObj)
{
return (ActiveItemManager)depObj.GetValue(ManagerProperty);
}
public static void SetManager(DependencyObject depObj, ActiveItemManager manager)
{
depObj.SetValue(ManagerProperty, manager);
}
public static object GetItem(DependencyObject depObj)
{
return depObj.GetValue(ItemProperty);
}
public static void SetItem(DependencyObject depObj, object item)
{
depObj.SetValue(ItemProperty, item);
}
private static void ManagerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement fe = d as FrameworkElement;
fe.GotFocus += fe_GotFocus;
}
private static void fe_GotFocus(object sender, RoutedEventArgs e)
{
var manager = GetManager(sender as DependencyObject);
var newItem = GetItem(sender as DependencyObject);
var oldItem = manager.ActiveItem;
if (Object.ReferenceEquals(newItem, oldItem)) return;
manager.ActiveItem = newItem;
}
}
所以基本上我的想法是我附加了两个属性,一个是跟踪活动项的管理器,另一个是作为项的对象(当元素获得焦点时成为活动项)。
经理更简单:
public class ActiveItemManager : FrameworkElement
{
public static readonly DependencyProperty ActiveItemProperty = DependencyProperty.Register("ActiveItem", typeof(object), typeof(ActiveItemManager));
public object ActiveItem
{
get { return this.GetValue(ActiveItemProperty); }
set { this.SetValue(ActiveItemProperty, value); }
}
}
所以在我的<UserControl.Resources>
我定义了一个(或更多经理):
<cc:ActiveItemManager x:Key="ActiveItemManager" ActiveItem="{Binding MyActiveItem, Mode=TwoWay, PresentationTraceSources.TraceLevel=High}" />
我得到了像TextBox
等几个控件,如下所示:
<TextBox Text="{Binding Station}" cc:ActiveItemBehavior.Manager="{StaticResource ActiveItemManager}" cc:ActiveItemBehavior.Item="{Binding}" />
所以我基本上在这里使用MVVM模式,而视图的VM有一个属性MyActiveItem
,它永远不会得到正确的值。管理器实例本身获取正确的值设置为ActiveItem
,因此这可以按预期工作。但是从经理那里,它永远不会被复制回VM。
绑定跟踪显示:
System.Windows.Data Warning: 56 : Created BindingExpression (hash=43567975) for Binding (hash=27811722)
System.Windows.Data Warning: 58 : Path: 'ActiveMoxItem'
System.Windows.Data Warning: 61 : BindingExpression (hash=43567975): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=43567975): Attach to cc.ActiveItemManager.ActiveItem (hash=38526232)
System.Windows.Data Warning: 67 : BindingExpression (hash=43567975): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=43567975): Found data context element: ActiveItemManager (hash=38526232) (OK)
System.Windows.Data Warning: 71 : BindingExpression (hash=43567975): DataContext is null
System.Windows.Data Warning: 65 : BindingExpression (hash=43567975): Resolve source deferred
System.Windows.Data Warning: 67 : BindingExpression (hash=43567975): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=43567975): Found data context element: ActiveItemManager (hash=38526232) (OK)
System.Windows.Data Warning: 71 : BindingExpression (hash=43567975): DataContext is null
System.Windows.Data Warning: 67 : BindingExpression (hash=43567975): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=43567975): Found data context element: ActiveItemManager (hash=38526232) (OK)
System.Windows.Data Warning: 71 : BindingExpression (hash=43567975): DataContext is null
System.Windows.Data Warning: 67 : BindingExpression (hash=43567975): Resolving source (last chance)
System.Windows.Data Warning: 70 : BindingExpression (hash=43567975): Found data context element: ActiveItemManager (hash=38526232) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=43567975): Activate with root item <null>
System.Windows.Data Warning: 106 : BindingExpression (hash=43567975): Item at level 0 is null - no accessor
System.Windows.Data Warning: 80 : BindingExpression (hash=43567975): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 88 : BindingExpression (hash=43567975): TransferValue - using fallback/default value <null>
System.Windows.Data Warning: 89 : BindingExpression (hash=43567975): TransferValue - using final value <null>
我缺少什么让Manager收到新的活动项并通过绑定将其填充到VM?
注意:我已尝试使用某些ElementName
或代理元素。我发现这看起来很相似但没有答案:StackOverflow
答案 0 :(得分:1)
您的代码的要点是您在ActiveItemBehavior.Item中有一个随机值,然后在TextBox中单击并且ActiveItemManager.ActiveItem接收该值。 Futhermore ActiveItemManager.ActiveItem将通过Binding将值推送到MyActiveItem。简而言之,为什么不将ActiveItemBehavior.Item绑定到MyActiveItem?
无论如何,当你在资源内部时没有DataContext。因此,您无法设置MyActiveItem。要在Data中包含DataContext,您需要从Freezable继承。
答案 1 :(得分:0)
好的,我开始工作了。
我使用了ProxyElement
。
参考资料部分如下:
<UserControl.Resources>
<FrameworkElement x:Key="ProxyElement" DataContext="{Binding}" />
<cc:ActiveItemManager x:Key="ActiveItemManager" ActiveItem="{Binding DataContext.MyActiveItem, Source={StaticResource ProxyElement}, Mode=TwoWay}" />
</UserControl.Resources>
如果在UI上使用了代理元素,它只能提供一个datacontext,所以我把它放在那里但是隐藏了。
<ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}" />
现在它按预期工作。虽然我必须承认我不完全理解为什么。