Reputation: 1905
I simply want to use MultiBinding
for a WrapPanel
's ItemHeight
& ItemWidth
. The code is like this:
<Window.Resources>
<local:SensorHeightCalculator x:Key="HeightCalculator"/>
<local:SensorWidthCalculator x:Key="WidthCalculator"/>
</Window.Resources>
<Border x:Name="sensorPanelBorder" BorderBrush="#FFD5DFE5" BorderThickness="1" Grid.Column="2" Margin="0,9,2,2" CornerRadius="3">
<ListView x:Name="sensorPanel" Margin="0" ItemsSource="{Binding Source={StaticResource SensorControls}}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel x:Name="sensorWrapPanel" IsItemsHost="True">
<WrapPanel.ItemHeight>
<MultiBinding Converter="{StaticResource HeightCalculator}" UpdateSourceTrigger="PropertyChanged">
<Binding ElementName="sensorPanelBorder" Path="ActualHeight"/>
<Binding ElementName="sensorPanelBorder" Path="ActualWidth"/>
<Binding ElementName="sensorPanel" Path="Items.Count"/>
</MultiBinding>
</WrapPanel.ItemHeight>
</WrapPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Border>
But it throws exceptions and does not render. I also tried to do this in code-behind but that didn't work either.
The actual problem is that I need to bind the items of WrapPanel
to a CollectionViewSource
, and therefore, as I read online, I have to use the WrapPanel
inside a ListView
(like above). Before that, I filled the WrapPanel
manually I had a method which I was used to use to calculate the ItemHeight
and ItemWidth
of the WrapPanel
and assign to that. But now that the WrapPanel
is inside the ListView
, it's not accessible in code-behind and hence I decided to use the Multibinding
.
The Source of SensorHeightCalculator:
public class SensorHeightCalculator : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double H = (double)values[0];
double W = (double)values[1];
double N = (double)values[2];
if (N > 0)
{
double k = 7.0 / 6.0;
double c = N;
double r = 1;
double ah, aw, a, b;
do
{
aw = (W - 2) / c;
ah = k * aw;
if (Math.Floor(H / ah) <= r) break;
else
{
r++;
c = c - Math.Floor(c / r);
}
} while (r <= N);
a = Math.Min(aw, H / (k * r));
b = k * a;
return b - 10;
}
else
return 300;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return default(object[]);
}
}
The exception and full stack trace of that:
Exception: InvalidCastException: Specified cast is not valid.
Stack trace:
at AvaPa.SensorHeightCalculator.Convert(Object[] values, Type targetType, Object parameter, CultureInfo culture)
at System.Windows.Data.MultiBindingExpression.TransferValue()
at System.Windows.Data.MultiBindingExpression.Transfer()
at System.Windows.Data.MultiBindingExpression.UpdateTarget(Boolean includeInnerBindings)
at System.Windows.Data.MultiBindingExpression.AttachToContext(Boolean lastChance)
at System.Windows.Data.MultiBindingExpression.AttachOverride(DependencyObject d, DependencyProperty dp)
at System.Windows.Data.BindingExpressionBase.OnAttach(DependencyObject d, DependencyProperty dp)
at System.Windows.StyleHelper.GetInstanceValue(UncommonField1 dataField, DependencyObject container, FrameworkElement feChild, FrameworkContentElement fceChild, Int32 childIndex, DependencyProperty dp, Int32 i, EffectiveValueEntry& entry)
at System.Windows.StyleHelper.GetChildValueHelper(UncommonField
1 dataField, ItemStructList1& valueLookupList, DependencyProperty dp, DependencyObject container, FrameworkObject child, Int32 childIndex, Boolean styleLookup, EffectiveValueEntry& entry, ValueLookupType& sourceType, FrameworkElementFactory templateRoot)
at System.Windows.StyleHelper.GetChildValue(UncommonField
1 dataField, DependencyObject container, Int32 childIndex, FrameworkObject child, DependencyProperty dp, FrugalStructList1& childRecordFromChildIndex, EffectiveValueEntry& entry, ValueLookupType& sourceType, FrameworkElementFactory templateRoot)
at System.Windows.StyleHelper.GetValueFromTemplatedParent(DependencyObject container, Int32 childIndex, FrameworkObject child, DependencyProperty dp, FrugalStructList
1& childRecordFromChildIndex, FrameworkElementFactory templateRoot, EffectiveValueEntry& entry)
at System.Windows.StyleHelper.ApplyTemplatedParentValue(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList1& childRecordFromChildIndex, DependencyProperty dp, FrameworkElementFactory templateRoot)
at System.Windows.StyleHelper.InvalidatePropertiesOnTemplateNode(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList
1& childRecordFromChildIndex, Boolean isDetach, FrameworkElementFactory templateRoot)
at System.Windows.FrameworkTemplate.InvalidatePropertiesOnTemplate(DependencyObject container, Object currentObject)
at System.Windows.FrameworkTemplate.HandleBeforeProperties(Object createdObject, DependencyObject& rootObject, DependencyObject container, FrameworkElement feContainer, INameScope nameScope)
at System.Windows.FrameworkTemplate.<>c__DisplayClass45_0.b__2(Object sender, XamlObjectEventArgs args)
at System.Xaml.XamlObjectWriter.OnBeforeProperties(Object value)
at System.Xaml.XamlObjectWriter.Logic_CreateAndAssignToParentStart(ObjectWriterContext ctx)
at System.Xaml.XamlObjectWriter.WriteStartMember(XamlMember property)
at System.Xaml.XamlWriter.WriteNode(XamlReader reader)
at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)
Thanks in advance for helping
Upvotes: 0
Views: 221
Reputation: 128157
double N = (double)values[2];
is an invalid cast when the third binding in the MultiBinding binds to an integer:
<Binding ... Path="Items.Count"/>
So cast to an integer
var N = (int)values[2];
You should also make sure that the converter always returns a double, so replace
return 300;
with
return 300d;
Upvotes: 3