绑定到资源对象中的ViewModel属性

时间:2015-04-15 22:05:42

标签: c# wpf mvvm dependency-properties

我创建了一些附加的依赖项属性,让几个元素在集中管理器上设置一些信息,以跟踪“活动信息”。

这是附加行为:

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

2 个答案:

答案 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}" />

现在它按预期工作。虽然我必须承认我不完全理解为什么。