why don't I get any fired converter? - silverlight

I have radio button and I want to define binding between the radio button IsChecked state and the visibility some stackpanel so I wrote this convert method:
public class RadioBtnState2Visible : IValueConverter
{
// RadioBtn start => Visible / Hide
public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
if( value == null )
return Visibility.Collapsed;
bool visibility = false;
bool.TryParse( value.ToString(), out visibility );
return visibility ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
{
throw new NotImplementedException();
//return ( ( Visibility )value ) == Visibility.Visible ? true : false;
}
}
The xaml is
<local:PageEx.Resources>
<local:RadioBtnState2Visible x:Key="Convert" />
</local:PageEx.Resources>
<RadioButton x:Name="MyRadioBtn1" GroupName="group1" />
<RadioButton x:Name="MyRadioBtn2" GroupName="group1" />
<StackPanel Visibility="{Binding ElementName=MyRadioBtn1, Path=IsChecked, Converter={StaticResource Convert}}" />
Now, I dont see any convert fire - i dont see that the application stops on the breakpoint that i set on the first line of the convert method.

This is a duplicate of your previous question, already answered. Here is the answer again:
I got your code working in a test project with one minor change. I made the converter a page resource with the following syntax:
<UserControl.Resources>
<local:RadioBtnState2Visible x:Key="Convert" />
</UserControl.Resources>
I should also mention that I had to actually put something in the stackpanel as well to see the change as by default it collapses to nothing :) I assume you actually have content in your real stackpanel.
Just to explain what is happening here. By adding "local:" to the resource declaration you are actually enclosing an instance of a Resource, and not changing the current resource. Referencing it by "Convert" does not work because it cannot find the resource where it expects to find it.

FYI there is BooleanToVisibilityConverter converter available already:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter1" />
</Window.Resources>

Related

Span in Contentpresenter not working properly

I have stumbled upon a small problem and I'm not sure how to avoid it or work around it and whether it's a bug or a "feature".
When rendering a span with text in it, it seems to be disconnected from the logical tree when using a content presenter to render it. It does not bubble IsMouseOver (or probably any event) and Hyperlinks inside the span also won't fire any associated code.
<ContentPresenter>
<ContentPresenter.Content>
<!--Normally this would be a binding, but it behaves the same.-->
<Span>
Test <Hyperlink Click="Hyperlink_OnClick">Testlink</Hyperlink>
</Span>
</ContentPresenter.Content>
</ContentPresenter>
Inspecting the visual tree with Snoop indeed shows that the TextBlock used to display the span does not receive IsMouseOver-Events from it's inline elements while they themselves do indeed register them correctly (when you expand the inline property and navigate to them; they just refuse to pass them on). Also when attaching a message box to the click handler, nothing happens when you click on the link.
<TextBlock Grid.Row="1">
<Span>
Test <Hyperlink Click="Hyperlink_OnClick">Testlink</Hyperlink>
</Span>
</TextBlock>
This one on the other hand works as expected. The IsMouseOver works fine and even the Link works.
The premise of my problem is, that I want to dynamically bind the text of the TextBlock to something. But I can't bind the text-property to a span directly so I'm using a content presenter which does the job (but is broken). Is this a bug or some feature/implication that I'm unaware of? And is there another way to bind a span to something to display it with working event handling & hyperlink clicks?
You could use a converter that returns a TextBlock with the Span added to its Inlines collection:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Span span = value as Span;
TextBlock textBlock = new TextBlock();
textBlock.Inlines.Add(span);
return textBlock;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
XAML:
<ContentPresenter Content="{Binding Span, Converter={StaticResource MyConverter}}" />

How to implement a Converter

I have a list of objects that I'm binding to the screen. One of the properties is isPurchased. It is a Boolean type.
I don't have a lot of experience with converters so I'm finding this a little difficult. I have 2 questions.
The 1st question is regarding syntax. I copied this example from here.
public class purchasedConverter : IValueConverter
{
public object Convert(inAppPurchases value, Type targetType, object parameter, string language)
{
return;
}
}
If the isPurchased == true then I'd like to set the background color to my stackpanel to a different color.
I changed object value to inAppPurchases value on the Convert method. However, no matter what I tried I could not get a reference to a Background.
I think I want to return Background="somecolor"
My 2nd question (assuming I can do the 1st part), is I'm using StandardStyles.xaml which comes with the Microsoft WinRT projects So my converter would exist there.
<StackPanel Grid.Column="1" VerticalAlignment="Top"
Background="CornflowerBlue" Orientation="Vertical" Height="130"
Margin="0,0,5,0"/>
However, like I said I've tried this before but I wasn't able to figure out how to add the convert to my .xaml file. Where would I reference the converter? Is it on the StandardStyls.xaml or the main .xaml that I'm viewing?
Any help is appreciated.
Background property of StackPanel is type of Brush (Panel.Background msdn) , so we can return object of type SolidColorBrush from Convert method.
Your converter should look like this:
class PurchasedConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// isPurchased is bool so we can cast it to bool
if ((bool)value == true)
return new SolidColorBrush(Colors.Red);
else
return new SolidColorBrush(Colors.Orange);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Next you must create instance of this converter in XAML:
<Window.Resources>
<con:PurchasedConverter x:Key="pCon" />
</Window.Resources>
And now you can use this converter to binding Background property in StackPanel:
<StackPanel VerticalAlignment="Top" Orientation="Vertical" Height="130"
Background="{Binding isPurchased, Converter={StaticResource pCon}}"
Margin="0,0,5,0" >
</StackPanel>

How to implement a table that appears / expands when the "expand" button is clicked?

Is it better to build 2 different pages? Such that when a button is clicked, it leads to another page with the table? Or can we hide the table until the "expand" button is clicked? Is it better to present the table as a listbox? Thanks.
I think a converter is the way to go, like TerrenceJackson said!
In the DataGrid your Binding should look like this:
<CheckBox Content="Expand" Height="72" Name=MyExpandCheckbox IsChecked="False" />
<DataGrid Visibility="{Binding ElementName=MyExpandCheckbox, Path=IsChecked, Converter={StaticResource BoolToVisibleConverter}}"/>
You have to set the Name of your Button/Checkbox/... for the ElementName in the binding for the visibility-property.
Here is an example of a BoolToVisibilityConverter:
public class BoolToVisibilityConverter : IValueConverter
{
#region IValueConverter member
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (Boolean)value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
i would'nt do it with two seperate pages.
You can use a simple expander and style it for your purpose. Here's a video how to use the expander: http://silverlight.net/learn/videos/all/silverlight-toolkit-creating-a-toolkit-expander/ and here's a simple tutorial http://www.c-sharpcorner.com/Resources/768/.
You could also use a simple toggle button and bind the visibility of the table (DataGrid or ListBox, whatever you want) with a converter to the checked state of the toggle button. Somehow like this:
<ToggleButton x:Name="myToggleButton" />
<DataGrid Visibility="{Binding ElementName, Path=IsChecked, Converter={StaticResource BoolToVisibleConverter}}"/>
The BoolToVisibleConverter is a class which implements IValueConverter (http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx).
I don't know your exact aim, but I guess the expander approach is good for you.
Hope this helps.
BR,
TJ

WPF : Conditional templating of textblock

I have a bunch of textblocks in an itemscontrol... I need to know how can I underline the text in the textblock based on whether the text is available in a list in the data model..
Sounds very simple to me...but I have been googling since the past 8 hrs...
Can I use datatriggers and valueconverters for this purpose? If yes, then how can I execute the method which lies in the viewModel (the method which helps me to check whther a given a text exists in the data model list)...
Even if I go for conditional templating....how do I access the list which lies in my model (the viewmodel can fetch it...but then how do i access the viewmodel?)..
This should be a fairly easy thing to do...Am I really missing something very simple here?? :)
I am following the MVVM pattern for my application..
One way is to use a multivalueconverter which is a class that implements IMultiValueConverter. A multivalueconverter allows you to bind to several values which means that you can get a reference to both your viewmodel and the text of your TextBlock in your valueconverter.
Assuming that your viewmodel has a method called GetIsUnderlined that returns true or false indicating whether or not the text should be underlined your valueconverter can be implemented along these lines:
class UnderlineValueConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var viewmodel = values[0] as Window1ViewModel;
var text = values[1] as string;
return viewmodel.GetIsUnderlined(text) ? TextDecorations.Underline : null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
You can use this valueconverter in the following way for a TextBlock:
<Grid x:Name="grid1" >
<Grid.Resources>
<local:UnderlineValueConverter x:Key="underlineValueConverter" />
</Grid.Resources>
<TextBlock Text="Blahblah">
<TextBlock.TextDecorations>
<MultiBinding Converter="{StaticResource underlineValueConverter}">
<Binding /> <!-- Pass in the DataContext (the viewmodel) as the first parameter -->
<Binding Path="Text" RelativeSource="{RelativeSource Mode=Self}" /> <!-- Pass in the text of the TextBlock as the second parameter -->
</MultiBinding>
</TextBlock.TextDecorations>
</TextBlock>
</Grid>

Change other's property

Right now, I'm learning WPF. Can we change another WPF object's property when an WPF object's property is changed?
Below is simplified scenario.
I have a Window with a TextBox named m_Text and a ToggleButton named m_Button. I want to change the m_Text.Background property if m_Button is pressed, that is m_Button.IsChecked = true. I think it's possible using a Trigger but I don't know how to do it.
P.S. If possible, I want to do it only in XAML.
WPF makes this really easy - you can databind the TextBox's Background property directly to the IsChecked property on the ToggleButton. Of course, you will need to convert the IsChecked (boolean) to be a Brush, but WPF allows you to specify a Converter object right in the binding...
In code, you create an object that implements IValueConverter, and implement the Convert method, like
public class BoolToBrushConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool isChecked = (bool)value;
string[] colours = parameter.ToString().Split(':');
if (isChecked)
return new BrushConverter().ConvertFromString(colours[0]);
return new BrushConverter().ConvertFromString(colours[1]);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
then in xaml you need to add the namespace containing this class, declare an instance of the converter as a resource within the window, then use it in the Binding... it should look something like this:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:BoolToBrushConverter x:Key="boolToBrushConverter" />
</Window.Resources>
<StackPanel Height="250">
<ToggleButton Name="toggleButton" Height="32" Content="Green" />
<TextBox
Background="{Binding ElementName=toggleButton, Path=IsChecked, Converter={StaticResource boolToBrushConverter}, ConverterParameter=Green:White}" />
</StackPanel>
</Window>
UPDATE: As per Ivan's excellent suggestion - have updated to show how you can pass parameters through to the Converter from the XAML...

Resources