使用ObservableCollection进行自定义控件绑定

时间:2014-12-24 20:05:18

标签: c# .net

我有自定义控件MyGrid

public class MyGrid : Canvas
{
//...
    ObservableCollection<object> items = new ObservableCollection<object>();
    public ObservableCollection<object> Items
    {
        get { return items; }
        set { 
            items = value;
            UpdateValues();
            UpdateGrid();
        }
    }
    //..
}

我希望Items可以从XAML代码绑定:

<local:MyGrid Items="{Binding Numbers}" />

其中Numbers是ObservableCollection(工作正常,我可以使用它绑定到默认控件)。 我试图将Items定义为DependencyProperty,但它是静态的,我需要在页面上使用多个不同数据源的控件,因此使用静态项将无法工作。上面的代码也不起作用。 InitializeComponent()抛出异常:无法分配给属性'App.MyGrid.Items'。 [线:27位置:114]。我怎样才能使它发挥作用?

2 个答案:

答案 0 :(得分:0)

可能会对你有帮助。

<ItemsControl ItemsSource="{Binding items}">
     <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Margin="0,5,5,0" VerticalAlignment="Top">
                        <TextBlock TextAlignment="Right" FontWeight="Bold" Text="{Binding yourVariable}" Height="16"/>
                        <TextBlock TextAlignment="Right" Text="{Binding yourVariable1}" FontSize="26"/>
                        <TextBlock TextAlignment="Right" Text="{Binding yourVariable2}" FontSize="10" Foreground="DarkGray"/>
                    </StackPanel>                        
                </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.Template>
            <ControlTemplate>
                <ScrollViewer Padding="{TemplateBinding Padding}" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
                    <ItemsPresenter />
                </ScrollViewer>
            </ControlTemplate>
        </ItemsControl.Template>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel>
                </WrapPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

这可能实际上并不是你想要的。但我认为这可以帮到你。

答案 1 :(得分:0)

当你的MyGrid从Canvas扩展时(最后也是DependecyObject)你可以在MyGrid中实现Dependency属性。

然后你也可以使用PropertyChangedCallback实现它,这样你就可以注册/取消注册到事件本身,然后你可以在那里更新网格/值

所以你可以像这样改变MyGrid:

public class MyGrid : Canvas
{
    protected static PropertyChangedCallback ItemsPropertyChangedCallback = new PropertyChangedCallback(ItemsPropertyChanged);

    public static DependencyProperty ItemsProperty = DependencyProperty.RegisterAttached("Items", typeof(INotifyCollectionChanged), typeof(MyGrid), new PropertyMetadata(null, ItemsPropertyChangedCallback));

    private static void ItemsPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        MyGrid thisGrid = (MyGrid)sender;
        if (thisGrid == null)
        {
            return;
        }
        thisGrid.UnregisterItems(e.OldValue as INotifyCollectionChanged);
        thisGrid.RegisterItems(e.NewValue as INotifyCollectionChanged);
        thisGrid.Refresh();
    }

    public INotifyCollectionChanged Items 
    { 
        get
        {
            return (INotifyCollectionChanged)GetValue(ItemsProperty);
        }
        set
        {
            SetValue(ItemsProperty, value);
        }
    }

    protected void UnregisterItems(INotifyCollectionChanged items)
    {
        if (items == null)
        {
            return;
        }
        items.CollectionChanged -= ItemsChanged;
    }

    protected void RegisterItems(INotifyCollectionChanged items)
    {
        if (items == null)
        {
            return;
        }
        items.CollectionChanged += ItemsChanged;
    }

    protected virtual void UpdateValues()
    {
        System.Diagnostics.Debug.WriteLine("Updating values");
    }

    protected virtual void UpdateGrid()
    {
        System.Diagnostics.Debug.WriteLine("Updating grid");
    }

    public void Refresh()
    {
        UpdateValues();
        UpdateGrid();
    }

    protected virtual void ItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        Refresh();
    }

    public MyGrid()
    {
    }
}

然后在Xaml中你可以稍后绑定到Items属性。当Items属性与另一个集合一起更改时,它将从最后一个对象(如果有的话)的已更改事件中取消注册,然后注册到新对象(如果有)。之后,它将调用您的类的Refresh方法(然后调用UpdateValues / UpdateGrid方法)

我也同意@ user3248647你应该尽可能利用Binding和ContentTemplates,但是如果你不能使用它,你可以让你的DependencyProperty起反应至少这样。

是的,DependencyProperty在类上是静态的,但属性本身总是在类中实现。使用PropertyChangedCallback时,只需将发件人转发回“MyGrid”,然后您就可以更改实例成员:)