我有自定义控件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]。我怎样才能使它发挥作用?
答案 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”,然后您就可以更改实例成员:)