How can I bind an inverted value of a bool in my xaml?
I know, I know, there are a lot of q&a about this, but there aren't any about a specific case: when the converter is in a view model and the radio button in a user control.
how can I correctly refer to the main window view model data context? In other case I used the code I've posted, but in this case I don't get how to use it.
UPDATE CODE:
namespace ***.ViewModel
{
[ValueConversion(typeof(bool), typeof(bool))]
public class InverseBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (targetType != typeof(bool))
throw new InvalidOperationException("The target must be a boolean");
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
class MainWindowViewModel : MyClass.UtilityClasses.ViewModelBase
{
public MainWindowViewModel(){
SaveCommand = new DelegateCommand(SaveData, CanSave );
UndoCommand = new DelegateCommand(UndoActions, CanSave);
[...]
}
....
}
ANOTHER CODE UPDATE:
In my xaml, I have a devexpress GridControl where I list my observableCollection from db. When I click one element, a layout group is populated with the relative data.
In this layout group, I have:
<StackPanel Margin="0" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Left">
<RadioButton Content="{DynamicResource Locale}" Margin="10,0,0,0" x:Name="rd_LOCALE" VerticalAlignment="Center" IsChecked="{Binding Path=REMOTO, Converter={StaticResource InverseBooleanConverter}}" GroupName="Location" Panel.ZIndex="9" TabIndex="10" />
<RadioButton Content="{DynamicResource Remoto}" Margin="10,0,6,0" x:Name="rd_REMOTO" VerticalAlignment="Center" IsChecked="{Binding REMOTO}" GroupName="Location" Panel.ZIndex="10" TabIndex="11" Tag="PRISMA" />
</StackPanel>
WhenI change from one record to another, the converter gives me error... why? It fails the "if (targetType != typeof(bool))" row. So I tried to change that like:
if (value.getType() != typeof(bool))
but in this way, without fails nothing in the code, it put the wrong value in the radiobutton!
You need to make sure that the value converter is referenced in the XAML
<UserControl.Resources>
<myproject:InverseBooleanConverter x:Key="InverseBooleanConverter" />
</UserControl.Resources>
where my project is the namespace in which the value converter class is defined
Related
What I want it to bind TextBoxes to my dictionaries values.
I could find some posts about it already but :
One means having my dictionary as context :
XML :
<TextBox x:Name="FirstLine" Text="{Binding Path=[FirstLine]}"/>
XAML :
public ImportProfilesOptions()
{
InitializeComponent();
contexte = new ViewModelImportProfilesOptions();
DataContext = contexte.ParamsData;
}
The other one using Templates :
<ItemsControl x:Name="dictionaryItemsControl" ItemsSource="{Binding dictionary}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But I would like to use it, without using Templates (I need to add in labels some translates I take from properties), and without setting my dictionary as context. Something like that :
XML
<TextBox x:Name="FirstLine" Text="{Binding Path=ParamsDate[FirstLine]}" />
XAML
contexte = new ViewModelImportProfilesOptions();
DataContext = contexte;
But then, binding is not working anymore.
You can't do this out of the box, though you could create your own converter I guess:
public class SomeFunkyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is Dictionary<string,string> dictionary))
return null;
if (!(parameter is string key))
return null;
return !dictionary.TryGetValue(key, out var result) ? null : result;
}
// ill leave this up to you
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
Usage
<TextBlock Text="{Binding Path=ParamsDate,
ElementName=TextBox,
Converter={StaticResource SomeFunkyConverter},
ConverterParameter='Bob'}"/>
Note : Completely untested
I have a combobox with StaticResource called Currencies, Currencies is an ObservableCollection of some class
in this class i have a parameter called CurrencyID.
I have another class called Item which have a parameter called CurrencyID.
i want to set the Item.CurrencyID from the combobox, for that i use ValueSelected and ValueSelectedPath with a converter from comboboxitem to the CurrencyID.
and it works.
next i want to select the comboboxitem from the CurrencyID of the Item class.
But it always show unselected comboboxitem.
Here's the relevant code:
XAML:
<Window.Resources>
<converters:sp_GetCurrencies_ResultToID x:Key="sp_GetCurrencies_ResultToIDConverter"/>
<CollectionViewSource x:Key ="Currencies" Source="{Binding Currencies}"/>
</Window.Resources>
<ComboBox x:Name="cmbCurrencies" ItemsSource="{Binding Source={StaticResource Currencies} }" SelectedValuePath="{Binding CurrencyID, Mode=TwoWay}" SelectedValue="{Binding Item.CurrencyID, Converter={StaticResource sp_GetCurrencies_ResultToIDConverter}}" DisplayMemberPath="CurrencyName" Width="150" Height="30" VerticalContentAlignment="Center" FlowDirection="RightToLeft" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="5"/>
Converter:
public class sp_GetCurrencies_ResultToID : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
using (PricingManagerEntities db = new PricingManagerEntities())
return db.sp_GetCurrencies((long)value,null).FirstOrDefault();
else
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
return (value as sp_GetCurrencies_Result).CurrencyID;
}
else return null;
}
}
Inside the code i set Item.CurrencyID = 1.
I'm getting also this error, in which i think it's related:
BindingExpression path error: 'CurrencyID' property not found on 'object' ''ItemsViewModel' (HashCode=45202739)'. BindingExpression:Path=CurrencyID; DataItem='ItemsViewModel' (HashCode=45202739); target element is 'ComboBox' (Name='cmbCurrencies'); target property is 'SelectedValuePath' (type 'String')
The program '[12436] PricingManager.vshost.exe' has exited with code 0 (0x0).
Thank you for your help.
<Button
VerticalAlignment="Stretch"
ToolTip="Convert selected Node(s)"
ToolTipService.ShowOnDisabled="False"
Visibility="{Binding Source={StaticResource serviceLocator}, Path=NetworkManager.NetworkViewModel.IsGenericProfileLoaded}"
Command="{Binding Path=ConvertToNonControlPlaneCommand}" >
<Image
Style="{StaticResource toolbarImageStyle}"
Source="/Resources/Icons/equipment_edit.png"
/>
</Button>
The button should be collapsed or invisible depending on the Path property called IsGenericProfileLoaded. Even if IsGenericProfileLoaded is false, the button is still visible. How to make it invisible. From other question on stackoverflow, it seems that i need to visibilitytoBoolean converter or is there anything that I can use here like disable="true"?
In general when a data binding does not work, debug the app in Visual Studio and look in the debug output. You can show the debug output by: menu / DEBUG / Windows / Output. Go in the application to that page and keep an eye to the messages shown in the debug output window. You will get some information about what does not work.
You are correct, in your case you need a converter. The data binding alone will not be able to assign a bool to a dependency property of type Visibility.
Here is a very simple version of such convertor:
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool booleanValue = (value as bool?).GetValueOrDefault();
return booleanValue ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
You will have to also add somewhere in XAML a static reference that makes this convertor available. Maybe in App.xaml something like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:<replace_with_your_namespace>;assembly=<replace_with_your_assembly>">
...
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
...
</ResourceDictionary>
In your case the visibility will have to be set like this:
Visibility="{Binding Source={StaticResource serviceLocator}, Path=NetworkManager.NetworkViewModel.IsGenericProfileLoaded, Converter={StaticResource BoolToVisibilityConverter}}"
You will soon see that you need more flexibility from the convertor. You will want to convert a true to Visibility.Collapsed and a false to Visibility.Visible. Here is how such a more flexible convertor would be used in XAML:
Visibility="{Binding IsLocked, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=not}"
And here is how the convertor method would have to be rewritten:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool booleanValue = (value as bool?).GetValueOrDefault();
if (parameter != null)
{
if (parameter.ToString().Equals("not", StringComparison.OrdinalIgnoreCase))
{
booleanValue = !booleanValue;
}
else
{
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Invalid value for the BoolToVisibilityConverter parameter: '{0}'. The only valid values are null or 'not' (case insensitive)", parameter));
}
}
return booleanValue ? Visibility.Visible : Visibility.Collapsed;
}
I have a main program window with a row of shortcut buttons along the bottom. I'm trying to make the Visibility of these selectable through a separate Settings window using CheckBoxes, and then store that state in the UserSettings of the program so when it's opened again the previous setting will be remembered. I've found and used an IValueConverter to implement this, and I know the Setting is saved as the CheckBox itself retains it's value.
The problem is that clicking the CheckBox does not affect the Visibility of the button. It works within the Settings window itself, but I can't seem to figure out how to make it work between different windows.
I have tried implementing both the UpdateSourceTrigger & NotifyOnSourceUpdated flags to no avail. Can anybody see the problem?
Main Window XAML
<WrapPanel.Resources>
<main:BooleanToHiddenVisibility x:Key="boolToVis" />
</WrapPanel.Resources>
<ToggleButton Name="alwaysOnTop" Checked="alwaysOnTop_Checked"
Style="{StaticResource ShortcutToggleStyle}" Unchecked="alwaysOnTop_Unchecked"
Visibility="{Binding Source=main:Properties.Settings.Default, Path=pinShow, Converter={StaticResource boolToVis}, Mode=TwoWay}" >
<Image SnapsToDevicePixels="True" Source="Images/pushpin.png"
ToolTip="Always on Top" />
</ToggleButton>
Settings Window XAML
<CheckBox Name="pinDisable" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Center"
IsChecked="{Binding Source={x:Static main:Properties.Settings.Default}, Path=pinShow, Mode=TwoWay}"
Checked="pinDisable_Checked" Unchecked="pinDisable_Unchecked"/>
Convertere Code-Behind
public class BooleanToHiddenVisibility : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility rv = Visibility.Visible;
try
{
var x = bool.Parse(value.ToString());
if (x)
{
rv = Visibility.Visible;
}
else
{
rv = Visibility.Collapsed;
}
}
catch (Exception)
{
}
return rv;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}
Just wondering if it is possible to show a WPF on a disabled item ONLY (and not when the item is enabled).
I would like to give the user a tooltip explaining why an item is currently disabled.
I have an IValueConverter to invert the boolean IsEnabled property binding. But it doesn't seem to work in this situation. The ToolTip is show both when the item is enabled and disabled.
So is is possible to bind a ToolTip.IsEnabled property exclusively to an item's own !IsEnabled?
Pretty straightforward question I guess, but code example here anyway:
public class BoolToOppositeBoolConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (targetType != typeof(bool))
throw new InvalidOperationException("The target must be a boolean");
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (targetType != typeof(bool))
throw new InvalidOperationException("The target must be a boolean");
return !(bool)value;
}
#endregion
}
And the binding:
<TabItem Header="Tab 2" Name="tabItem2" ToolTip="Not enabled in this situation." ToolTipService.ShowOnDisabled="True" ToolTipService.IsEnabled="{Binding Path=IsEnabled, ElementName=tabItem2, Converter={StaticResource oppositeConverter}}">
<Label Content="Item content goes here" />
</TabItem>
Thanks folks.
JustABill's suggestion worked. I also needed to define the string as a resource to avoid problems with quotation marks. And you still need to set ToolTipService.ShowOnDisabled="True".
So, here is the working code which shows how to display a tooltip in WPF only when an item is disabled.
In the top container, include the system namespace (see sys below). I also have a Resources namespace, which I called "Res".
<Window x:Class="MyProjectName.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:Res="clr-namespace:MyProjectName.Resources"
>
Then you need
<Window.Resources>
<Res:FalseToStringConverter x:Key="falseToStringConv" />
<sys:String x:Key="stringToShowInTooltip">This item is disabled because...</sys:String>
</Window.Resources>
In my case, it was a tab item that I was interested in. It could be any UI element though...
<TabItem Name="tabItem2" ToolTipService.ShowOnDisabled="True" ToolTip="{Binding Path=IsEnabled, ElementName=tabItem2, Converter={StaticResource falseToStringConv}, ConverterParameter={StaticResource stringToShowInTooltip}}">
<Label Content="A label in the tab" />
</TabItem>
And the converter in code behind (or wherever you want to put it). Note, mine went into the a namespace called Resources, which was declared earlier.
public class FalseToStringConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool && parameter is string)
{
if ((bool)value == false)
return parameter.ToString();
else return null;
}
else
throw new InvalidOperationException("The value must be a boolean and parameter must be a string");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
A little out of date, but I got this working by setting RelativeSource mode to Self instead of setting the ElementName within the Binding.
<TabItem Header="Tab 2" Name="tabItem2" ToolTip="Not enabled in this situation." ToolTipService.ShowOnDisabled="True" ToolTipService.IsEnabled="{Binding Path=IsEnabled, RelativeSource={RelativeSource Mode=Self}, Converter={StaticResource oppositeConverter}}">
<Label Content="Item content goes here" />
</TabItem>