Setting Visibility using MVVM pattern in silverlight - silverlight

I take one grid in silverlight. Initially textbox2 is invisible. When I click on textbox1 we have to visible textbox2. I try it as belows:
<TextBox x:Name="textbox1" SelectionChanged="txt1_SelectionChanged"/>
<TextBox x:Name="textbox2 " Visibility="Collapsed"/>
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
textbox2 .Visibility = Visibility.Visible;
}
It works fine.
But I want to use MVVM pattern. So there I don't want to use eventHandler.
So how to do that using MVVM pattern?

edit: sorry, i thought you meant the textbox to be visible when the other one has focus, I changed my inital answer.
I can not try it at the moment, but you bind the Visibility property of your textbox to the SelectionLength property of the other, using a valueconverter:
<UserControl.Resources>
<local:IntToVisibilityConverter x:Key="IntToVisibilityConverter" />
</UserControl.Resources>
<Textbox
x:name="textbox2"
Visibility={Binding SelectionLength,
ElementName="textbox1"
Converter={StaticResource IntToVisibilityConverter}}
/>
implement the value converter like this:
public class IntToVisibilityConverter : IValueConverter
{
public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture)
{
return (int)value > 0 ? Visibility.Visible : Visibility.Hidden;
}
public Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture)
{
throw new InvalidOperationException("Converter cannot convert back.");
}
}

Create a property in viewmodel
public bool IsVisible
{
get
{
return _isVisible;
}
set
{
if (_isVisible == value)
{
return;
}
_isVisible = value;
RaisePropertyChanged("IsVisible");
}
}
This returns a boolean value so u need a converter BoolToVisibility Converter make BoolToVisibilityConverter class
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter == null)
{
return ((bool)value == true) ? Visibility.Visible : Visibility.Collapsed;
}
else if (parameter.ToString() == "Inverse")
{
return ((bool)value == true) ? Visibility.Collapsed : Visibility.Visible;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
Now Bind the TextBox and use the converter
<UserControl.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</UserControl.Resources>
<Textbox x:name="textbox2" Visibility={Binding IsVisible,
Converter={StaticResource BoolToVisibilityConverter}}/>
This is it.

The biggest problem you will have is getting the SelectionChanged event sent to the ViewModel. Commands in SL4 only work on button clicks, so TextBox SelectionChanged events can't fire commands by default.
There are a few solutions out there for you:
Binding Commands to ANY event
EventToCommand Behavior
Once you have done that, you can have a command in your ViewModel that sets a Visibility property in your ViewModel and fires the PropertyChanged event.
Using my ViewModelSupport library, the VM would look like this:
public class MyViewModel : ViewModelBase
{
public Visibility ShowTextbox2
{
get { return Get(() => ShowTextbox2, Visibility.Collapsed); }
set { Set(() => ShowTextbox2, value); }
}
public void Execute_SelectionChanged()
{
ShowTextbox2 = Visibility.Visible;
}
}
}
You would then bind the SelectionChanged event to the SelectionChanged command in the VM and the Textbox2 visibility attribute to the ShowTextbox2 property in the VM.
Good luck.

If you are using MVVM Light, you can also do it like this:
using System.Windows; //place it at the top of your view model class.
private Visibility _isVisible = Visibility.Collapsed;
public Visibility IsVisible
{
get
{ return _isVisible; }
set
{
if (_isVisible == value) { return; }
RaisePropertyChanging(() => IsVisible);
_passwordMissing = value;
RaisePropertyChanged(() => IsVisible);
}
}

Related

How to change the font color of a datatemplated wpf listbox using a converter?

I have a DataTemplate that is used by a listbox:
<local:BooleanToFontColorConverter x:Key="boolToFontColor" />
<DataTemplate x:Key="ListBox_DataTemplateSpeakStatus">
<Label Width="Auto">
<TextBlock Name="MY_TextBlock" Text="Hello!" Foreground="{Binding Path=MY_COLOR, Converter={StaticResource boolToFontColor}}" />
</Label>
</DataTemplate>
MY_COLOR is the following bit of code:
public class Packet_Class : INotifyPropertyChanged
{
private bool _my_color = false;
public bool MY_COLOR { get { return _my_color; }
set { _my_color = value; RaisePropertyChanged("MY_COLOR"); } }
}
and then when appropriate I set the property, which I think would fire the RaisePropertyChanged function
myPacketClass.MY_COLOR = true;
while boolToFontColor is "trying" to use this bit:
public class BooleanToFontColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
if (value is Boolean)
{
return ((bool)value) ? new SolidColorBrush(Colors.Red) : new SolidColorBrush(Colors.Black);
}
return new SolidColorBrush(Colors.Black);
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}
When I change the value of MY_COLOR from true to false, or vice versa, I see no visible changes in my text foreground color during runtime. Is anyone able to give advice as to where I am going wrong? Much appreciated and thank you in advance.
EDIT:
Some additional information to attempt to provide more clarity. I am using my DataTemplate in a ListBox like this:
<ListBox x:Name="MyUserList" ItemTemplate="{StaticResource ListBox_DataTemplateSpeakStatus}" SelectionMode="Extended" />
And in my WPF Window element I set my local namespace to the namespace that my mainwindow.xaml.cs is encapsulated in:
xmlns:local ="clr-namespace:My_NameSpace"
the RaisePropertyChanged method should raise the PropertyChanged event define in the interface and look like:
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged (string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
the converter:
public class BooleanToFontColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
if (value is Boolean)
{
return ((bool)value) ? new SolidColorBrush(Colors.Red) : new SolidColorBrush(Colors.Black);
}
return new SolidColorBrush(Colors.Black);
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}
You have to use a SolidColorBrush to make it work.
It works on my environment, let me know if you encounter any trouble.

PropertyChanged event not changing UI for binding using converter

I have below xaml for "canvas"...i want to change its visibility depends on property change.
XAML:
<d1:BooleanToVisibilityConverter x:Key="BoolToVis" />
Visibility="{Binding Path=IsVisible, Converter={StaticResource BoolToVis}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
I have this Visibility property in ViewModel
private bool _isVisible;
public bool IsVisible
{
get { return _isVisible; }
set
{
_isVisible = value;
RaisePropertyChanged("IsVisible");
}
}
This is my Converter code:
class BooleanToVisibilityConverter : IValueConverter
{
public BooleanToVisibilityConverter() { }
#endregion
#region Properties
public bool Collapse { get; set; }
#endregion
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool bValue = (bool)value;
if (bValue)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
//if (Collapse)
// return Visibility.Collapsed;
//else
// return Visibility.Hidden;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//Visibility visibility = (Visibility)value;
//if (visibility == Visibility.Visible)
// return true;
//else
// return false;
return value;
}
#endregion
}
While debugging I observed my Setter is changing the property value but its not hitting break point on my converter. Converter is getting hit only initially while loading window. After that it doesnt get triggered even though property is changed.
I read that you are using Prism so try to change your RaisePropertyChanged in this form:
RaisePropertyChanged(() => IsVisible);

How can you get a XAML TextBlock in WP7 Silverlight to collapse when it contains no data?

I have a textblock inside a list view that I need to hide or collapse when it is empty or null. I tried using a string converter but that does not do it.
Any other ideas?
Update # 1:
Here is the code inside the textblock:
Visibility="{Binding Converter={StaticResource StringConverter}}
Here is the converter:
public class StringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
return string.IsNullOrEmpty(value.ToString()) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
I would recommend creating text and visibility bindings on your textbox.
Here's an example of the view model properties you'd have.
public String TextBoxText
{
get { return textBoxText; }
set
{
if (value != textBoxText)
{
textBoxText= value;
SetTextBoxVisibility();
OnPropertyChanged("TextBoxText");
}
}
}
private String textBoxText;
public Visibility TextBoxVisibility
{
get { return textBoxVisibility; }
set
{
if (value != textBoxVisibility)
{
textBoxVisibility= value;
OnPropertyChanged("TextBoxVisibility");
}
}
}
private Visibility textBoxVisibility;
public void SetTextBoxVisibility()
{
this.TextBoxVisibility = String.IsNullOrEmpty(this.TextBoxText) ? Visibility.Collapsed : Visibility.Visible;
}
The only thing you've not shown of your code is where you instantiate the converter class. Is this because you're not doing so?
Typically you'd add something like this to app.xaml:
<Application.Resources>
<ResourceDictionary>
<conv:StringConverter x:Key="StringConverter " />
</ResourceDictionary>
</Application.Resources>

WPF Converters for radio buttons not working

I have two radiobuttons which are bound to the same property .There are 2 converters for the radio buttons. But the conversion for the 2 nd checkbox only happens the 1st time . Is there something wrong in the code.
<RadioButton Margin="5,1" GroupName="groupValueOrTime" Name="radioButtonTimeDriven" VerticalAlignment="Top" IsChecked="{Binding Path=TriggerType ,Converter={StaticResource dailyTriggerConverter}}" Grid.Column="0" Grid.Row="0" >Time Driven</RadioButton>
<RadioButton Margin="5,1" GroupName="groupValueOrTime" Name="radioButtonValueDriven" VerticalAlignment="Top" Grid.Column="0" Grid.Row="1" IsChecked="{Binding Path=TriggerType,Converter={StaticResource valueDrivenTriggerConverter}}" >Value Driven</RadioButton>
Code:
public class TriggerTypeDailyToBoolProperty:IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//convert from TriggerType to bool:
int TriggerType=int.Parse(value.ToString());
if (TriggerType == 0 || TriggerType == 1 || TriggerType == 2 || TriggerType == 3 || TriggerType == 4 || TriggerType == 5 || TriggerType == 6)
return true;
else
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool isChecked = (bool)value;
return (isChecked? 0: -1);
}
#endregion
}
public class TriggerTypeValueDrivenToBoolProperty : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//convert from TriggerType to bool:
int TriggerType = int.Parse(value.ToString());
if (TriggerType == 9)
return true;
else
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool isChecked = (bool)value;
return (isChecked ? 9 : -1);
}
#endregion
}
Combining grouping, radio buttons, and binding doesn't work. An odd feature of binding is that if you set the value of a bound target property in code, it disables the binding. The assumption that the design of binding appears to be making is that the only ways you should change a target property is by using the UI or by changing the source property it's bound to, and if a piece of code explicitly sets the value of a bound target property, it knows what it's doing.
Unfortunately, this means that grouped radio buttons, which set each others' values in code when they're changed, break their bindings when the user clicks on them. Oops.
The solution's simple: bind the radio buttons to properties in your view model, eliminate the grouping, and put logic in the view model to handle the mutually-exclusive nature of the bound properties, e.g.:
private bool _Option1;
public bool Option1
{
get { return _Option1; }
set
{
if (value != _Option1)
{
_Option1 = value;
if (value)
{
Option2 = false;
Option3 = false;
}
}
OnPropertyChanged("Option1");
}
}
I think you will require to have two different boolean properties in your view model.
Please refer below example depicting viewmodel.
public class TriggerViewModel : INotifyPropertyChanged
{
private bool _triggerTypeValue;
private bool _triggerTypeTime;
public bool TriggerTypeValue
{
get
{
return _triggerTypeValue;
}
set
{
_triggerTypeValue = value;
OnPropertychanged("TriggerTypeValue");
SetTriggerTypeTime(!_triggerTypeValue);
}
}
public bool TriggerTypeTime
{
get
{
return _triggerTypeTime;
}
set
{
_triggerTypeTime = value;
OnPropertychanged("TriggerTypeTime");
SetTriggerTypeValue(!_triggerTypeTime);
}
}
public TriggerViewModel()
{
_triggerTypeValue = false;
_triggerTypeTime = true;
}
private void SetTriggerTypeTime(bool value)
{
_triggerTypeTime = value;
OnPropertychanged("TriggerTypeTime");
}
private void SetTriggerTypeValue(bool value)
{
_triggerTypeValue = value;
OnPropertychanged("TriggerTypeValue");
}
private void OnPropertychanged(string propertyName)
{
if(PropertyChanged!= null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
For XAML
<RadioButton Margin="5,1" GroupName="groupValueOrTime" Name="radioButtonTimeDriven"
VerticalAlignment="Top" IsChecked="{Binding Path=TriggerType}"
Grid.Column="0" Grid.Row="0">
Time Driven
</RadioButton>
<RadioButton Margin="5,1" GroupName="groupValueOrTime" Name="radioButtonValueDriven"
VerticalAlignment="Top" Grid.Column="0" Grid.Row="1"
IsChecked="{Binding Path=TriggerType}">
Value Driven
<RadioButton>
Note: This approach removes Converters and allow you to keep your business logic in central view model.

WPF/XAML - hide image if another control's text property is empty/not set

i'm new to wpf and this is my first attempt of creating a custom user control. its purpose is to display two values (myText1 and myText2) with their corresponding images (myimage1, myimage2). sometimes, one of these values is not set and therefore oneimage should be hidden as well. here's my code so far:
Window1.xaml
<local:myControl myText2="Hello World!" />
myControl.xaml
<TextBlock Text="{Binding ElementName=myControl,Path=myText1}" />
<Image Source="myimage1.jpg" />
<TextBlock Text="{Binding ElementName=myControl,Path=myText2}" />
<Image Source="myimage2.jpg" />
myText1 was not set in window1.xaml and therefore the textblock remains empty. but the image is still displayed. which lines of code am i missing to hide the image if myText1 (or myText2) was not set in window1.xaml?
You have write converter for text to visibility
public class TextToVisibilityConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string && targetType == typeof(bool))
{
if (value.ToString().Equals(string.Empty))
return Visibility.Hidden;
else
return Visibility.Hidden;
}
else
{
return null;
}
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is Visibility && targetType == typeof(string))
{
if ((Visibility)value == Visibility.Visible)
{
return "Text";
}
else
{
return string.Empty;
}
}
else
{
return null;
}
}
}
And in XAML < TextToVisibilityConverter x:Key="myCnverter"/>
Couple of small mistakes there:
if (value is string && targetType == typeof(bool))
{
if (value.ToString().Equals(string.Empty))
return Visibility.Hidden;
else
return Visibility.Hidden;
}
Should be
if (value is string && targetType == typeof(Visibility))
{
if (value.ToString().Equals(string.Empty))
return Visibility.Hidden;
else
return Visibility.Visible;
}
You need the following usings:
using System.Windows;
using System.Windows.Data;
You may also consider returning Visibility.Collapsed rather than Visibility.Hidden
Once you create the right converter then is easy.
And not much answers also got that Text.IsEmpty is available for TextBlock Text property
I created a BooleanVisibilityConverter that depends on a parameter the boolean against True or False.
Gives you the !True flexibility that is missing on xaml.
public class BooleanVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility v = Visibility.Collapsed;
bool checkValue = true;
if(parameter != null)
{
checkValue = Boolean.Parse(parameter.ToString());
}
if(value.Equals(checkValue))
{
v = Visibility.Visible;
}
return v;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then in your xaml import that namespace into:
xmlns:conv="clr-namespace:ConvertersNamespace"
Create the converter into the Resources:
<UserControl.Resources>
<conv:BooleanVisibilityConverter x:Key="bool2vis" />
</UserControl.Resources>
Then just use into your design:
<TextBlock Text="{Binding ElementName=myControl,Path=myText1}" x:Name="txtBlock"/>
<Image Source="myimage1.jpg"
Visibility="{Binding ElementName=txtBlock,Path=Text.IsEmpty,
Converter={StaticResource bool2vis},ConverterParameter=False}"/>

Resources