自定义控件和绑定引起的麻烦

时间:2011-10-15 18:20:34

标签: silverlight xaml data-binding silverlight-4.0

我目前正在构建一堆常用的控件,基本上只是通过添加标签和类似的东西来扩展默认的Silverlight控件......但是我很难让一些绑定工作......下面是目前不起作用的一些例子:

更新

以下是帮助理解问题的更多背景信息:

public class ComboboxField : Field
{

    public string SelectedValuePath
    {
        get { return (string)this.GetValue(SelectedValuePathProperty); }
        set { this.SetValue(SelectedValuePathProperty, value); }
    }
    public static readonly DependencyProperty SelectedValuePathProperty =
    DependencyProperty.Register("SelectedValuePath", typeof(string), typeof(ComboboxField), new PropertyMetadata(string.Empty));


    public string DisplayMemberPath
    {
        get { return (string)this.GetValue(DisplayMemberPathProperty); }
        set { this.SetValue(DisplayMemberPathProperty, value); }
    }
    public static readonly DependencyProperty DisplayMemberPathProperty =
      DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(ComboboxField), new PropertyMetadata(string.Empty, null));



    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)this.GetValue(ItemsSourceProperty); }
        set { this.SetValue(ItemsSourceProperty, value); }
    }

    public static readonly DependencyProperty ItemsSourceProperty =
    DependencyProperty.Register("ItemsSource", typeof(Object), typeof(ComboboxField), new PropertyMetadata(new List<object>()));



    public object SelectedValue 
    {
        get { return (object)GetValue(SelectedValueProperty); }
        set { SetValue(SelectedValueProperty, value); }
    }

    public static readonly DependencyProperty SelectedValueProperty =
        DependencyProperty.Register("SelectedValue", typeof(object), typeof(ComboboxField), new PropertyMetadata(null, (s, e) => { s.SetValue(Field.ValueProperty, SelectedValueProperty);}));

    #region Ctors
    public ComboboxField(FieldDescription fieldDescription, Form parentForm) : base(fieldDescription, parentForm)
    {
        this.Template = Application.Current.Resources["ComboBoxDefaultTemplate"] as ControlTemplate;
    }

    public ComboboxField() : base(new FieldDescription(Guid.NewGuid(), "ComboboxField1", FieldType.Collection), null)
    {
        this.Template = Application.Current.Resources["ComboBoxDefaultTemplate"] as ControlTemplate;
    }
    #endregion

}

控制模板:(删除了一些不相关的东西)

<ControlTemplate x:Name="ComboBoxDefaultTemplate" TargetType="my:ComboboxField">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="{TemplateBinding LabelColumnWidth}" />
                    <ColumnDefinition Width="{TemplateBinding FieldColumnWidth}" />
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Row="0" Grid.Column="0" Style="{TemplateBinding TitleStyle}" Text="{TemplateBinding Title}"></TextBlock>
                <TextBlock Text="*" Grid.Row="0" Grid.Column="0" Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Required, Converter={StaticResource boolToVisibility}}" Width="5" />
                <TextBlock Grid.Row="1" Grid.Column="0" Style="{TemplateBinding SummaryStyle}" Text="{TemplateBinding Summary}" Grid.ColumnSpan="2"></TextBlock>
<ComboBox Style="{TemplateBinding FieldStyle}" Grid.Row="0" Grid.Column="1"
                          ItemsSource="{TemplateBinding ItemsSource}" 
                          SelectedValue="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedValue, Mode=TwoWay}" 
                          SelectedValuePath="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedValuePath, Mode=TwoWay}" 
                          DisplayMemberPath="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisplayMemberPath, Mode=TwoWay}"></ComboBox>
            </Grid>
        </ControlTemplate>

我试图使用它的方式:

<cc:ComboboxField Grid.Row="10" TitleStyle="{StaticResource labelStyle}" 
                                  Title="Countries" ItemsSource="{Binding Countries}" 
                                  SelectedValuePath="CountryId" DisplayMemberPath="CountryId" 
                                  SelectedValue="{Binding Path=SelectedCountry, Mode=TwoWay}" />

我在这里做错了什么?

1 个答案:

答案 0 :(得分:1)

我可以立即看到您的依赖项属性的几个问题。

首先,我有一个黄金规则来处理你的代码违反的依赖属性:

  

CLR属性getter必须只包含对GetValue的调用,而setter必须只包含对SetValue的调用。

例如,SelectedValuePath属性应如下所示:

public string SelectedValuePath
{
    get { return (string)this.GetValue(SelectedValuePathProperty); }
    set { this.SetValue(SelectedValuePathProperty, value); }
}

如果要使用绑定,动画或样式更改依赖项属性的值,Silverlight不会调用您的属性。如果您在任何设置器上放置断点,您会发现它们不会像您预期的那样经常被击中。

您可以将两个依赖项属性绑定在一起,而无需任何一个类需要实现INotifyPropertyChanged。我假设您的NotifyPropertyChanged方法触发了PropertyChanged事件,您应该可以将其删除。

此外,如果您希望Value属性在每次更改后都设置为SelectedValue属性的值,则需要将PropertyChangedCallback添加到SelectedValue依赖项属性中

其次,SelectedValuePathPropertyDisplayMemberPathPropertyItemsSourceProperty的依赖属性注册是错误的。当它们归Field类所有时,它们都将所有者类指定为ComboboxField

最后,你说你是

  

很难获得一些绑定工作

你没告诉我们你的问题究竟是什么。您期望代码做什么以及它实际上在做什么?鉴于我没有您的FormFieldFieldDescription类以及您的FieldType枚举,我无法运行您的代码,因此我无法提供帮助你了。