So I'm trying to build out a project that will allow a user to type some text into a textbox on the left side of the form and that will filter out the available items from my datasource list.
<Label Content="Enter item name below"></Label>
<TextBox Name="SearchTermTextBox" TabIndex="0" Text="" />
I was under the impression I could bind to the datasource the list then use a converter to filter out the items that were unlike the string.
<ListBox DataContext="{Binding Colors}">
<ListBox.ItemsSource>
<MultiBinding Converter="{StaticResource FilterTextValueConverter}" ConverterParameter="{Binding ElementName=SearchTermTextBox, Path=Text}" />
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
//etc...
</ListBox.ItemTemplate>
</ListBox>
However, you can't bind to an elementname in the converterparameter unless you use something called a dependency property.
Edit: Seeing as I've created confusion with the code above, here's the converter I'm trying to bind:
public class FilterTextValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var trackedColors = value as List<Colors>;
if (trackedColors != null)
return (trackedColors).Where(item => item.ColorName.Contains(parameter.ToString())).ToList();
return null;
}
public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class Colors
{
public String ColorName;
public String Description;
}
What is wrong with my approach here? Clearly I'm angering the WPF gods since this is a fairly straightforward operation but I'm being denied it on principle. Any help would be appreciated.
Simple binding with converter will work here, no need for MultiBinding.
<ListBox ItemsSource="{Binding Path=Text, ElementName=SearchTermTextBox,
Converter="{StaticResource FilterTextValueConverter}">
......
</ListBox>
Assuming FilterTextValueConverter is implementing IValueConverter, you can access text from value passed to Convert method.
public class FilterTextValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
string text = value.ToString(); // TEXT for textBox can be accessed here.
return new List<string>(); // Return filtered list from here.
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
}
UPDATE
In case you want to pass multiple bindings to converter, use IMultiValueConverter because ConverterParameter is not Dependency property, hence cannot be bound.
XAML
<ListBox DataContext="{Binding Colors}">
<ListBox.ItemsSource>
<MultiBinding Converter="{StaticResource FilterTextValueConverter}">
<Binding/>
<Binding ElementName="SearchTermTextBox" Path="Text"/>
</MultiBinding>
</ListBox.ItemsSource>
</ListBox>
Converter
public class FilterTextValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
var trackedColors = values[0] as List<Colors>;
if (trackedColors != null && !String.IsNullOrEmpty(values[1].ToString()))
return (trackedColors).Where(item =>
item.ColorName.Contains(values[1].ToString())).ToList();
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I continued looking into this issue well after the accepted answer was posted and working for me. What I discovered is that it's a fairly trivial task to wrap the control you're trying to get a new dependencyproperty out of to allow for proper binding.
I will not be accepting my own answer to this determined so much later, but this seems (in my amateur opinion) like a much more elegant solution than adding a converter despite being a bit more complex:
Note that this is for a new dependency on the caretindex property of a textbox, not for the original question on binding, but it just requires some smart renaming to get it working ;).
public class TextBoxDependencyWrapper : TextBox
{
public static readonly DependencyProperty CaretIndexProperty = DependencyProperty.Register(
"CaretIndex", typeof (int), typeof (TextBoxDependencyWrapper), new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, CaretIndexChanged ));
protected override void OnKeyUp(KeyEventArgs e) //Event that changes the property we're trying to track
{
base.OnKeyUp(e);
CaretIndex = base.CaretIndex;
}
protected override void OnKeyDown(KeyEventArgs e) //Event that changes the property we're trying to track
{
base.OnKeyDown(e);
CaretIndex = base.CaretIndex;
}
public new int CaretIndex
{
get { return (int) GetValue(CaretIndexProperty); }
set { SetValue(CaretIndexProperty, value); }
}
}
Related
I’m trying to learn XAML (without much success) – be gentle.
I have a toggle button, a slider and a button. This is what I am trying to do:
When the slider’s value is changed the toggle button should turn off – works fine.
When the button is pressed, set the slider value and keep the toggle button in whichever state it is – does not work; after I push the button, (1) does not work anymore. It behaves like the IsChecked binding was cleared.
Ideally I would like to write everything in XAML, but I guess it is not possible.
// MainWindow.xaml.cs
public class ValueToFalse : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var saved = toggle.IsChecked;
slider.Value = 2;
toggle.IsChecked = saved;
}
}
<!--App.xaml-->
<local:ValueToFalse x:Key="ValueToFalse"/>
<!--MainWindow.xaml-->
<ToggleButton
Name="toggle"
Content="toggle"
HorizontalAlignment="Left"
Margin="479,64,0,0"
VerticalAlignment="Top"
Height="108"
Width="192"
IsChecked="{Binding Value, Mode=OneWay, ElementName=slider, Converter={StaticResource ValueToFalse} }"
/>
<Slider
Name="slider"
HorizontalAlignment="Left"
Margin="167,105,0,0"
VerticalAlignment="Top"
Width="233"
Height="35"
/>
<Button
Content="Button"
HorizontalAlignment="Left"
Margin="346,340,0,0"
VerticalAlignment="Top"
Click="Button_Click"
/>
I didn't quite understand what you want to implement.
But nevertheless, you have an obvious mistake that #Clemens pointed out - if you need to assign a Dependency Property value and keep the binding from it, then the binding must be in the direction of the TwoWay or OneWaySource source.
Since you do not need to assign a value to the source, but you need to store the direction to the source in the binding, you can solve this by implementing a converter.
I show the full implementation of the converter with markup extension. This may be useful to you in the future.
[ValueConversion(typeof(object), typeof(bool))]
public class ValueToFalseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// This value tells the binding that the result of the conversion should not be assigned.
return Binding.DoNothing;
}
private ValueToFalseConverter() { }
public static ValueToFalseConverter Instance { get; } = new ValueToFalseConverter();
}
[MarkupExtensionReturnType(typeof(ValueToFalseConverter))]
public class ValueToFalseExtension : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return ValueToFalseConverter.Instance ;
}
}
<ToggleButton
----------
----------
IsChecked="{Binding Value,
Mode=TwoWay,
ElementName=slider,
Converter={local:ValueToFalse}}"
/>
I make a button and Color picker to xamarin.forms app, but I want to make it when I choose one color (ex. red) and close app, when i reopen it to see this red color automatic picked. I try to use this code but Preferences not working with Color:
public Color ColorPicker
{
get => Preferences.Get(nameof(ColorPicker), color.Red);
set
{
Preferences.Set(nameof(ColorPicker), value);
OnPropertyChanged(nameof(ColorPicker));
}
}
Can someone help me?
You can store Xamarin.Forms.Color as a string like this:
public string ColorPicker
{
get => Preferences.Get(nameof(ColorPicker), Color.Red.ToString());
set
{
Preferences.Set(nameof(ColorPicker), value);
OnPropertyChanged(nameof(ColorPicker));
}
}
Then you can bind it for instance to Label like this:
<Label TextColor="{Binding ColorPicker}" />
Make sure you set BindingContext in your view. You can read more about Binding here.
The Color.FromHex(string value) method needs a string type parameter. Try to convert the value to string type in the custom class.
Check the code:
Custom Converter class
public class StringToColorConverter : IValueConverter, INotifyPropertyChanged
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var color = Color.FromHex(value as string);
return color;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Page.xaml
<ContentPage.Resources>
<local:StringToColorConverter x:Key="myConverter" />
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout BackgroundColor="{Binding Color_string, Converter={StaticResource myConverter}}">
...
</StackLayout>
</ContentPage.Content>
I is not possible to make it like this. Because i need to use converter after to make string=>color. I am trying this:
public class StringToColor : IValueConverter
{
ColorTypeConverter converter = new ColorTypeConverter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//return value.ToString(); //not working
//return (Color)(converter.ConvertFromInvariantString(value.ToString())); //not working
return Color.FromHex(value.ToString()); //not working too
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
and add this convetor to xaml
<ContentPage.Resources>
<ResourceDictionary>
<local:StringToColor x:Key="str" />
</ResourceDictionary>
</ContentPage.Resources>
<Label Text="TEST" FontSize="Title" TextColor="{Binding ColorPicker,
Converter={StaticResource str}}"/>
but nothing happend...
This question already has answers here:
WPF Binding a ListBox to an enum, displaying the Description Attribute
(6 answers)
Closed 7 years ago.
I'm using caliburn micro framework in a WPF application.
I need to bind this enum to a combobox.
Consider following enum in a ViewModel:
public enum MovieType
{
[Description("Action Movie")]
Action,
[Description("Horror Movie")]
Horror
}
How can I bind this enum to a combobox?
Is it possible to show the enum description insted of enum values in
combobox?
Can I implement IvalueConverter for this purpose?
In the resources of your Window/UserControl/? you have to create an ObjectDataProvider like:
<ObjectDataProvider x:Key="MovieDataProvider" MethodName="GetValues" ObjectType="{x:Type namespace:MovieType}">
<ObjectDataProvider.MethodParameters>
<x:Type Type="namespace:MovieType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
To use it as itemssource of your ComboBox you have to do the following:
ItemsSource="{Binding Source={StaticResource MovieDataProvider}}"
If you want to display a custom value you can modify the ItemTemplate of your ComboBox like:
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={converters:MovieDisplayConverter}}"/>
</DataTemplate>
</ComboBox>
The MovieDisplayConverter can look like the following if you want to return custom values:
internal class MovieDisplayConverter : MarkupExtension, IValueConverter
{
private static MovieDisplayConverter converter;
public MovieDisplayConverter()
{
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is MovieType)
{
switch ((MovieType)value)
{
case MovieType.Action:
return "Action Movie";
case MovieType.Horror:
return "Horror Movie";
default:
throw new ArgumentOutOfRangeException("value", value, null);
}
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return converter ?? (converter = new MovieDisplayConverter());
}
}
If you want the description-attribute of your enum-values in the ComboBox replace the convert-method of the above converter with the following:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is MovieType)
{
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
if (fieldInfo != null)
{
object[] attributes = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), true);
if (attributes.Length > 0)
{
return ((DescriptionAttribute)attributes[0]).Description;
}
}
}
return value;
}
I am working on a windows universal app and I'm trying to work out data binding.
I have a listview which has an item template and data template in which a property of a custom class is bound.
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<Textblock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This works fine an displays the names all instances of my custom class in the ObservableCollection I bind to the listview. I was wondering however if there is some way of modifying what is being bound before it is bound without changing the class itself.
I'm trying to bind a capitalisation of the string property Name so if the name was Test I want to bind TEST instead. Currently the way I'm doing this is to have a separate property called NameLabel which I populate like this
NameLabel = Name.ToUpper();
However this seems very messy and I was wondering if there's a neater way of doing it without creating a separate property?
You can use a Converter.
Create a StringToUpper.cs File with a StringToUpper Class which inherits form IValueConverter:
public class StringToUpper: IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var valueString = value.ToString();
if (!string.IsNullOrEmpty(valueString))
{
return valueString.ToUpper();
}
return string.Empty;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// do nothing.
}
}
Add the resource of your created Converter:
...
xmlns:converter="clr-namespace:StringToUpper"
...>
<Window.Resources>
<converter:StringToUpper x:Key="StringToUpperConverter" />
</Window.Resources>
Add the converter:
<Textblock Text="{Binding Name, Converter={StaticResource StringToUpperConverter}}"/>
Here is a good Tutorial about Converters in WPF.
You could create a converter, that turns the value of a property into a form desired for the view (in your case, a simple capitalisation of the string).
Your converter class might look like this:
public class StringToUpperStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var valueString = value.ToString();
if (!string.IsNullOrEmpty(valueString))
{
return valueString.ToUpper();
}
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Your xaml might have this defined in the resource section:
<converters:StringToUpperStringConverter x:Key="StringToUpperStringConverter" />
And your binding would then look like this:
<Textblock Text="{Binding Name, Converter={StaticResource StringToUpperStringConverter}}"/>
I need to calculate/change form of input between textbox to its bindable source. The way i trying to achive this, is with help of converters.
Converter:
public class ParameterConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return string.Empty;
string originalParameValue = value.ToString();
string fixedParameterValue = string.Format("#_{0}", originalParameValue);
return fixedParameterValue;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
XAML:
<Window.Resources>
<converters:ParameterConverter x:Key="parameterConverter" />
</Window.Resources>
<Grid>
<TextBox Text="{Binding ParameterA, Converter={StaticResource parameterConverter}}"/>
</Grid>
The problem is, that converter is functioning only once. Is it approach correct (i mean with converter) or there are another approaches ?
Perhaps the binding Mode is not two way, and did your property fire property changed.
Does your data context implement INotifyPropertyChanged and is PropertyChanged being called whenever ParameterA is changed? It seems as if nobody is notifying the textbox that it needs to update its contents.