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}}"
/>
Related
I have two ImageButtons which should switch their images when clicked.
<ImageButton
Grid.Column="15"
Grid.Row="20"
Clicked="Clicked"
Source="{Binding Game[0], Converter={StaticResource StringToSourceConverter}}"
>
</ImageButton>
<ImageButton
Grid.Column="15"
Grid.Row="20"
Clicked="Clicked"
Source="{Binding Game[1], Converter={StaticResource StringToSourceConverter}}"
>
</ImageButton>
The Clicked method swaps the Sources in my Game array and activates INotifyPropertyChanged. It all works out fine. I would just like to know how to implement, that the image should only bind if the image is loaded. Because as you see in the following Images there is a short period where no image is displayed. It's short but it is annoying. The ImageSource is an EmbeddedResource.
I'm wondering if you are using Embedded images or just Local images ? Local images is recommended .
What's more , there is another way to implement this function(swap the image by clicking the button).
Add a bool property in viewmodel.
public class ViewModel : BaseViewModel
{
private bool _isOne;
public bool isOne {
get
{
return _isOne;
}
set
{
_isOne = value;
NotifyPropertyChanged();
}
}
}
Add two Converter for the two ImageButton .
public class FirstConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isOne = (bool)value;
return isOne ? "a.jpg" : "b.jpg";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return true;
}
}
public class SecondConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isOne = (bool)value;
return isOne ? "b.jpg" : "a.jpg";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return true;
}
}
Create binding on the ImageButton .
<ContentPage.Resources>
<ResourceDictionary>
<local:FirstConverter x:Key="first" />
<local:SecondConverter x:Key="second" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<ImageButton Clicked="ImageButton_Clicked" Source="{Binding isOne, Converter={StaticResource first}}"/>
<ImageButton Clicked="ImageButton_Clicked" Source="{Binding isOne, Converter={StaticResource second}}"/>
</StackLayout>
Change the property in Button Click event.
private void ImageButton_Clicked(object sender, EventArgs e)
{
model.isOne = !model.isOne;
}
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...
I think I've followed the examples given in this post but my property is not changing when button are changed. Any suggestions on where I went wrong?
C# code for enum and class
public enum SystemTypes
{
TypeA,
TypeB
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
SystemTypes systemType = SystemTypes.TypeA;
public SystemTypes SystemType
{
get { return systemType; }
set { systemType = value; }
}
}
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;
}
}
xaml
<Canvas>
<Canvas.Resources>
<local:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
</Canvas.Resources>
<RadioButton x:Name="TypeARadioButton" Content="TypeA" Canvas.Left="10" Canvas.Top="10"
IsChecked="{Binding Path=SystemType, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SystemTypes.TypeA}}" />
<RadioButton x:Name="TypeBRadioButton" Content="TypeB" Canvas.Left="10" Canvas.Top="31"
IsChecked="{Binding Path=SystemType, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SystemTypes.TypeB}}" />
</Canvas>
You need to set Binding Mode to TwoWay, then in Converter implement method ConvertBack responsible for converting bool to SystemTypes, in settter of SystemType include
set { systemType = value; OnPropertyChanged(() => "SystemType");}
in order to fill property in that its value was changed.
OnPropertyChanged(() => "SystemType")
can work if you implement interface INotifyPropertyChanged. I cannot you whether you set DataContext, if you did not binding is not working. In order to rectify this after InitializeComponent() add
this.DataContext = this;
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); }
}
}
I am using WPF.
I want to show button when the label is not empty. When Label has a value, the button will be hidden.
How can I do this with WPF? Using <Style>?
Code:
<Label Name="lblCustomerName"/>
<Button Name="btnCustomer" Content="X" Visibility="Hidden" />
try
if (string.IsNullOrEmpty(lblCustomerName.Text)) {
btnCustomer.Visibility = Visibility.Hidden;
}
else {
btnCustomer.Visibility = Visibility.Visible;
}
You will need to use a converter and bind it to the content of lblCustomer.
public class ContentNullToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return Visibility.Hidden;
}
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
More on converters here.
Then in xaml you can do the following:
First line needs to be defined in your resources where you will need to qualify it with the namespace in which you created the class above. Once you have defined the resource you can use the second part.
<ContentNullToVisibilityConverter x:Key="visConverter"/>
<Label Name="lblCustomerName"/>
<Button Name="btnCustomer" Content="X" Visibility="{Binding ElementName=lblCustomer, Path=Content, Converter={StaticResource visConverter}}" />