Reputation: 13769
The code below binds column widths: Samp1.ActualWidth
and Samp2.ActualWidth
to StatName.Width
. See: Bind DataGrid Column Width to Two Colums of Another DataGrid
However, the Designer reports the error Specified cast is not valid.
, but in spite of the error, the code still compiles and executes as expected.
Even though it runs as expected, the "error" still bugs me.
Question: What is causing the error: Specified cast is not valid.
? What is being cast to what? How can I fix it? If a fix is not straightforward, how can I at least hide or ignore the error?
Note: The question WPF MultiBinding VS designer exception is similar. However, that code causes a runtime exception, while my code causes a build error and runs fine (without any exceptions thrown).
Xaml:
<Page.Resources>
<local:WidthConverter x:Key="WidthConverter" />
</Page.Resources>
<!--- ... -->
<DataGrid IsReadOnly="True" HeadersVisibility="Column">
<DataGrid.Columns>
<DataGridTextColumn x:Name="Samp1" Binding="{Binding a}" Header="S1" />
<DataGridTextColumn x:Name="Samp2" Binding="{Binding b}" Header="S2" />
<DataGridTextColumn x:Name="Total" Binding="{Binding c}" Header="Tot" />
</DataGrid.Columns>
<local:MyGenericRecord a="5000" b="2500" c="7500" />
<local:MyGenericRecord a="1000" b="1500" c="2500" />
</DataGrid>
<DataGrid IsReadOnly="True" HeadersVisibility="Column">
<DataGrid.Columns>
<DataGridTextColumn x:Name="StatName" Binding="{Binding a}" Header="Stat">
<DataGridTextColumn.Width >
<!-- ####################################### -->
<!-- Begin error: Specified cast is invalid. -->
<MultiBinding Converter="{StaticResource WidthConverter}">
<Binding Source="{x:Reference Samp1}" Path="ActualWidth" />
<Binding Source="{x:Reference Samp2}" Path="ActualWidth" />
</MultiBinding>
<!-- End error -->
<!-- ###################################### -->
</DataGridTextColumn.Width>
</DataGridTextColumn>
<DataGridTextColumn x:Name="StatValue" Binding="{Binding b}" Header="Val" Width="{Binding ElementName=Total, Path=ActualWidth}" />
</DataGrid.Columns>
<local:MyGenericRecord a="Min" b="2500" />
<local:MyGenericRecord a="Max" b="7500" />
<local:MyGenericRecord a="Average" b="5000" />
</DataGrid>
Converter:
public class WidthConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double totalWidth = 0;
foreach (double Width in values)
totalWidth += Width;
DataGridLength outLen = new DataGridLength(totalWidth);
return outLen;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return new object[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue};
}
}
public class MyGenericRecord
{
public string a { get; set; }
public string b { get; set; }
public string c { get; set; }
}
Upvotes: 4
Views: 1481
Reputation: 101573
In any converter you should always expect value (or values) can be DependencyProperty.UnsetValue
. This value is used by wpf when actual value cannot be obtained for whatever reason. Most often it happens when binding cannot be resolved (for example - you bind to property which does not exist). WPF designer does not compile the whole code, so it might misbehave, especially with bindings. Note that null
could not be used instead of UnsetValue
, because null
can be a valid value. So expect UnsetValue
and if possible, try to do something meaningful in that case. For example:
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double totalWidth = 0;
foreach (double Width in values.OfType<double>())
totalWidth += Width;
DataGridLength outLen = new DataGridLength(totalWidth);
return outLen;
}
This will ignore all values which are not double (including UnsetValue
).
Upvotes: 3