0

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(UncommonField1 dataField, ItemStructList1& valueLookupList, DependencyProperty dp, DependencyObject container, FrameworkObject child, Int32 childIndex, Boolean styleLookup, EffectiveValueEntry& entry, ValueLookupType& sourceType, FrameworkElementFactory templateRoot) at System.Windows.StyleHelper.GetChildValue(UncommonField1 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, FrugalStructList1& 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, FrugalStructList1& 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

Amir
  • 1,885
  • 3
  • 19
  • 36
  • "But it throws exceptions" - what exception? Recommended reading - http://meta.stackoverflow.com/questions/260648/stack-overflow-question-checklist. – Eugene Podskal Jun 25 '16 at 21:46
  • This is the exception, but I think does not really help: InvalidCastException: Specified cast is not valid. – Amir Jun 25 '16 at 21:49
  • Please, read http://meta.stackoverflow.com/questions/260648/stack-overflow-question-checklist%E2%80%8C%E2%80%8B, then add full stack trace of that exception to your question (not as comment). Also, this exception probably happens in `local:SensorHeightCalculator`, so its source code should be added as well. – Eugene Podskal Jun 25 '16 at 21:52
  • @EugenePodskal I'm pretty sure that the exception has nothing to do with the SensorHeightCalculator, but I add that if you think so – Amir Jun 25 '16 at 22:01
  • That stack trace seems to disagree with you - `at AvaPa.SensorHeightCalculator.Convert` – Eugene Podskal Jun 25 '16 at 22:03
  • @EugenePodskal Please explain the problem if you find out. I'm really stuck – Amir Jun 25 '16 at 22:04
  • Possible duplicate of [Why am I getting InvalidCastException?](http://stackoverflow.com/questions/5309436/why-am-i-getting-invalidcastexception) – Eugene Podskal Jun 25 '16 at 22:13

1 Answers1

3
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;
Clemens
  • 123,504
  • 12
  • 155
  • 268