I'm using a binding of the form
{Binding RelativeSource={RelativeSource Self}, Path=Children.Count, Converter={StaticResource CountToDimensionConverter}, ConverterParameter=Rows}
Despite adding the children in xaml, when I break in the converter, the value is always 0.
What I assume is going on is that the children are not added until after this binding is called.
I also assume that the binding is broken after it's been called once because .Count is a readonly property (I've had a similar problem before where I had to add an empty setter in the property to maintain the binding and fool WPF) hence the binding not updating once children are added.
However, I'm stuck on the bit where you come up with a solution for the problem and make it work... =/
<UniformGrid x:Name="MyUniformGrid"
Rows="{Binding RelativeSource={RelativeSource Self}, Path=Children.Count, Converter={StaticResource CountToDimensionConverter}, ConverterParameter=R}"
Columns="{Binding RelativeSource={RelativeSource Self}, Path=Children.Count, Converter={StaticResource CountToDimensionConverter}, ConverterParameter=C}">
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
</UniformGrid>
Thanks, Rabit
That's because UIElementCollection
(the type of the Children
property) doesn't raise notifications when a new item is added or removed, so the binding isn't refreshed
You could, however, create your own custom UniformGrid
, and override the CreateUIElementCollection
property to create an instance of a custom collection that inherits UIElementCollection
and implements INotifyCollectionChanged
.
Here's a basic implementation :
ObservableUIElementCollection
public class ObservableUIElementCollection : UIElementCollection, INotifyCollectionChanged, INotifyPropertyChanged
{
public ObservableUIElementCollection(UIElement visualParent, FrameworkElement logicalParent)
: base(visualParent, logicalParent)
{
}
public override int Add(UIElement element)
{
int index = base.Add(element);
var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, element, index);
OnCollectionChanged(args);
OnPropertyChanged("Count");
OnPropertyChanged("Item[]");
return index;
}
public override void Clear()
{
base.Clear();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged("Count");
OnPropertyChanged("Item[]");
}
public override void Insert(int index, UIElement element)
{
base.Insert(index, element);
var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, element, index);
OnCollectionChanged(args);
OnPropertyChanged("Count");
OnPropertyChanged("Item[]");
}
public override void Remove(UIElement element)
{
int index = IndexOf(element);
if (index >= 0)
{
RemoveAt(index);
var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, element, index);
OnCollectionChanged(args);
OnPropertyChanged("Count");
OnPropertyChanged("Item[]");
}
}
public override UIElement this[int index]
{
get
{
return base[index];
}
set
{
base[index] = value;
var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, index);
OnCollectionChanged(args);
OnPropertyChanged("Item[]");
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
var handler = CollectionChanged;
if (handler != null)
handler(this, e);
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
MyUniformGrid
public class MyUniformGrid : UniformGrid
{
protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)
{
return new ObservableUIElementCollection(this, logicalParent);
}
}
XAML
<local:MyUniformGrid x:Name="MyUniformGrid"
Rows="{Binding RelativeSource={RelativeSource Self}, Path=Children.Count, Converter={StaticResource CountToDimensionConverter}, ConverterParameter=R}"
Columns="{Binding RelativeSource={RelativeSource Self}, Path=Children.Count, Converter={StaticResource CountToDimensionConverter}, ConverterParameter=C}">
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
<Button Content="Hello, World!" />
</local:MyUniformGrid>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With