Amir
Amir

Reputation: 1905

WrapPanel ItemWidth & ItemHeight MultiBinding

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

Upvotes: 0

Views: 221

Answers (1)

Clemens
Clemens

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

Related Questions