WPF 多重绑定失败.为什么? [英] WPF MultiBinding Fails. Why?

查看:39
本文介绍了WPF 多重绑定失败.为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个标记:

   <GroupBox BorderThickness="2">
    <GroupBox.BorderBrush>
        <SolidColorBrush x:Name="Border">
            <SolidColorBrush.Color>
                <MultiBinding Converter="{StaticResource ConnectionAndLoggedInToBorderBrush}">
                    <Binding Path="IsConnected"/>
                    <Binding Path="IsLoggedIn"/>
                </MultiBinding>
            </SolidColorBrush.Color>
        </SolidColorBrush>
    </GroupBox.BorderBrush>

在后面的代码中,我在 window_loaded 方法中有这一行:

In the code behind I have this line in the window_loaded method:

DataContext = uiManager;

uiManager 是 UIManager 类型,它有两个名为 IsConnected 和 IsLoggedIn 的公共属性.

uiManager is of type UIManager that has two public properties named IsConnected and IsLoggedIn.

此代码在启动时失败,因为 Multibinding 调用的 Converter 中的 values 数组未填充布尔值,而是具有 DependencyProperty.UnsetValue 值.

This code fails at at startup because the values array in the Converter that is called by the Multibinding is not filled with booleans but have a value of DependencyProperty.UnsetValue.

当我使用下面的标记(并更改转换器的返回类型)时,它确实有效.

When I use the markup below (and change the returntype of the converter) it does work.

   <GroupBox BorderThickness="2">
    <GroupBox.BorderBrush>
         <MultiBinding Converter="{StaticResource ConnectionAndLoggedInToBorderBrush}">
              <Binding Path="IsConnected"/>
              <Binding Path="IsLoggedIn"/>
         </MultiBinding>
    </GroupBox.BorderBrush>

在后面的代码中通过 DataContext 设置的绑定似乎在第一个示例中失败,但在第二个示例中有效.为什么?

It seems that the binding set through the DataContext in the code behind fails in the first example, but works in the second one. Why?

为了在 UIManager 类下面的完整性:

For completeness below the UIManager class:

public class UIManager:IUIManager
    {

        #region Implementation of IUIManager

        private const string IsLoggedInProperty = "IsLoggedIn";
        private bool loggedIn;
        private readonly object loggedInLock = new object();
        public bool IsLoggedIn
        {
            get
            {
                lock (loggedInLock)
                {
                    return loggedIn;
                }
            }
            set
            {
                lock (loggedInLock)
                {
                    if(value==loggedIn)return;
                    loggedIn = value;
                    OnPropertyChanged(IsLoggedInProperty);
                }
            }
        }

        private void OnPropertyChanged(string property)
        {
            if(PropertyChanged!=null)PropertyChanged(this,new PropertyChangedEventArgs(property));
        }

        private const string IsConnectedProperty = "IsConnected";
        private bool isConnected;
        private object isConnectedLock = new object();
        public bool IsConnected
        {
            get
            {
                lock (isConnectedLock)
                {
                    return isConnected;
                }
            }
            set
            {
                lock (isConnectedLock)
                {
                    if(value==isConnected)return;
                    isConnected = value;
                    OnPropertyChanged(IsConnectedProperty);
                }
            }
        }

        #endregion

        #region Implementation of INotifyPropertyChanged

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }

失败的 XAML 的转换方法(在转换为 bool of values[0] 时失败:

The conversion method for the failing XAML (it fails on the conversion to bool of values[0]:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var is_connected = (bool) values[0];
            var is_loggedin = (bool) values[1];
            return is_loggedin
                       ? is_connected
                             ? Colors.YellowGreen
                             : Colors.Red
                       : Colors.Gray;
        }

对于工作 XAML:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var is_connected = (bool) values[0];
            var is_loggedin = (bool) values[1];
            return is_loggedin
                       ? is_connected
                             ? Brushes.YellowGreen
                             : Brushes.Red
                       : Brushes.Gray;
        }

推荐答案

该问题与 MultiBinding 或您的转换器无关.DependencyProperty.UnsetValue 表示绑定没有值.事实上,如果您在调试模式下运行,您可以在 Output 窗口中看到绑定错误:

The problem has nothing to do with a MultiBinding or your converter. DependencyProperty.UnsetValue means that the binding got no value. And indeed if you run in debug mode you can see binding errors in the Output window:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IsConnected; DataItem=null; target element is 'SolidColorBrush' (HashCode=17654054); target property is 'Color' (type 'Color')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=IsLoggedIn; DataItem=null; target element is 'SolidColorBrush' (HashCode=17654054); target property is 'Color' (type 'Color')

那么让我们稍微简化一下标记并应用一些诊断:

So let's simplify the markup a bit and apply some diagnostics:

<GroupBox>
    <GroupBox.BorderBrush>
        <SolidColorBrush>
            <SolidColorBrush.Color>
                <Binding Path="GroupColor" PresentationTraceSources.TraceLevel="High"/>
            </SolidColorBrush.Color>
        </SolidColorBrush>
    </GroupBox.BorderBrush>
</GroupBox>

应用附加的依赖属性 PresentationTraceSources.TraceLevel 会产生更多输出:

Applying the attached dependency property PresentationTraceSources.TraceLevel yields some more output:

System.Windows.Data Warning: 52 : Created BindingExpression (hash=17654054) for Binding (hash=44624228)
System.Windows.Data Warning: 54 :   Path: 'GroupColor'
System.Windows.Data Warning: 56 : BindingExpression (hash=17654054): Default mode resolved to OneWay
System.Windows.Data Warning: 57 : BindingExpression (hash=17654054): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 58 : BindingExpression (hash=17654054): Attach to System.Windows.Media.SolidColorBrush.Color (hash=52727599)
System.Windows.Data Warning: 60 : BindingExpression (hash=17654054): Use Framework mentor <null>
System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source 
System.Windows.Data Warning: 65 : BindingExpression (hash=17654054): Framework mentor not found
System.Windows.Data Warning: 61 : BindingExpression (hash=17654054): Resolve source deferred
System.Windows.Data Warning: 91 : BindingExpression (hash=17654054): Got InheritanceContextChanged event from SolidColorBrush (hash=52727599)
System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source 
System.Windows.Data Warning: 66 : BindingExpression (hash=17654054): Found data context element: GroupBox (hash=51393439) (OK)
System.Windows.Data Warning: 67 : BindingExpression (hash=17654054): DataContext is null
System.Windows.Data Warning: 91 : BindingExpression (hash=17654054): Got InheritanceContextChanged event from SolidColorBrush (hash=52727599)
System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source 
System.Windows.Data Warning: 65 : BindingExpression (hash=17654054): Framework mentor not found
System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source 
System.Windows.Data Warning: 65 : BindingExpression (hash=17654054): Framework mentor not found
System.Windows.Data Warning: 63 : BindingExpression (hash=17654054): Resolving source  (last chance)
System.Windows.Data Warning: 65 : BindingExpression (hash=17654054): Framework mentor not found
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=GroupColor; DataItem=null; target element is 'SolidColorBrush' (HashCode=52727599); target property is 'Color' (type 'Color')

我们看到绑定没有找到 DataContext 并且绑定失败.当我更改 windows 的构造函数以便在初始化内容之前设置 DataContext 绑定工作:

We see that the binding doesn't find a DataContext and the binding fails. When I change the windows's constructor so that DataContext is set before initializing the content the binding works:

public Window1()
{
    DataContext = ...;
    InitializeComponent();
}

这很奇怪,因为对于其他地方的绑定,这无关紧要.不知道为什么它在那里不起作用,所以我只能提供解决方法.例如,将画笔创建为具有绑定的资源(该资源也可以是 GroupBox 的本地资源):

Which is weird since for bindings in other places this doesn't matter. Not sure why it doesn't work there so I can only offer workarounds. What works for example is creating the brush as a resource with the bindings (that resource could also be local to the GroupBox):

<GroupBox BorderBrush="{DynamicResource resbrush}">
    <GroupBox.Resources>
        <SolidColorBrush x:Key="resbrush">
            <SolidColorBrush.Color>
                <MultiBinding Converter="{StaticResource ConnectionAndLoggedInToBorderBrush}">
                    <Binding Path="IsConnected"/>
                    <Binding Path="IsLoggedIn"/>
                </MultiBinding>
            </SolidColorBrush.Color>
        </SolidColorBrush>
    </GroupBox.Resources>
</GroupBox>

如果您的 UIManager 类是某种MVVM ViewModel.

I would suggest though to drop the MultiBinding and to do some pre-processing in the DataContext if your UIManager class is some sort of MVVM ViewModel.

这篇关于WPF 多重绑定失败.为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆