WPF MultiBinding失败。为什么? [英] WPF MultiBinding Fails. Why?

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

问题描述

我有这样的标记:

 <分组框中了borderThickness =2>
    < GroupBox.BorderBrush>
        <的SolidColorBrush X:名称=边境>
            < SolidColorBrush.Color>
                < MultiBinding转换器={的StaticResource ConnectionAndLoggedInToBorderBrush}>
                    <绑定路径=IsConnected/>
                    <绑定路径=IsLoggedIn/>
                < / MultiBinding>
            < /SolidColorBrush.Color>
        < /的SolidColorBrush>
    < /GroupBox.BorderBrush>
 

在code后面我此行的window_loaded方式:

 的DataContext = UIManager的;
 

UIManager的类型是UIManager的,有一个名为IsConnected和IsLoggedIn。两个公共属性

这code未能在启动时,因为数值数组中的转换器被称为由Multibinding没有填充布尔值,但有DependencyProperty.UnsetValue的值。

当我使用下面的标记(并更改转换器的返回类型),它的工作。

 <分组框中了borderThickness =2>
    < GroupBox.BorderBrush>
         < MultiBinding转换器={的StaticResource ConnectionAndLoggedInToBorderBrush}>
              <绑定路径=IsConnected/>
              <绑定路径=IsLoggedIn/>
         < / MultiBinding>
    < /GroupBox.BorderBrush>
 

似乎通过在DataContext在code中的绑定集落后失败在第一例,但工作在第二个。为什么呢?

有关UIManager的类下面完整性:

 公共类UIManager的:IUIManager
    {

        IUIManager的#地区实施

        私人常量字符串IsLoggedInProperty =IsLoggedIn;
        私人布尔的loggedIn;
        私人只读对象loggedInLock =新的对象();
        公共BOOL IsLoggedIn
        {
            得到
            {
                锁定(loggedInLock)
                {
                    返回的loggedIn;
                }
            }
            组
            {
                锁定(loggedInLock)
                {
                    如果(价值==的loggedIn)回报;
                    的loggedIn =价值;
                    OnPropertyChanged(IsLoggedInProperty);
                }
            }
        }

        私人无效OnPropertyChanged(字符串属性)
        {
            如果(!的PropertyChanged = NULL)的PropertyChanged(这一点,新PropertyChangedEventArgs(属性));
        }

        私人常量字符串IsConnectedProperty =IsConnected;
        私人布尔isConnected;
        私有对象isConnectedLock =新的对象();
        公共BOOL IsConnected
        {
            得到
            {
                锁定(isConnectedLock)
                {
                    返回isConnected;
                }
            }
            组
            {
                锁定(isConnectedLock)
                {
                    如果(价值== isConnected)回报;
                    isConnected =价值;
                    OnPropertyChanged(IsConnectedProperty);
                }
            }
        }

        #endregion

        INotifyPropertyChanged的的#地区实施

        公共事件PropertyChangedEventHandler的PropertyChanged;

        #endregion
    }
 

编辑: 发生故障的XAML的转换方法(它失败的转换值的布尔[0]:

 公共对象转换(对象[]值,类型TARGETTYPE,对象参数,CultureInfo的文化)
        {
            VAR is_connected =(布尔)值[0];
            VAR is_loggedin =(布尔)值[1];
            返回is_loggedin
                       ? is_connected
                             ? Colors.YellowGreen
                             :Colors.Red
                       :Colors.Gray;
        }
 

有关工作的XAML:

 公共对象转换(对象[]值,类型TARGETTYPE,对象参数,CultureInfo的文化)
        {
            VAR is_connected =(布尔)值[0];
            VAR is_loggedin =(布尔)值[1];
            返回is_loggedin
                       ? is_connected
                             ? Brushes.YellowGreen
                             :Brushes.Red
                       :Brushes.Gray;
        }
 

解决方案

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

  System.Windows.Data错误:2:找不到理事FrameworkElement的或FrameworkContentElement上的目标元素。 BindingEx pression:路径= IsConnected; DataItem的= NULL;目标元素是'的SolidColorBrush'(哈希code = 17654054); target属性是颜色(输入颜色)
System.Windows.Data错误:2:找不到理事FrameworkElement的或FrameworkContentElement上的目标元素。 BindingEx pression:路径= IsLoggedIn; DataItem的= NULL;目标元素是'的SolidColorBrush'(哈希code = 17654054); target属性是颜色(输入颜色)
 

让我们简化的标记了一下,应用一些诊断:

 <分组框中>
    < GroupBox.BorderBrush>
        <的SolidColorBrush>
            < SolidColorBrush.Color>
                <绑定路径=GroupColorpresentationTraceSources.TraceLevel =高级/>
            < /SolidColorBrush.Color>
        < /的SolidColorBrush>
    < /GroupBox.BorderBrush>
< /分组框中>
 

应用附加依赖属性 presentationTraceSources.TraceLevel 产生一些输出:

  System.Windows.Data警告:52:创建BindingEx pression(哈希值= 17654054)进行绑定(哈希值= 44624228)
System.Windows.Data警告:54:路径:GroupColor
System.Windows.Data警告:56:BindingEx pression(哈希值= 17654054):解析为单向默认模式
System.Windows.Data警告:57:BindingEx pression(哈希值= 17654054):默认更新触发器决定的PropertyChanged
System.Windows.Data警告:58:BindingEx pression(哈希值= 17654054):附加到System.Windows.Media.SolidColorBrush.Color(哈希值= 52727599)
System.Windows.Data警告:60:BindingEx pression(哈希值= 17654054):使用框架的导师<零>
System.Windows.Data警告:63:​​BindingEx pression(哈希值= 17654054):解决源
System.Windows.Data警告:65:BindingEx pression(哈希值= 17654054):框架导师没有发现
System.Windows.Data警告:61:BindingEx pression(哈希值= 17654054):解析来源推迟
System.Windows.Data警告:91:BindingEx pression(哈希值= 17654054):得到InheritanceContextChanged事件从的​​SolidColorBrush(哈希值= 52727599)
System.Windows.Data警告:63:​​BindingEx pression(哈希值= 17654054):解决源
System.Windows.Data警告:66:BindingEx pression(哈希值= 17654054):创建数据上下文元素:分组框(哈希= 51393439)(OK)
System.Windows.Data警告:67:BindingEx pression(哈希值= 17654054):DataContext的是空
System.Windows.Data警告:91:BindingEx pression(哈希值= 17654054):得到InheritanceContextChanged事件从的​​SolidColorBrush(哈希值= 52727599)
System.Windows.Data警告:63:​​BindingEx pression(哈希值= 17654054):解决源
System.Windows.Data警告:65:BindingEx pression(哈希值= 17654054):框架导师没有发现
System.Windows.Data警告:63:​​BindingEx pression(哈希值= 17654054):解决源
System.Windows.Data警告:65:BindingEx pression(哈希值= 17654054):框架导师没有发现
System.Windows.Data警告:63:​​BindingEx pression(哈希值= 17654054):解决源(最后一次机会)
System.Windows.Data警告:65:BindingEx pression(哈希值= 17654054):框架导师没有发现
System.Windows.Data错误:2:找不到理事FrameworkElement的或FrameworkContentElement上的目标元素。 BindingEx pression:路径= GroupColor; DataItem的= NULL;目标元素是'的SolidColorBrush'(哈希code = 52727599); target属性是颜色(输入颜色)
 

我们看到,绑定未找到的DataContext 和绑定失败。当我改变窗口的构造函数,以便的DataContext 正在初始化内容结合工程之前设置:

 公共窗口1()
{
    的DataContext = ...;
    的InitializeComponent();
}
 

这是因为在其他地方,这并不重要绑定怪异。不知道为什么它不工作,有那么我只能提供解决方法。因为适合的例子是创建笔刷与绑定的资源(即资源也可以是本地的分组框):

 <分组框中BorderBrush ={DynamicResource resbrush}>
    < GroupBox.Resources>
        <的SolidColorBrush X:关键=resbrush>
            < SolidColorBrush.Color>
                < MultiBinding转换器={的StaticResource ConnectionAndLoggedInToBorderBrush}>
                    <绑定路径=IsConnected/>
                    <绑定路径=IsLoggedIn/>
                < / MultiBinding>
            < /SolidColorBrush.Color>
        < /的SolidColorBrush>
    < /GroupBox.Resources>
< /分组框中>
 

我会建议,虽然放弃了 MultiBinding ,并做了一些pre处理的的DataContext 如果你的 UIManager的类是某种 MVVM 视图模型的。

I have this Markup:

   <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>

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

DataContext = uiManager;

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

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>

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?

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
    }

EDIT: 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;
        }

for the working 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;
        }

解决方案

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>

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')

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();
}

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>

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 MultiBinding失败。为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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