Condition in XAML to change component - c#

I've a combobox, which allows me to select a type. When I select a type, i'm able to fill a component. But I'd like that my component corresponding to my type. So, if it's a date, i'd like to display a datepicker, and if it's a string, i'd like to display a textbox.
How can I do that ?
I don't want to change things around DataTemplate, because this row is a part of a datagrid :)
<DataGridTemplateColumn Header="SQLValue" Width="0.55*" CanUserResize="False" CanUserReorder="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!-- HERE ! HOW CAN I CHOOSE ONE BY A CONDITION ? -->
<DatePicker/>
<TextBox Text="{Binding SqlValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

The idea here is: you should a property in data context call DispType (int)
Then in each control you binding Visibility with above property, include a Converter convert number to Visible or not, Converter have parameter is number.
You can see my eg:
<Grid>
<Button Visibility="{Binding DispType, Converter={StaticResource VisibilityTypeConverter}, ConverterParameter=1}"/>
<TextBox Visibility="{Binding DispType, Converter={StaticResource VisibilityTypeConverter}, ConverterParameter=2}"/>
<DatePickerTextBox Visibility="{Binding DispType, Converter={StaticResource VisibilityTypeConverter}, ConverterParameter=3}"/>
</Grid>
You see the hard code for ConverterParameter.
And Converter class
public class VisibilityTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int actualType = parameter == null ? 0 : System.Convert.ToInt32(parameter);
int compareType = value == null ? 0 : System.Convert.ToInt32(value);
if (actualType == compareType)
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Please not that code is only demo, you should change code to meet your expectation.

Related

Allow NULL in a WPF Extended Toolkit DecimalUpDown control

I have a property on my view model of type decimal?. NULL should be a valid value for this property, but when I erase the text from the DecimalUpDown control, a validation error occurs and the property is not given the value NULL (whatever it was previously remains).
The control is declared in xaml like:
<xctk:DecimalUpDown ValueChanged="UpDownBase_OnValueChanged" Text="{Binding ServiceSize}" Minimum="0" Grid.Column="4" Grid.Row="2" Margin="5" IsEnabled="{Binding IsEditable}"/>
It will bind correctly if I enter a number
But as soon as the number is erased a validation error occurs, and the value can't be set back to NULL (in this case the model still has "5" as the value for "ServiceSize").
Validation.GetHasError() returns true for this control. Can I remove the Validation Rules entirely somehow?
You can implement an IValueConverter to handle empty input.
public class DecimalUpDownValueConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
// handle input on a case-to-case basis
if(value == null)
{
// Do something
return 0;
}
else
{
return value;
}
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// Do the conversion from model property to DecimalUpDownValue
return value;
}
}
On your view: (Assuming you added the DecimalUpDownValueConverter as a static resource)
<xctk:DecimalUpDown ValueChanged="UpDownBase_OnValueChanged" Text="{Binding ServiceSize, Converter = { StaticResource DecimalUpDownValueConverter }}" Minimum="0" Grid.Column="4" Grid.Row="2" Margin="5" IsEnabled="{Binding IsEditable}"/>

Converter Parameter In ItemTemplate

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?

Expressions in Databinding... possible? How to?

I have a collection databound to a ListBox. What I would like to do is show some UI based on whether or not some property of the member of the collection exists.
E.g.:
public class Widget
{
public string foo;
public string bar;
}
public ObservableCollection<Widget> Stuff;
XAML:
<ListBox ItemsSource="{Binding Stuff}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding foo}"
Visiblity="{Binding
(foo != null ? Visibility.Visible : Visibility.Collapsed)
}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note the Visibility attribute on the TextBlock. Clearly this isn't supported, but it should give you an idea of what I want to do.
One possible solution is that I could add a property to widget that looks like this:
public Visibility has_foo;
And then:
... Visibility="{Binding has_foo}" ...
But it seems awkward to have to generate these additional properties.
I suspect there is a much better way. Is there? How would you do it?
Thanks.
Create a value converter. Something like
public class NullToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then add it something like
<YourUserControl.Resources>
<NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
</YourUserControl.Resources>
<ListBox ItemsSource="{Binding Stuff}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding foo}"
Visiblity="{Binding foo,
Converter={StaticResource NullToVisibilityConverter}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Obviously I've not implemented ConvertBack (not really sure if you will be able to convert back) but you shouldn't need it in this instance.

Conditional element in xaml depending on the binding content

Is it possible to display this TextBlock, only if the Address.Length > 0 ? I'd like to do this directly into the xaml, I know I could put all my controls programmatically
<TextBlock Text="{Binding Path=Address}" />
Basically, you're going to need to write an IValueConverter so that you can bind the Visibility property of your TextBox to either the Address field, or a new field that you create.
If you bind to the Address field, here's how the binding might look like::
<TextBlock Text="{Binding Path=Address}"
Visibility="{Binding Path=Address, Converter={StaticResource StringLengthVisibilityConverter}}" />
And then StringLengthVisiblityConverter could look something like this:
public class StringLengthVisiblityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || value.ToString().Length == 0)
{
return Visibility.Collapsed;
}
else
{
return Visibility.Visible;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// Don't need to implement this
}
}
Then you'd just need to add your converter as a resource, using syntax like this (where src is mapped to the namespace where the converter is defined):
<src:StringLengthVisiblityConverter x:Key="StringLengthVisiblityConverter" />
I would do this with another boolean property called HasAddress which returns Address.Length > 0.
<!-- In some resources section -->
<BooleanToVisibilityConverter x:Key="Bool2VisibilityConverter" />
<TextBlock
Text="{Binding Address}"
Visibility="{Binding HasAddress, Converter={StaticResource Bool2VisibilityConverter}}"
/>
You should also remember to notify the property change for HasAddress in the setter of Address.
You can create a StringToVisibility converter.
It will return Visibility.Visible if bound string is not null or empty and Visibility.Collapsed if it is.
Use this converter while binding Address with Visibility property of your TextBlock.
Example:
<TextBlock Text="{Binding Path=Address}" Visibility="{Binding Address, Converter={StaticResource StringToVisibilityConverter}}" />

Silverlight: Difficulty with binding to visiblity

I have two elements: a listbox and a "this list is empty" message. I'd like to bind their visibility to the list box's ItemsSource being empty. However, I'm not sure how to do this:
<TextBlock Text="No favorite searches yet. Add some by searching, then clicking 'Add to Favorites'"
Padding="10,0"
VerticalAlignment="Center"
Visibility="{Binding Path=FavoriteFilters.IsEmpty, Converter={StaticResource visibilityConverter}}"
/>
<ListBox ItemsSource="FavoriteFilters"
x:Name="favoriteFiltersList"
Visibility="{Binding Path=FavoriteFilters.IsEmpty, Converter={StaticResource visibilityConverter}}">
<ListBox.ItemTemplate>
<DataTemplate>
<my:FavoriteFilterLink />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
They are both visible, although the ItemsSource is empty. Also, I'm not sure how to invert the condition for the ListBox.
The visibility converter:
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool?)
{
if (string.IsNullOrEmpty((string)parameter))
{
return (value as bool?).Value ? Visibility.Visible : Visibility.Collapsed;
} else
{
return (value as bool?).Value ? Visibility.Collapsed : Visibility.Visible;
}
}
throw new ArgumentException();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
You might be better off writing two converters, one for the ListBox the other for the TextBlock. The logic of each would be simpler and you wouldn't need to pass a parameter to get the correct result.
While it might not be as elegant as a single converter solution it will be far more maintainable.
If you really want to pass a parameter then you need to use the ConverterParameter.
There's an example here but I'm not 100% sure it'll meet your requirements. The simplified XAML syntax is:
<TextBlock Visibility="{Binding FavoriteFilters.IsEmpty,
Converter={StaticResource visibilityConverter}, ConverterParameter=false}"/>
<ListBox Visibility="{Binding FavoriteFilters.IsEmpty,
Converter={StaticResource visibilityConverter}, ConverterParameter=true}"/>
Then in your converter (simplified):
bool show = (bool)value;
bool visible = (bool)parameter;
if (visible)
{
return show ? Visibility.Visible : Visibility.Collapsed;
}
else
{
return show ? Visibility.Collapsed : Visibility.Visible;
}

Categories

Resources