代码之家  ›  专栏  ›  技术社区  ›  Dabblernl

WPF多重绑定失败。为什么?

  •  6
  • Dabblernl  · 技术社区  · 15 年前

    我有这个标记:

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

    在后面的代码中,我在窗口加载方法中有这一行:

    DataContext = uiManager;
    

    uiManager的类型为uiManager,它有两个名为isConnected和isLoggedin的公共属性。

    此代码在启动时失败,因为多绑定调用的转换器中的值数组没有填充布尔值,而是具有DependencyProperty.UnsetValue的值。

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

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

    在第一个示例中,通过代码隐藏中的DataContext进行的绑定集似乎失败了,但在第二个示例中有效。为什么?

    对于uimanager类下面的完整性:

    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的转换方法(在值[0]转换为bool时失败):

    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;
            }
    
    3 回复  |  直到 14 年前
        1
  •  15
  •   gix    15 年前

    这个问题与 MultiBinding 或者你的转换器。 DependencyProperty.UnsetValue 表示绑定没有值。实际上,如果在调试模式下运行,您可以在 Output 窗口:

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

    因此,让我们简化标记并应用一些诊断:

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

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

    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的构造函数时, 数据上下文 在初始化内容之前设置绑定工作:

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

    这很奇怪,因为在其他地方绑定并不重要。不知道为什么它在那里不起作用,所以我只能提供解决办法。例如,将画笔创建为具有绑定的资源(该资源也可以是 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 .

        2
  •  1
  •   agroskin    14 年前

    我的理论。颜色是结构(不能为空),所以solidColorBrush.color=空是错误的。WPF无法创建solidColorBrush,您将得到异常。

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

    borderBrush是对象(可以为空),所以groupBox.borderBrush=空可以。

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

    此solidColorBrush不是对象,而是工厂。它仅在需要时实例化,此时您已经附加了DataContext。

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

    只有我的2美分。

    读我的文章,btw,如果你需要一些奇怪的绑定或者带有奇怪转换器的动画,它可能会很有用。 http://www.codeproject.com/KB/WPF/BindingHub.aspx

        3
  •  0
  •   Pete OHanlon    15 年前

    正是因为这样的原因,您可能想考虑学习MVVM。此模式帮助您抽象模型和绑定,这样您就不必太依赖DPS了—您只需在视图模型中绑定到一个可通知属性即可。

    有几篇关于MVVM的优秀文章,所以我建议你从阅读卡尔·希夫莱特、乔什·史密斯、马龙·格雷奇和萨夏·巴伯的作品开始。

    推荐文章