【问题标题】:Property Binding to Dependency property in Custom control not working自定义控件中的属性绑定到依赖属性不起作用
【发布时间】:2018-10-02 06:43:28
【问题描述】:

我创建了一个名为“ItemsPerPage”的带有 DependencyProperty 的自定义控件。我在一个窗口中使用了那个自定义控件。现在,如果我将值直接分配给 ItemsPerPage 属性,那么它可以工作,但是如果我将它与窗口中定义的属性绑定,那么它就无法工作。

自定义控件声明。

public class SmartDataGrid : DataGrid
{

    public SmartDataGrid()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(SmartDataGrid), new FrameworkPropertyMetadata(typeof(SmartDataGrid)));
    }


    public static readonly DependencyProperty ItemsPerPageProperty =
       DependencyProperty.Register("ItemsPerPage", typeof(Int32),
           typeof(SmartDataGrid)
           , new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnItemsPerPageChanged, CoerceTextProperty, true, UpdateSourceTrigger.PropertyChanged));

    public Int32 ItemsPerPage
    {
        get
        {
            return (Int32)GetValue(ItemsPerPageProperty);
        }
        set
        {
            SetValue(ItemsPerPageProperty, value);
        }
    }

    private static void OnItemsPerPageChanged(DependencyObject defectImageControl, DependencyPropertyChangedEventArgs eventArgs)
    {
        var control = (SmartDataGrid)defectImageControl;
        control.callmyInstanceMethod(eventArgs);
    }

    private static object CoerceTextProperty(DependencyObject d, object value)
    {
        return value ?? 0;
    }
    private void callmyInstanceMethod(DependencyPropertyChangedEventArgs e)
    {
        ItemsPerPage = (Int32)e.NewValue;
    }
}

现在我创建了一个新的 WPF 项目,并在 Window1 中使用了这个自定义控件,如下所示。

<Grid>
        <sg:SmartDataGrid ItemsPerPage="{Binding ipp}"></sg:SmartDataGrid>
    </Grid>

这里的sg:是一个命名空间声明添加自定义控件项目的引用。并且在Window1的.cs文件中我已经声明了一个属性。

public partial class Window1 : Window, INotifyPropertyChanged
{

    int _ipp;
    public int ipp
    { get { return _ipp; } set { _ipp = value; RaisePropertyChanged(); } }

    public Window1()
    {
        ipp = 30;
        InitializeComponent();
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

但值 30 未分配给 ItemsPerPage 属性。它总是显示0。 如果我直接分配 30 ItemsPerPage="30"。然后它就可以工作了。

【问题讨论】:

  • 属性的每次更改都必须通知才能使绑定正常工作。这里没有魔法。一个普通的类(ViewModel,Model,...)应该实现 INotifyPropertyChanged,从 DependencyObject 派生的类应该使用 DependencyProperty(Window 是从 DependencyObject 派生的)
  • 我已经实现了 NotifyPropertyChanged 但仍然无法正常工作
  • @SirRufo,我认为DataGrid也是从DepedencyObject派生的。
  • 请注意您的 OnItemsPerPageChanged 回调是没有意义的。无需设置ItemsPerPage = (Int32)e.NewValue;,因为它已经具有该值。回调旨在在属性值更改后执行操作。
  • 是的,我知道还有一些额外的实现。但我正在尝试不同的选择来让它发挥作用。我将删除额外的工作。

标签: c# wpf data-binding dependency-properties


【解决方案1】:

我认为 OP 的作者不想将 datacontext 设置为窗口。 您需要像这样将控件绑定到 Window 的属性:

ItemsPerPage="{Binding Path=ipp,
                          RelativeSource={RelativeSource Mode=FindAncestor,
                                                         AncestorType=Window}}"

ipp 应通知属性已更改:

int _ipp;
public int ipp
{ 
   get=>_ipp;
   set{
        if (value!=_ipp)
        {
           _ipp=value;
           RaisePropertyChanged(nameof(ipp));
        }
   }
}
void RaisePropertyChanged(string propname)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
}


public Window1()
{
     ipp = 30;
     InitializeComponent();
}

【讨论】:

  • 虽然它可以工作,但从 DependencyObject 派生的类应该使用 DependencyProperty
  • @Access Denied,问题已更新,我已经实现了 NotifyPropertyChanged,但它仍然无法正常工作。而且我在初始化之前为 ipp 分配了值,因此它应该在没有 NotifyPropertyChanged 的​​情况下工作。
  • @AccessDenied 您的解决方案有效并标记为该解决方案非常适合我的需要。我不想实现数据上下文。
【解决方案2】:

主要问题是,您没有指定窗口的DataContext

public partial class Window1 : Window
{
    public int ipp { get; set; }
    public Window1()
    {
        ipp = 30;
        InitializeComponent();
        DataContext = this;
    }
}

【讨论】:

  • @maulikkansara 您应该考虑为您的视图设置一个 ViewModel,并将该 ViewModel 用作绑定的 DataContext。 MVVM 是开发 WPF 时考虑的模式
  • 同意。但我正在准备一个演示项目来测试自定义控件,只是忽略了在演示项目中实现 MVVM。那是我最大的错误。
  • 您的解决方案有效,并且是第一个有效的答案。但收到了来自@access Denied 的另一个答复。我认为这是完美的解决方案。因为在没有 MVVM 模式实现的情况下分配 DataContext 是一种解决问题的方法。
  • @maulikkansara "因为在没有 MVVM 模式实现的情况下分配 DataContext 是解决问题的方法" 并不完全正确。将 Window 的 DataContext 设置为自身是很常见的。 根本没有设置DataContext是不常用的。
猜你喜欢
  • 2012-08-29
  • 2019-05-26
  • 2012-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多