Why is binding to "Self" not working? - wpf

I try to bind the control's Tag property to the control's Visibility property, but I receive the following error in VS:
object reference not set to an instance of an object
The XAML is like below:
<RadioButton GroupName="NavButtonSide"
Tag="7"
Visibility="{Binding Path=Tag,
Converter={StaticResource ControlTagVisibilityConverter},
RelativeSource={RelativeSource Mode=Self}}"/>
Can anyone tell me how to solve it?

Nothing wrong with your binding. This works fine for me;
<Window.Resources>
<local:ControlTagVisibilityConverter x:Key="ControlTagVisibilityConverter" />
</Window.Resources>
<RadioButton
Tag="7"
Visibility="{Binding Path=Tag,
Converter={StaticResource ControlTagVisibilityConverter},
RelativeSource={RelativeSource Mode=Self}}"/>
ControlTagVisibilityConverter.cs
public class ControlTagVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var valueAsString = (string) value;
var valueAsInt = int.Parse(valueAsString);
switch (valueAsInt)
{
case 7:
return Visibility.Visible;
default:
return Visibility.Hidden;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Related

Is there a way to make this image binding more performant?

I am binding a list of 500 odd nicks to a list with a status image for each. The scrolling of the list is painfully slow, and so is flicking between tabs with different lists.
This is all caused by my recent change in which I added these images.
Is there a way to speed it up?
My bitmaps (very small 16*16) :
<BitmapImage x:Key="ActiveIcon" UriSource="/WPFClient;component/Images/active.png" />
<BitmapImage x:Key="IdleIcon" UriSource="/WPFClient;component/Images/idle.png" />
<BitmapImage x:Key="AwayIcon" UriSource="/WPFClient;component/Images/away.png" />
<BitmapImage x:Key="UnknownIcon" UriSource="/WPFClient;component/Images/unknown.png" />
My List :
<ListBox ItemsSource="{Binding Users}">
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<Image Source="{Binding Status, Converter={StaticResource UserStatusToIconConverter}}" Height="16" Width="16" Margin="0,0,5,0" />
<TextBlock Text="{Binding Nick}" />
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My converter :
public class UserStatusToIconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string userStatus = value.ToString();
string iconName = "UnknownIcon";
switch (userStatus)
{
case "Active":
iconName = "ActiveIcon";
break;
case "Idle":
iconName = "IdleIcon";
break;
case "Away":
iconName = "AwayIcon";
break;
}
return iconName;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
NOTE: The code also DOES NOT work as it currently stands, no image is actually displayed. However I assume thats a minor detail somewhere.
Try using VirtualizationStackPanel will give some improvements
<ListBox VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
</ListBox>
in framework 4.5 VirtualizingPanel is available and setting VirtualizingPanel.ScrollUnit="Item" will give good performance improvement
The easiest way to solve that is to change converter to:
public class UserStatusToIconConverter : IValueConverter
{
private static readonly Uri ActiveIcon = new Uri("pack://application:,,,/WPFClient;component/Images/active.png");
private static readonly Uri IdleIcon = new Uri("pack://application:,,,/WPFClient;component/Images/idle.png");
private static readonly Uri AwayIcon = new Uri("pack://application:,,,/WPFClient;component/Images/away.png");
private static readonly Uri UnknownIcon = new Uri("pack://application:,,,/WPFClient;component/Images/unknown.png");
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var userStatus = value.ToString();
switch (userStatus)
{
case "Active":
return ActiveIcon;
case "Idle":
return IdleIcon;
case "Away":
return AwayIcon;
default:
return UnknownIcon;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The slow-down is caused by improper binding.

textbox visibility/collapsed in silverlight mvvm

I Silverlight5 with mvvm pattern i have one doubt.
In xaml i have used one textblock and i bind some id in it.
If the textblock content value is 1 or 2 means
yet another textbox is visible or else that is collapsed.. how to acheive that..
my code:
<TextBlock Name="textBlock1" Text="{Binding id}" Loaded="textBlock1_Loaded" Visibility="Collapsed" />
<TextBox Text="{Binding name,Mode=TwoWay}" x:Name="t1" Visibility="{Binding IsVisible,Converter={StaticResource visibilityconverter}}" />
in view model i had created the property for id and raised the event and bind the value to textblock.
to convert the value to visible i have a visibilityconverter class in one separate folder named "Converters"
public class visibilityconverter:IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (id==1 && id==2)
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
in the above visibleconverter class how i cna get the id value from viewmodel and check it..
If i got the value from viewmodel to visibilityconverter means i will proceed further.
tell me if u can..!
Hi i have found the solution..
In xaml give the following:
<TextBox Text="{Binding name,Mode=TwoWay}" x:Name="t1" Visibility="{Binding id,Converter={StaticResource visibilityconverter}}" />
In visibilityConverter class:
public class visibilityconverter:IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
string v = value.ToString();
if (v =="1" || v=="2")
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Problem Solved... !

Binding-driven Indexed Property Doesn't Return

Public Class View
Public Property Items As String() = {"One", "Two", "Three"}
Public Property Index As Integer = 0
End Class
It's instance is set as DataContext of this XAML:
<Window>
<StackPanel>
<ListBox ItemsSource="{Binding Items}" SelectedIndex="{Binding Index}"/>
<Label Content="{Binding Items[Index]}"/>
</StackPanel>
</Window>
But this doesn't work.
<Label Content="{Binding Items[{Binding Index}]}"/>
This neither.
<Label Content="{Binding Items[0]}"/>
This works.
Is there any solution except making extra property in view? Something directly in XAML?
I'm afraid it's not possible without some code-behind, but using reflection and dynamic, you can create a converter that can do this (it would be possible without dynamic, but more complex):
public class IndexerConverter : IValueConverter
{
public string CollectionName { get; set; }
public string IndexName { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Type type = value.GetType();
dynamic collection = type.GetProperty(CollectionName).GetValue(value, null);
dynamic index = type.GetProperty(IndexName).GetValue(value, null);
return collection[index];
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Put following into resources:
<local:IndexerConverter x:Key="indexerConverter" CollectionName="Items" IndexName="Index" />
and use it like this:
<Label Content="{Binding Converter={StaticResource indexerConverter}}"/>
EDIT: The previous solution doesn't update properly when the values change, this one does:
public class IndexerConverter : IMultiValueConverter
{
public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
return ((dynamic)value[0])[(dynamic)value[1]];
}
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
In resources:
<local:IndexerConverter x:Key="indexerConverter"/>
Usage:
<Label>
<MultiBinding Converter="{StaticResource indexerConverter}">
<Binding Path="Items"/>
<Binding Path="Index"/>
</MultiBinding>
</Label>
What you write in the binding markup extension is assigned to the Path property by default, this property is a string so any dynamic content you refer to inside it will not be evaluated. There is no simple XAML-only method to do what you try to do.
Why don't use this:
<StackPanel>
<ListBox Name="lsbItems" ItemsSource="{Binding Items}" SelectedIndex="{Binding Index}"/>
<Label Content="{Binding ElementName=lsbItems, Path=SelectedItem}"/>
</StackPanel>

how to bind a boolean to combobox in wpf

Well I was wondering how to bind a boolean property to a combobox.Combobox will be a yes/no combobox.
You could use a ValueConverter to convert the boolean value to a ComboBox index and back. Like this:
public class BoolToIndexConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((bool)value == true) ? 0 : 1;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((int)value == 0) ? true : false;
}
}
}
Assuming Yes is on index 0 and No on index 1. Then you'd have to use that converter in binding to the SelectedIndex property. For this, you declare your converter in your resources section:
<Window.Resources>
<local:BoolToIndexConverter x:Key="boolToIndexConverter" />
</Window.Resources>
Then you use it in your binding:
<ComboBox SelectedIndex="{Binding YourBooleanProperty, Converter={StaticResource boolToIndexConverter}}"/>
I have found myself using the IsSelected property of the ComboBox items for this in the past. This method is entirely in xaml.
<ComboBox>
<ComboBoxItem Content="No" />
<ComboBoxItem Content="Yes" IsSelected="{Binding YourBooleanProperty, Mode=OneWayToSource}" />
</ComboBox>
First solution is to replace your 'Yes/No' combobox with a checkbox because, well, checkbox exists for a reason.
Second solution is to fill your combobox with true and false objects and then bind the 'SelectedItem' of your combobox to your Boolean property.
Here is an example (replace enabled/disabled with yes/no):
<ComboBox SelectedValue="{Binding IsEnabled}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={x:Static converters:EnabledDisabledToBooleanConverter.Instance}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.Items>
<system:Boolean>True</system:Boolean>
<system:Boolean>False</system:Boolean>
</ComboBox.Items>
</ComboBox>
Here is Converter:
public class EnabledDisabledToBooleanConverter : IValueConverter
{
private const string EnabledText = "Enabled";
private const string DisabledText = "Disabled";
public static readonly EnabledDisabledToBooleanConverter Instance = new EnabledDisabledToBooleanConverter();
private EnabledDisabledToBooleanConverter()
{
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Equals(true, value)
? EnabledText
: DisabledText;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//Actually won't be used, but in case you need that
return Equals(value, EnabledText);
}
}
And no need to play with indices.

Silverlight 4: how to switch control visibility

I am using MVVM in my Silverlight app. When control visibility is need to be managed by data, I am connecting its 'Visibility' property to object's corresponding property:
XAML:
<TextBlock Text="Price" Visibility="{Binding PriceVisibility, Mode=OneWay}"/>
<TextBox Text="{Binding TicketPrice, Mode=TwoWay}" Visibility="{Binding PriceVisibility, Mode=OneWay}"/>
CodeBehind (C#):
public string PriceVisibility { get { return PriceVisible ? "Visible" : "Collapsed"; } }
But from my perspective, returning string representation of the Visibility property is not a best approach.
Could you please advise if there are any better way?
Thanks!
I just used Reflector to inspect the type converters in the PresentationFramework.dll
There is already an implementation that can convert between boolean and visibility. You should be able to make use of this in your silverlight application.
public sealed class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool flag = false;
if (value is bool)
{
flag = (bool) value;
}
else if (value is bool?)
{
bool? nullable = (bool?) value;
flag = nullable.HasValue ? nullable.Value : false;
}
return (flag ? Visibility.Visible : Visibility.Collapsed);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((value is Visibility) && (((Visibility) value) == Visibility.Visible));
}
}
I've faced the problem of binding a Boolean value to the visibility property, so I've implemented my own Boolean to Visibility Converter, I'm using it with most of my applications.
Add the Following Class to your application:
public class BoolVisibilityConverter : IValueConverter{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture){
bool isVisible = (bool)value;
return isVisible ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){
System.Windows.Visibility currVisibility = (System.Windows.Visibility)value;
return (currVisibility == System.Windows.Visibility.Visible);
}
}
Now To Use it you'll need to add it as a resource in your XAML Code.
<UserControl.Resources>
<Helpers:BoolVisibilityConverter x:Key="boolVisibilityConverter" />
</UserControl.Resources>
In your example use the following:
<TextBlock Text="Price" Visibility="{Binding PriceVisibility, Mode=OneWay, Converter={StaticResource boolVisibilityConverter}}"/>
<TextBox Text="{Binding TicketPrice, Mode=TwoWay}" Visibility="{Binding PriceVisibility, Mode=OneWay, Converter={StaticResource boolVisibilityConverter}}"/>

Resources