Silverlight make listbox visible on button hover - silverlight

I cant find a (for sure) simple solution for a simple problem:
If have the following XAML code:
<StackPanel>
<Button Content="Item">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter"></i:EventTrigger>
<i:EventTrigger EventName="MouseLeave"></i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<ListBox Visibility="Collapsed"></ListBox>
</StackPanel>
I would like the list box to show at MouseEnter and hide at MouseLeave. It is probably just a one-liner but i cant find it.
Any help is deeply appreciated.
Thanks!

I believe this will do what you are after:
<StackPanel xmlns:local="clr-namespace:SilverlightApplication;assembly=SilverlightApplication">
<StackPanel.Resources>
<local:BoolToUIElementVisibilityConverter x:Name="BoolToUIElementVisibilityConv"/>
</StackPanel.Resources>
<Button Content="Item" x:Name="YourButton">
</Button>
<ListBox Visibility="{Binding Path=IsMouseOver, ElementName=YourButton, Converter={StaticResource BoolToUIElementVisibilityConv}}">
<ListBoxItem>a</ListBoxItem>
<ListBoxItem>b</ListBoxItem>
<ListBoxItem>c</ListBoxItem>
</ListBox>
</StackPanel>
with a class:
using System.Windows.Data;
using System;
using System.Globalization;
using System.Windows;
namespace SilverlightApplication
{
public class BoolToUIElementVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value == true)
return Visibility.Visible;
else
return "Collapsed";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

Related

How to reference another control in a TreeViewItem through a binding converter?

I would like to bind the Visibility of a TextBox based on SelectedItem of a ComboBoxin same TreeViewItemContainer. I think I can use a Converter for the Binding but I don't know how to send the ComboBox item as a parameter of the TextBox Binding. Can this be done?
<TreeView>
<TreeView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox Margin="2,0" Name="SkillSelectCB" ItemsSource="{Binding PotentialChildren}" />
<TextBox Margin="2,0" Width="50" Visibility="{Binding ??}" />
<Button Margin="2,0" Content="Add" />
</StackPanel>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
This is actually in a HierarchicalDataTemplate, the example above is very minimal. The "Add" Button will add new children to the ViewModel for the TreeView based on what's selected in the ComboBox. And the visibility is the TextBox will change depending on some property of the ComboBox's SelectedItem.
So the Xaml for the TextBox:
<TextBox Margin="2,0"Width="50" Visibility="{Binding SelectedItem, ElementName=SkillSelectCB, Converter={StaticResource SkillToVisibilityConverter}}" />
And the Converter:
public class SkillToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var s = (Skill)value;
return (s == null || !s.Specialized) ? "Hidden" : "Visible";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

When is x:Reference in WPF resolved and why does XAML element order affect it?

x:Reference can not be resolved after I re-arrange elements in XAML.
Here I present a working code. Just move the DataGrid element so it comes after the button element and the bindings for the MenuItem in ContextMenu and MultiBinding in Button.IsEnabled become broken. In Button.IsEnabled only MultiBinding is broken. It can be replaced with commented block and x:Reference works in that single binding.
Both throw XamlParseException.
MenuItem gives System.Xaml.XamlObjectWriterException and message talks about unresolved reference.
MultiBinding gives System.Collections.Generic.KeyNotFoundException as inner exception.
So when is that x:Reference actually resolved and why does only some bindings break when referenced element comes after the element that references it?
Here is my XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xxx="clr-namespace:WpfApplication1"
Title="MainWindow" SizeToContent="WidthAndHeight">
<Window.Resources>
<xxx:BoolToVisibleConverter x:Key="boolToVisibleConv"></xxx:BoolToVisibleConverter>
<xxx:NullToFalseConverter x:Key="nullToFalseConv"></xxx:NullToFalseConverter>
<xxx:NullsOrToFalseConverter x:Key="nullsOrToFalseConv"></xxx:NullsOrToFalseConverter>
<ContextMenu x:Key="MyMenu">
<MenuItem
Header="Menuitem enabled when row selected"
IsEnabled="{Binding
Path=SelectedItem,
Source={x:Reference dataGridElement},
Converter={StaticResource nullToFalseConv}}" />
</ContextMenu>
</Window.Resources>
<StackPanel>
<DataGrid
Name="dataGridElement"
IsReadOnly="True" />
<Button
Content="Button"
ContextMenu="{StaticResource MyMenu}"
Visibility="{Binding
Path=IsReadOnly,
Source={x:Reference dataGridElement},
Converter={StaticResource boolToVisibleConv}}">
<Button.IsEnabled>
<!--<Binding
Path="SelectedItem"
Source="{x:Reference dataGridElement}"
Converter="{StaticResource nullToFalseConv}"/>-->
<MultiBinding
Converter="{StaticResource nullsOrToFalseConv}">
<Binding
Path="SelectedItem"
Source="{x:Reference dataGridElement}"/>
<Binding
Path="SelectedItem"
Source="{x:Reference dataGridElement}"/>
</MultiBinding>
</Button.IsEnabled>
</Button>
</StackPanel>
</Window>
Here is my Code behind (without usings):
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class BoolToVisibleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || (bool)value == false)
return System.Windows.Visibility.Hidden;
else
return System.Windows.Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class NullsOrToFalseConverter : IMultiValueConverter
{
public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
foreach (object val in value)
{
if (val == null)
return false;
}
return true;
}
public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class NullToFalseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value != null);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
I suppose it is because your resources(Window.Resources) will be created first, before referenced instance exists. I would try to solve this through DataContext (ViewModel).
<Window.DataContext>
<yourNameSpace:YourViewModel x:Name="VieModName" />
</Window.DataContext>
<MenuItem Header="HeadrTxt" Command="{Binding CommandInViewModelCmd}" DataContext="{x:Reference Name=VieModName}" />
Excerpted from MSDN(http://msdn.microsoft.com/en-us/library/ee795380.aspx).
x:Reference is a construct defined in XAML 2009. In WPF, you can use
XAML 2009 features, but only for XAML that is not WPF markup-compiled.
Markup-compiled XAML and the BAML form of XAML do not currently
support the XAML 2009 language keywords and features.
x:Reference must be avoided in WPF. Because this markup extension is a recent addition to the XAML language (2009). And it is not completely supported in WPF. Use ElementName in your Binding instead of x:Reference.
<Binding Path="SelectedItem"
ElementName="dataGridElement"/>
On MSDN.

WPF ComboBox a better way to format ItemsSource

Morning Guys,
I have a few ComboBoxes bound to List of TimeSpan. I am formatting the TimeSpans using IValueConverter and ItemTemplate. I was wondering if there were an easier way to format the TimeSpans. Here's what I'm currently doing.
public class TimeSpanConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return string.Empty;
TimeSpan t = TimeSpan.MinValue;
TimeSpan.TryParse(value.ToString(), out t);
return "{0:00}:{1:00}".F(t.Hours,t.Minutes);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return TimeSpan.Parse(value.ToString());
}
#endregion
}
<Canvas>
<Canvas.Resources>
<bc:TimeSpanConverter x:Key="ts" />
<DataTemplate x:Key="TimeSpanTemplate">
<TextBlock Text="{Binding ., Converter={StaticResource ts}}" />
</DataTemplate>
</Canvas.Resources>
<TextBlock Canvas.Left="6"
Canvas.Top="6"
Height="21"
Name="textBlock4"
Text="Begin"
Width="40" />
<TextBlock Canvas.Left="81"
Canvas.Top="6"
Height="21"
Name="textBlock5"
Text="End"
Width="40" />
<ComboBox Canvas.Left="7"
Canvas.Top="25"
Height="23"
Name="TimeBeginCombo"
ItemTemplate="{StaticResource TimeSpanTemplate}"
SelectedItem="{Binding TimeBegin}"
Width="68" />
<ComboBox Canvas.Left="81"
Canvas.Top="25"
Height="23"
Name="TimeEndCombo"
ItemTemplate="{StaticResource TimeSpanTemplate}"
SelectedItem="{Binding TimeEnd}"
Width="68" />
</Canvas>
</GroupBox>
Is what you're binding to of type TimeSpan? If so, then the converter can be much simpler
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is TimeSpan))
return string.Empty;
TimeSpan t = (TimeSpan)value;
return "{0:00}:{1:00}".F(t.Hours,t.Minutes);
}
And also, a general remark - are you sure you need to layout your UI on a Canvas and using absolute coordinates? :)

Binding to a WPF ToggleButton's IsChecked state

I would like to use a WPF ToggleButton to expand and collapse some controls in my application. How can I use XAML to accomplish this?
I'm thinking that I could somehow bind the Visibility attribute of some controls to the ToggleButton's IsChecked state, but I do not know how to do this.
Maybe I need to give my ToggleButton a Name, then bind using ElementName? Then I would need a ValueConverter for converting between a boolean value and a Visibility, correct? How could I make a generic ValueConverter for this purpose?
You need to bind the Visibility through a converter:
<Window
x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<StackPanel>
<ToggleButton x:Name="toggleButton" Content="Toggle"/>
<TextBlock
Text="Some text"
Visibility="{Binding IsChecked, ElementName=toggleButton, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</StackPanel>
</Window>
In Silverlight there is no BooleanToVisibilityConverter but it is easy to write your own with some added features:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace WpfApplication1 {
public class BooleanToVisibilityConverter : IValueConverter {
public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture) {
if (targetType == typeof(Visibility)) {
var visible = System.Convert.ToBoolean(value, culture);
if (InvertVisibility)
visible = !visible;
return visible ? Visibility.Visible : Visibility.Collapsed;
}
throw new InvalidOperationException("Converter can only convert to value of type Visibility.");
}
public Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture) {
throw new InvalidOperationException("Converter cannot convert back.");
}
public Boolean InvertVisibility { get; set; }
}
}
Now you can specify a converter that maps true to Collapsed and false to Visible:
<BooleanToVisibilityConverter
x:Key="InverseBooleanToVisibilityConverter" InvertVisibility="True"/>
Use the BooleanToVisibilityConverter:
<BooleanToVisibilityConverter x:Key="bvc" />
<TextBlock Visibility="{Binding IsChecked, ElementName=toggle, Converter={StaticResource bvc}}" />
Is there a reason why you aren't just using the Expander? It's based on the ToggleButton anyway.

Show the validation error template on a different control in WPF

I have a UserControl that contains other controls and a TextBox. It has a Value property that is bound to the TextBox text and has ValidatesOnDataErrors set to True.
When a validation error occurs in the Value property binding, the error template (standard red border) is shown around the entire UserControl.
Is there a way to show it around the TextBox only?
I'd like to be able to use any error template so simply putting border around textbox and binding its color or something to Validation.HasError is not an option.
Here's my code:
<DataTemplate x:Key="TextFieldDataTemplate">
<c:TextField DisplayName="{Binding Name}" Value="{Binding Value, Mode=TwoWay, ValidatesOnDataErrors=True}"/>
</DataTemplate>
<controls:FieldBase x:Name="root">
<DockPanel DataContext="{Binding ElementName=root}">
<TextBlock Text="{Binding DisplayName}"/>
<TextBox x:Name="txtBox"
Text="{Binding Value, Mode=TwoWay, ValidatesOnDataErrors=True}"
IsReadOnly="{Binding IsReadOnly}"/>
</DockPanel>
UserControl (FieldBase) is than bound to ModelView which performs validation.
to accomplish this task I've used this solution. It uses converter, that "hides" border by converting (Validation.Errors).CurrentItem to Thickness.
<Grid>
<Grid.Resources>
<data:ValidationBorderConverter
x:Key="ValidationBorderConverter" />
</Grid.Resources>
<Border
BorderBrush="#ff0000"
BorderThickness="{Binding
ElementName=myControl,
Path=(Validation.Errors).CurrentItem,
onverter={StaticResource ValidationBorderConverter}}">
<TextBox
ToolTip="{Binding
ElementName=myControl,
Path=(Validation.Errors).CurrentItem.ErrorContent}" />
</Border>
</Grid>
ValidationBorderConverter class is pretty simple:
[ValueConversion(typeof(object), typeof(ValidationError))]
public sealed class ValidationBorderConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return (value == null) ? new Thickness(0) : new Thickness(1);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

Resources