TextBlock MultiBinding throws exception - c#

A TextBlock, should only be visible if a CheckBox is checked (x:Name=DisplaySubscriber) or the Binding string is not null or empty.
This is my approach:
<CheckBox Content="Display Subscriber" x:Name="DisplaySubscriber" />
<TextBlock Text="{Binding Path=SubscriberString, Mode=OneWay}" >
<TextBlock.Visibility>
<MultiBinding>
<Binding ElementName="DisplaySubscriber" Path="IsChecked" Mode="OneWay" Converter="{StaticResource BooleanToVisibleConverter}"/>
<Binding Path="SubscriberString" Mode="OneWay" Converter="{StaticResource StringIsNullEmptyConverter}"/>
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
But I got this error:
Provide value on 'System.Windows.Data.MultiBinding' threw an
exception.

converter:
public class TextBlockVisibilityConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if((value[0] != null && (bool)value[0]) || (value[1]!=null && !String.IsNullOrEmpty(value[1].ToString())))
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
#endregion
}
xaml:
define the converter in resource:
<local:TextBlockVisibilityConverter x:Key="TextBlockVisibilityConverter"/>
use it in the multibinding
<MultiBinding Converter="{StaticResource TextBlockVisibilityConverter}">
<Binding ElementName="DisplaySubscriber" Path="IsChecked"/>
<Binding Path="SubscriberString" />
</MultiBinding>

Related

Error with Binding in Caliburn.Micro, how to solve?

The rest of my program binds normally, but this part of the code doesn't work:
This is my View:
<Window x:Class="TestProject.Views.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestProject.Views"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
Title="MainWindowView" Height="450" Width="800">
<Window.Resources>
<local:LookupConverter x:Key="LookupConverter" />
<Style x:Key="CalendarDayButtonStyle" TargetType="CalendarDayButton">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource LookupConverter}">
<Binding />
<!--CaliburnMicro does not connect-->
<Binding Path="Dates" RelativeSource="{RelativeSource AncestorType=Calendar}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="Pink" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Margin="5">
<Calendar SelectionMode="MultipleRange"
CalendarDayButtonStyle="{DynamicResource CalendarDayButtonStyle}" />
</Grid>
This is my converter:
public class LookupConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var date = (DateTime)values[0];
var dates = values[1] as HashSet<DateTime>;
return dates.Contains(date);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
And this is my ViewModel:
internal class MainWindowViewModel : Screen
{
public MainWindowViewModel()
{
Dates.Add(DateTime.Today);
Dates.Add(DateTime.Today.AddDays(2));
Dates.Add(DateTime.Today.AddDays(4));
}
public HashSet<DateTime> Dates { get; } = new HashSet<DateTime>();
}
I hosted this part of the code with the problem on GitHub: https://github.com/Foiolag/TestProject.git
Please, someone help me make this work with Caliburn Micro =]
As Pavel points out, RelativeSource binds to the control itself, not its DataContext. You need to declare the binding as I originally provioded it:
<Binding Path="DataContext.Dates" RelativeSource="{RelativeSource AncestorType=Calendar}" />

Attached Property not triggering IMultiValueConverter

Below is my DataGrid with some attached properties that are associated with the popup controls further down. The ComboBox is populated by an enum.
<DataGrid Name="GenericDataGrid"
helpers:SearchBehaviours.SearchValue="{Binding ElementName=FindTextbox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
helpers:SearchBehaviours.IsFindPopupOpen="{Binding ElementName=PopupFind, Path=IsOpen, UpdateSourceTrigger=PropertyChanged}"
helpers:SearchBehaviours.SearchableItems="{Binding ElementName=ComboSearchableItems, Path=SelectedValue, UpdateSourceTrigger=PropertyChanged}" >
</DataGrid>
<Popup x:Name="PopupFind">
<TextBox x:Name="FindTextbox" />
<ComboBox x:Name="ComboSearchableItems"
ItemsSource="{Binding Source={helpers:Enumeration {x:Type helpers:SearchItems}}}"
DisplayMemberPath="Description"
SelectedValue="{x:Static helpers:SearchItems.AllItems}"
SelectedValuePath="Value" />
</Popup>
Here is the class that handles the behaviors:
class SearchBehaviours
{
// Using a DependencyProperty as the backing store for IsTextMatch. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsTextMatchProperty =
DependencyProperty.RegisterAttached("IsTextMatch", typeof(bool), typeof(SearchBehaviours), new UIPropertyMetadata(false));
public static bool GetIsTextMatch(DependencyObject obj)
{
return (bool)obj.GetValue(IsTextMatchProperty);
}
public static void SetIsTextMatch(DependencyObject obj, bool value)
{
obj.SetValue(IsTextMatchProperty, value);
}
public static readonly DependencyProperty SearchValueProperty =
DependencyProperty.RegisterAttached("SearchValue", typeof(string), typeof(SearchBehaviours), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.Inherits));
public static string GetSearchValue(DependencyObject obj)
{
return (string)obj.GetValue(SearchValueProperty);
}
public static void SetSearchValue(DependencyObject obj, string value)
{
obj.SetValue(SearchValueProperty, value);
}
public static readonly DependencyProperty IsFindPopupOpenProperty =
DependencyProperty.RegisterAttached("IsFindPopupOpen", typeof(bool), typeof(SearchBehaviours),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits));
public static bool GetIsFindPopupOpen(DependencyObject obj)
{
return (bool)obj.GetValue(IsFindPopupOpenProperty);
}
public static void SetIsFindPopupOpen(DependencyObject obj, bool value)
{
obj.SetValue(IsFindPopupOpenProperty, value);
}
public static readonly DependencyProperty SearchableItemsProperty =
DependencyProperty.RegisterAttached("SearchableItems", typeof(SearchItems), typeof(SearchBehaviours), new PropertyMetadata(SearchItems.AllItems));
public static SearchItems GetSearchableItems(DependencyObject obj)
{
return (SearchItems)obj.GetValue(SearchableItemsProperty);
}
public static void SetSearchableItems(DependencyObject obj, SearchItems value)
{
obj.SetValue(SearchableItemsProperty, value);
}
}
The issue is in the following IMultiValueConverter
<Style TargetType="{x:Type DataGridCell}" x:Key="textCellStyle" >
<Setter Property="helpers:SearchBehaviours.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource SearchValueConverter}" FallbackValue="False">
<Binding Path="Content.Text" RelativeSource="{RelativeSource Self}" />
<Binding Path="(helpers:SearchBehaviours.SearchValue)" RelativeSource="{RelativeSource Self}" />
<Binding Path="(helpers:SearchBehaviours.IsFindPopupOpen)" RelativeSource="{RelativeSource Self}"/>
<Binding Path="(helpers:SearchBehaviours.SearchableItems)" RelativeSource="{RelativeSource Self}"/>
<Binding />
<Binding RelativeSource="{x:Static RelativeSource.Self}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="helpers:SearchBehaviours.IsTextMatch" Value="True">
<Setter Property="Background" Value="DarkOrange" />
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
It triggers the IMultiValueConverter up when the popup is open and closed.
It triggers when the textbox text is changed.
However if the SelectedValue changes in the ComboBox it does not trigger.
Below is the converter it is pretty simple at present outputing when triggered.
public class SearchValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Console.WriteLine("Triggered");
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
[EDIT]
public enum SearchItems
{
[Description("All Items")]
AllItems,
[Description("Selected Items")]
SelectedItems
}
[END EDIT]
Can someone what the issue is?
Change DataGridCell Style code as below :
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="local:SearchBehaviours.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource SearchValueConverter}" FallbackValue="False">
<Binding Path="Content.Text" RelativeSource="{RelativeSource Self}" />
<Binding Path="(local:SearchBehaviours.SearchValue)" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}" />
<Binding Path="(local:SearchBehaviours.IsFindPopupOpen)" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}"/>
<Binding Path="(local:SearchBehaviours.SearchableItems)" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}"/>
<Binding />
<Binding RelativeSource="{x:Static RelativeSource.Self}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="local:SearchBehaviours.IsTextMatch" Value="True">
<Setter Property="Background" Value="DarkOrange" />
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
You were passing all attached properties of DataGridCell to MultiBinding Converter which was not assigned.In order to solve this issue, you have to pass DataGrid's attached properties to MultiBindingConverter.
UPDATE :
You can also use ComboBox like this :
<ComboBox x:Name="ComboSearchableItems"/>
& Assign ItemSource by code behind to it like this :
ComboSearchableItems.ItemsSource = Enum.GetValues(typeof(SearchItems));
If you want to bind only using XAML then refer this link
Star by using the WPF inspector to examine what you have bound to your control at all.
enter link description here

Multibinding Error

I posted my question before:
Multi-Forms Binding data
I solved it by building Converter.
XAML:
<Window x:Class="Test_MultiBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="621"
xmlns:c="clr-namespace:Test_MultiBinding">
<Window.Resources>
<c:myConverter x:Key="TestConverter"/>
</Window.Resources>
<Grid>
<TextBox TextWrapping="Wrap" AcceptsReturn="True" Height="269" HorizontalAlignment="Left" Margin="376,22,0,0" Name="textBox1" VerticalAlignment="Top" Width="211" >
<TextBox.Text>
<MultiBinding Converter="{StaticResource TestConverter}">
<Binding ElementName="textBox2" Path="Text"/>
<Binding ElementName="textBox3" Path="Text"/>
<Binding ElementName="textBox4" Path="Text"/>
<Binding ElementName="textBox5" Path="Text"/>
<Binding ElementName="textBox6" Path="Text"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
<TextBox Height="40" HorizontalAlignment="Left" Margin="130,24,0,0" Name="textBox2" VerticalAlignment="Top" Width="222"/>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="12,22,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<TextBox Height="40" HorizontalAlignment="Left" Margin="130,70,0,0" Name="textBox3" VerticalAlignment="Top" Width="222" />
<TextBox Height="40" HorizontalAlignment="Left" Margin="130,116,0,0" Name="textBox4" VerticalAlignment="Top" Width="222" />
<TextBox Height="40" HorizontalAlignment="Left" Margin="130,162,0,0" Name="textBox5" VerticalAlignment="Top" Width="222" />
<TextBox Height="91" HorizontalAlignment="Left" Margin="130,208,0,0" Name="textBox6" VerticalAlignment="Top" Width="222" />
</Grid>
</Window>
MainWindow:
namespace Test_MultiBinding
{
public partial class MainWindow : Window
{
......
}
[ValueConversion(typeof(string), typeof(string))]
public class myConverter : IValueConverter
{
public Object Convert(object[] value, Type targettype, object parameter, System.Globalization.CultureInfo cultreinfo)
{
return str1 + value[0].ToString() + str2 + value[1].ToString() + str3 + value[2].ToString() + str4 + value[3].ToString() + str5 + value[4].ToString() + str6;
}
public Object ConvertBack(object value, Type targettype, object parameter, System.Globalization.CultureInfo cultreinfo)
{
throw new NotImplementedException();
}
}
}
In which str1,2,3,... are string. When I run it, I got error:
An object of the type "Test_MultiBinding.myConverter" cannot be applied to a property that expects the type "System.Windows.Data.IMultiValueConverter"
Please help!
For a MultiBinding you have to implement the IMultiValueConverter Interface instead of IValueConverter.
public class myConverter : IMultiValueConverter
public class MultiStringConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string result = "";
foreach(object value in values)
result += value.ToString();
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

MultiBinding Converter in CheckBox.IsChecked not called

I have a custom combobox a multiselectioncombobox if you will,
the thing is the selections depend on an other collection. I tried to bind ComboBox.IsChecked property to MultiBinding Converter but the converter isn't called.
<DataTemplate>
<StackPanel Orientation="Horizontal" x:Name="ItemStack" VirtualizingStackPanel.IsVirtualizing="False">
<CheckBox x:Name="CheckBoxItem"
Command="{Binding SelectItem, RelativeSource={RelativeSource AncestorType={x:Type MultiSelectionComboBox}}}"
CommandParameter="{Binding Key}"
>
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource MultiSelectionCommandConverter}" Mode="OneWay">
<Binding Path="Key"/>
<Binding Path="SelectedItem"
RelativeSource="{RelativeSource AncestorType={x:Type MultiSelectionComboBox}}" />
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
<TextBlock Text="{Binding DisplayText}"></TextBlock>
</StackPanel>
</DataTemplate>
and the converter is,
public class MultiSelectionCommandConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
///stuff to do...
}
public object[] ConvertBack(object values, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
any suggestions?
After trying out possibilities, I've found a work around. Still I'm not quite sure why this might work and the other won't.
I've changed my xaml to pass the whole object instead of the property. So the code looked liked this,
<DataTemplate>
<StackPanel Orientation="Horizontal" x:Name="ItemStack" VirtualizingStackPanel.IsVirtualizing="False">
<CheckBox x:Name="CheckBoxItem"
Command="{Binding SelectItem, RelativeSource={RelativeSource AncestorType={x:Type MultiSelectionComboBox}}}"
CommandParameter="{Binding Key}"
>
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource MultiSelectionCommandConverter}" Mode="OneWay">
<Binding Path="Key"/>
<Binding
RelativeSource="{RelativeSource AncestorType={x:Type MultiSelectionComboBox}}" />
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
<TextBlock Text="{Binding DisplayText}"></TextBlock>
</StackPanel>
</DataTemplate>
and the converter is
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string key = (string)values[0];
ObservableCollection<ListItem> selectedItems = (values[1] as MultiSelectionComboBox).SelectedItem;
//do stuff
return false;
}
This is definitely not a desired solution but, this will do until i figure out the other reason.

get user input from comboBox and bind to two variables from different classes

So i just started wpf a few months ago and now i want to get user input from a comboBox and bind it to two variables such that when selectedItem changes, the two variables will also be reflect the change.
The error i am facing now is this:
System.Windows.Data Warning: 40 : BindingExpression path error: '_institution' property not found on 'object' ''ObjectDataProvider' (HashCode=22018304)'. BindingExpression:Path=_institution; DataItem='ObjectDataProvider' (HashCode=22018304); target element is 'ComboBox' (Name='institutionCB'); target property is 'SelectedItem' (type 'Object')
and i have no idea what it says.
<Windows.Resources>
<ObjectDataProvider x:Key="institutionData" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:Institutions"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProvider x:Key="userInputData" ObjectType="{x:Type local:userInputData}">
<ObjectDataProvider.MethodParameters>
<sys:String>_institution</sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProvider x:Key="commonServiceModel" ObjectType="{x:Type local:ServiceCommonModel}">
<ObjectDataProvider.MethodParameters>
<sys:String>_institution</sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<local:Converter x:Key="Converter"/>
</Window.Resources>
converter is in my code behind:
public class Converter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values.ToString();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new object[] { value, value };
}
}
and this is my comboBox:
<ComboBox x:Name="institutionCB" HorizontalAlignment ="Left" VerticalAlignment="Top" Height="22" Width="51" Margin="5,27,0,0" Background="White"
ItemsSource="{Binding Source={StaticResource institutionData}}" Tag="Institution">
<ComboBox.SelectedItem>
<MultiBinding Converter="{StaticResource Converter}">
<Binding Source="{StaticResource userInputData}" Path="_institution" BindsDirectlyToSource="True" Mode="OneWayToSource"/>
<Binding Source="{StaticResource commonServiceModel}" Path="_institution" BindsDirectlyToSource="True" Mode="OneWayToSource"/>
</MultiBinding>
</ComboBox.SelectedItem>
</ComboBox>

Categories