为什么这个WPF绑定不起作用?

时间:2010-09-26 02:17:49

标签: binding

我无法获得绑定工作。我创造了一个完全没有结果的例子来证明我的问题。就像这样......

我有一组我希望能够在XAML中定义的小部件。此集合将与UserControl关联。在XAML中,我想将小部件的“Name”属性绑定到数据位(本例中为字符串)。

因此,对于代码,我有一个从DependencyObject派生的Widget类

public class Widget : DependencyObject
{
    public string Name
    {
        get { return (string)GetValue(NameProperty); }
        set { SetValue(NameProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty NameProperty =
        DependencyProperty.Register("Name", typeof(string), typeof(Widget), new UIPropertyMetadata("--widget--"));

}

请注意,此属性的默认值为“--widget--”。我也有一个WidgetCollection类......

public class WidgetCollection : Collection<Widget>
{
    public WidgetCollection()
    {
    }
}

WidgetControl是WidgetCollection的父级,它作为名为“Widgets”的属性公开

[ContentPropertyAttribute("Widgets")]
public partial class WidgetControl : UserControl
{

    public WidgetCollection Widgets
    {
        get { return (WidgetCollection)GetValue(WidgetsProperty); }
        set { SetValue(WidgetsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Widgets.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty WidgetsProperty =
        DependencyProperty.Register("Widgets", typeof(WidgetCollection), typeof(WidgetControl), new UIPropertyMetadata(null));


    public WidgetControl()
    {
        Widgets = new WidgetCollection();
        InitializeComponent();
    }

    public IEnumerable<string> GetWidgetNames()
    {
        return Widgets.Select(w => w.Name);
    }

}

对于视觉反馈,WidgetControl显示一个红色矩形......

<UserControl x:Class="StackOverflow.BindingProblem.WidgetControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Rectangle Margin="0" Fill="Red"/>    
    </Grid>
</UserControl>

所以现在我已经获得了演示的所有部分,我将它们放在MainWindow中......

    <Window x:Class="StackOverflow.BindingProblem.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:StackOverflow.BindingProblem"
        Title="MainWindow" Height="220" Width="160"
        x:Name="x_win">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <l:WidgetControl x:Name="x_WidgetControl" Grid.Row="0">
            <l:Widget Name="Sprocket"/>
            <l:Widget Name="{Binding Path=WidgetName1, ElementName=x_win}"/>
            <l:Widget Name="{Binding Path=WidgetName2, ElementName=x_win}"/>
            <l:Widget Name="Wrench"/>
        </l:WidgetControl>

        <StackPanel Orientation="Vertical" Grid.Row="1">
            <TextBlock Text="Sprocket"/>
            <TextBlock Text="{Binding Path=WidgetName1, ElementName=x_win}"/>
            <TextBlock Text="{Binding Path=WidgetName2, ElementName=x_win}"/>
            <TextBlock Text="Wrench"/>
        </StackPanel>

        <ListBox x:Name="x_ListBox" Grid.Row="2"/>
    </Grid>
</Window>

在这里,我已将结果转储到窗口中,这样您就可以在不使用调试器的情况下查看我正在谈论的内容。我正在使用网格来创建三行。顶部显示了WidgetControl(一个令人兴奋的红色矩形!),我在XAML中定义了4个小部件。请注意,其中两个小部件具有硬编码名称,另外两个小部件的名称数据绑定到MainWindow类上定义的字符串属性。中间一行显示四个具有 完全相同 绑定的TextBlock。底行显示了一个列表框。此列表框中填充了WidgetControl拥有的WidgetCollection中的窗口小部件的名称。此列表在加载窗口后收集,因此在数据绑定完成后收集。

背后的MainWindow代码看起来像这样......

public partial class MainWindow : Window
{
    public MainWindow()
    {
        Loaded += new RoutedEventHandler(MainWindow_Loaded);
        InitializeComponent();
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        x_ListBox.ItemsSource = x_WidgetControl.GetWidgetNames();
    }

    public string WidgetName1
    {
        get { return "Crank"; }
    }

    public string WidgetName2
    {
        get { return "Wheel"; }
    }
}

当这个演示运行时,窗口看起来像这样......

[大鼠!因为我是新的提交者而省略了图片]我将用文字嘲笑它......

-----------
|         |
|         |  <--  red rectangle (the WidgetControl)
|         |
-----------
Sprocket
Crank        <--  textblocks
Wheel
Wrench
-----------
Sprocket
--widget--   <--  listbox
--widget--
Wrench
-----------

注意TextBlocks上的绑定是如何工作的,但是Widgets上的绑定却没有。底行显示不成功的绑定为--widget--而不是Crank and Wheel。

那为什么会发生这种情况?如何让绑定工作?

2 个答案:

答案 0 :(得分:0)

我只是在黑暗中拍摄,但我认为您的DependencyProperty名称已正确绑定,但当它从“--widget--”更改为“Crank”时,更改不会传播到名称的任何位置被展示。您需要在DependencyProperty.Register上设置回调。

Widget究竟做了什么?

答案 1 :(得分:0)

好吧,我找到了一些答案。这两种技术似乎都可以解决问题,而且两者都非常有用。作为一张新的海报,我只能提交一个超链接。因此,您可以搜索“将虚拟分支附加到逻辑树 - 由Josh Smith”,和/或您可以转到此链接以获取我最喜欢的...

Using Freezable - Dr WPF

就个人而言,我喜欢从Freezable派生我的Widget,因为它需要较少的plumming并且对初始化顺序不敏感.Josh的解决方案只有在DataContext设置为 AFTER 时才会起作用InitializeComponent()被称为,如此......

public MainWindow()
{
    Loaded += new RoutedEventHandler(MainWindow_Loaded);
    InitializeComponent();
    DataContext = this;
}

注意:在我的例子中,仅从Freezable派生Widget是不够的。我还必须从FreezableCollection派生WidgetCollection !!

案件结案。