I have a group of ribbon toggle buttons inside of the same container in my XAML like this:
<ribbon:RibbonGroup Header="Layouts">
<ribbon:RibbonToggleButton Label="One"
IsChecked="{Binding PaneManager.Layout,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={s:Static windows:Layouts.One}}"/>
<ribbon:RibbonToggleButton Label="Two Vertical"
IsChecked="{Binding PaneManager.Layout,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={s:Static windows:Layouts.TwoVertical}}"/>
<!-- etc. for 2 horizontal and 4 panes -->
</ribbon:RibbonGroup>
I'm using the same EnumToBooleanConverter outlined in this answer:
public class EnumToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(true) ? parameter : Binding.DoNothing;
}
}
The problem is that when a user clicks the toggle button that's already selected, the toggle button happily turns itself off--even though the bound value matches that toggle button. When tracing through the code, what happens is that the ConvertBack method is called and it returns Binding.DoNothing. Afterwards, Convert is not called to reassign the value. When ConvertBack returns a value (i.e. it is clicked a second time and IsChecked is true again), the Convert method is called to reassign the value.
If I change the return type on false to be DependencyObject.UnsetValue, the toggle button is still turned off but now it has a red outline.
How do I force WPF to re-evaluate the bound value so that the toggle button stays on?
OK, it seems I have to control whether the toggle button IsHitTestVisible to make it behave properly. If I change my toggle buttons to look like this:
<ribbon:RibbonGroup Header="Layouts">
<ribbon:RibbonToggleButton Label="One"
IsChecked="{Binding PaneManager.Layout,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={s:Static windows:Layouts.One}}"
IsHitTestVisible="{Binding IsChecked,
RelativeSource={RelativeSource Self},
Converter={StaticResource InverseBooleanConverter}}"/>
<ribbon:RibbonToggleButton Label="Two Vertical"
IsChecked="{Binding PaneManager.Layout,
Converter={StaticResource EnumToBooleanConverter},
ConverterParameter={s:Static windows:Layouts.TwoVertical}}"
IsHitTestVisible="{Binding IsChecked,
RelativeSource={RelativeSource Self},
Converter={StaticResource InverseBooleanConverter}}"/>
<!-- etc. for 2 horizontal and 4 panes -->
</ribbon:RibbonGroup>
And then supply the following converter:
public class InverseBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
}
It feels like a hack, but it does prevent toggling back off. I am seriously open to more elegant solutions.
Related
I'm trying to convert a string on a label (or anything) to another string. This is for Icon fonts.
Converter
[ValueConversion(typeof(string), typeof(string))]
public class StringToIconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string property = ((string)value).ToLower();
switch (property)
{
case "maximize": return #"\e901";
default return property;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
...
}
Then I've added it to my pages that need it
<Helpers:StringToIconConverter x:Key="Icon" />
And this is how I'm setting it
<Button Style="{StaticResource NavButton}"
Tag="Document"
Command="{Binding GotoDataMatrixEnterCommand}">
<Button.Content>
<Label Content="{Binding Source={RelativeSource Self},
Path=Tag,
Converter={StaticResource Icon},
UpdateSourceTrigger=LostFocus}"
Tag="Document" />
</Button.Content>
</Button>
And what I'm getting is
Windows.System.Control.Label in its place. Am I not converting it properly, I'm not quite sure why it is not replacing the correct information. I've tried a few things, and reading up online though I'm stuck at the moment. Plus when I try to debug it doesn't work (it never hits the breakpoints)
The problem is with the Binding on Label.Content. You should use RelativeSource, not Source.
It should be:
RelativeSource={RelativeSource Mode=Self}
Also, you have a syntactic error in the switch statement of StringToIconConverter: default return property; should be default: return property; (you're missing a colon).
I have a collection of Checkboxes in a Listbox binding to an Enum which uses a converter. Code shown below:
<ListBox HorizontalAlignment="Left" Height="183" Margin="159,30,0,0" VerticalAlignment="Top" Width="144">
<ListBox.Resources>
<local:FlagsEnumValueConverter x:Key="FlagsConverter" />
</ListBox.Resources>
<CheckBox Content="Checkbox1" IsChecked="{
Binding Path=TestModel.TestEnum,
Converter={StaticResource FlagsConverter},
ConverterParameter={x:Static tc:TestEnum.Test1}}"/>
<CheckBox Content="Checkbox2" IsChecked="{
Binding Path=TestModel.TestEnum,
Converter={StaticResource FlagsConverter},
ConverterParameter={x:Static tc:TestEnum.Test2}}"/>
<CheckBox Content="Checkbox3" IsChecked="{
Binding Path=TestModel.TestEnum,
Converter={StaticResource FlagsConverter},
ConverterParameter={x:Static tc:TestEnum.Test3}}"/>
</ListBox>
Converter Code:
class FlagsEnumValueConverter : IValueConverter
{
private int mTargetValue;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var mask = (int)parameter;
mTargetValue = (int)value;
return ((mask & mTargetValue) != 0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
mTargetValue ^= (int)parameter;
return Enum.Parse(targetType, mTargetValue.ToString());
}
}
I'd rather use an ItemTemplate to keep things clean and simple however I'm not sure what to do with the 'ConverterParameter' since it requires the specific Enum value. I've been Googling for a solution but haven't found one. I honestly don't even know where to start. Is this even possible?
I want to bind IsEnabled of Button in WPF as follows:
WPF Code:
<Button Content="TestButton" IsEnabled="{Binding ??}" />
C# code:
private MyObjectClass _Checked;
public MyObjectClass Checked
{
get { return _Checked; }
set
{
_Checked = value;
RaisePropertyChanged("Checked");
}
}
In WPF code above, I want the button to be enabled only when Checked object is not null. I know one way is to have a bool property in C# code which tells me whether the Checked object is null or not, and then bind it to IsEnabled property. I want to know if there is a way I can bind IsEnabled to Checked object directly?
Use DataTrigger and check for {x:Null} value of binding:
<Button Content="TestButton">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding Checked}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Also, you can use IValueConverter which will return false if value is null otherwise true.
public class ObjectToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
bool returnValue = true;
if (value == DependencyProperty.UnsetValue || value == null)
{
returnValue = false;
}
return returnValue;
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
return Binding.DoNothing;
}
}
and bind in XAML:
<Button Content="TestButton"
IsEnabled="{Binding Checked,
Converter={StaticResource ObjectToBoolConverter}}" />
Ofcourse you need to declare instance of converter in your XAML for this.
You can use a converter to convert an object into a bool. Look into IValueConverter.
public class IsNotNullToBoolConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException("Two-way binding not supported by IsNotNullToBoolConverter");
}
}
And your xaml would look like this:
<Window.Resources>
<local:IsNotNullToBoolConverter x:Key="IsNotNull" />
</Window.Resources>
...
<Button IsEnabled="{Binding Converter={StaticResource IsNotNull}}" />
I know this is an old issue but you can do this without an extra code. Just add the "TargetNullValue=false" to the binding.
IsEnabled="{Binding SomeProperty, TargetNullValue=false}"
I bound my text box to property (only text box) and used converter which just return opposite bool value.
XAML
<TextBox Height="23" HorizontalAlignment="Left" Margin="13,41,0,0" Text="{Binding Path=CurrentProfile.profileName}" IsEnabled="{Binding Path=CurrentProfile.isPredefined, Converter={StaticResource PredefinedToControlEnabled}}" VerticalAlignment="Top" Width="247" Grid.ColumnSpan="2" TabIndex="1" />
Converter
public class PredefinedToControlEnabled: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var isPredefined = (bool)value;
return !isPredefined;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
When the property value isPredefined is true, the IsEnabled property of TextBox is set correctly to false. When the isPredefined is false, the converter returns false and all controls on GUI sets IsEnabled property to false, what means that application is not useable anymore (it works in background naturally). Why it is happening?
How does it look like:
Found,
VS automagically add line to Window properties
IsEnabled="{Binding Path=CurrentProfile.isPredefined}"
but the question still is, how?
I have a WPF window with a Grid and a TreeView. The datacontext for the Grid is bound to the selected item on the treeview. However, because not all treeviewitems are applicable, I want to disable the grid if the treviewitem isn't applicable. So, I created a value converter to do a null check and return a bool. (Applicable items would not be null in this case)
The problem is that the value converter is never used. I set break points and they are never hit. I have other value converters I'm using and they all work just fine.
Is there something I'm missing?
<Grid Grid.Column="1" Grid.Row="0" DataContext="{Binding MyVal}" IsEnabled="{Binding MyVal, Converter={StaticResource NullCheckConverter}}" Margin="2,2,2,2">
Not that it's important for this question but here is the ValueConverter code:
internal class NullCheckValueConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return !(value == null);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
That's because you bind DataContext to the same value as you binding IsEnabled. So for IsEnabled it actually looking for MyVal.MyVal. Replace to:
IsEnabled="{Binding Converter={StaticResource NullCheckConverter}}"
Also further if you have issues with binding, check in debug mode output window for binding errors.