Disable scrolling if the cursor is over element - wpf

I wanted to disable the scrolling when the cursor is over an element in WPF.
If the mouse is over the red rectangle, the scroll should be disabled.
The red rectangle is on a scrollviewer.
Any idea?

I got it to work with this code:
<Window.Resources>
<converter:MouseOverToScrollBarVisibility x:Key="scrollVisibility" />
</Window.Resources>
<ScrollViewer VerticalScrollBarVisibility="{Binding IsMouseOver,
ElementName=rec,
Converter={StaticResource scrollVisibility}}">
<Rectangle Height="50" Width="50" Fill="Red" x:Name="rec"/>
</ScrollViewer>
Then just define this converter:
[ValueConversion(typeof(bool), typeof(ScrollBarVisibility))]
sealed class MouseOverToScrollBarVisibility : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value) ? ScrollBarVisibility.Hidden : ScrollBarVisibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}

Related

Bind IsEnabled value from string

How can I bind a value of string Y or N to a isEnabled Value?
<TextBox IsEnabled="{Binding Path=StringValueFromSomeEntity, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
StringValueFromSomeEntity can be a Y or N value.
Use a converter to convert the string to a bool-value:
public class StringToBoolConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.ToString().ToLower() == "y")
return true;
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value)
return "Y";
return "N";
}
}
Refer to it in the resources:
<Window.Resources>
<conv:StringToBoolConverter x:Key="StringToBool"/>
</Window.Resources>
Apply it to your binding (if you just want to change the IsEnabled property according to your string, use Mode=OneWay, but if you really want to bind TwoWay you need the ConvertBack-method):
<TextBox IsEnabled="{Binding Path=StringValueFromSomeEntity, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ResourceKey=StringToBool}"/>
You can create an IValueConverter subclass like this:
public class YNBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value as string) == 'Y';
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value ? 'Y' : 'N';
}
}
You need ConvertBack if you are expecting to bind TwoWay.
Then add it to the resources of your page.
And add it to the binding
{Binding Path=StringValueFromSomeEntity, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged, Converter={StaticResource YNBoolConverter}}
By default string cann't be converted into Boolen type so you have to tell WPF how to convert and take the value in place where you want to have.
here are two ways to implement this.
Using ValueConverter (prefered way)
Add a Converter into your project like below.
public class StringToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string val = System.Convert.ToString(value).ToUpper();
if (string.IsNullOrWhiteSpace(val))
return false;
return val == "Y" ? true : false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Add the namespace into you window and add resource
<Window.Resources>
<convrter:StringToBoolConverter x:Key="stringtoboolConverter"/>
</Window.Resources>
Now refrance this convert into IsEnabled Propery of Checkbox.
<GroupBox Header="With Converter" >
<StackPanel>
<TextBox x:Name="txt1" Text="Y" />
<CheckBox IsEnabled="{Binding ElementName=txt1,Path=Text,Converter={StaticResource stringtoboolConverter}}" />
</StackPanel>
</GroupBox>
Using Style / Triggers (alternative way)
<TextBox x:Name="txt" Text="Y" />
<CheckBox Content="IsEnabled" Tag="{Binding ElementName=txt,Path=Text}" >
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Style.Triggers>
<Trigger Property="Tag" Value="Y" >
<Setter Property="IsEnabled" Value="true"/>
</Trigger>
<Trigger Property="Tag" Value="N" >
<Setter Property="IsEnabled" Value="false"/>
</Trigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
Use a ValueConverter.
Create a class which implements IValueConverter
for example
public class StringToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string value = (string)value;
return value.Trim().ToLower() == "y";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
After that you can it applay to your binding

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.

Silverlight make listbox visible on button hover

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();
}
}
}

Binding a Distinction basedon Actual Width to Visibility

Is it possible to bind an ActualWidth or Width property of a Control to the Visibility of another Control with a distinction about value (like <200)? In my Opinion it is only possible with a converter because a DataTrigger can not work with > or <.
So I tried it with a Converter but it didn't work. I'm not sure which BindingMode is necessary and which kind of converter I need for such a solution.
The xaml code:
<StackPanel>
<Slider x:Name="slider" Height="36" Width="220" Maximum="500"/>
<Rectangle x:Name="mover" Height="12" Stroke="Black" Width="{Binding Value, ElementName=slider}"/>
<Rectangle x:Name="rectangle" Fill="#FFFF9E0E" Height="34" Width="112" Visibility="{Binding ActualWidth, Converter={StaticResource umkehr}, ElementName=rectangle, Mode=OneWay}"/>
</StackPanel>
and the idea for the converter:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null) {
var val = System.Convert.ToDouble(value);
if (val > 100)
return Visibility.Visible;
return Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
It is likely not working because you are binding your Rectangle's Visibility to the same rectangle's ActualWidth, and an invisible rectangle will always have a width of 0, so will never be visible.
Here's some examples. One binds to the other rectangle's ActualWidth, and the other binds to your Slider's Value
<Rectangle x:Name="rectangle"
Visibility="{Binding ActualWidth, ElementName=mover,
Converter={StaticResource umkehr}}"/>
or
<Rectangle x:Name="rectangle"
Visibility="{Binding Value, ElementName=slider,
Converter={StaticResource umkehr}}"/>
And as far as I know, there's no easy way of basing a value off of if something is greater than or less than a value. Coverters are your best option.
ActualWidth is a readonly property exposed by FrameworkElement class -
public double ActualWidth { get; }
It is get only property hence you can't set it to other value from code. You can bind to Width of your control instead to make it work.
EDIT
This works for me, may be this is what you want -
Converter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double)
{
return ((double)value > 100) ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
XAML
<StackPanel>
<Slider x:Name="slider" Height="36" Width="220" Maximum="500"/>
<Rectangle x:Name="mover" Height="12" Stroke="Black" Width="{Binding Value, ElementName=slider}"/>
<Rectangle x:Name="rectangle" Fill="#FFFF9E0E" Height="34" Width="112" Visibility="{Binding ActualWidth, Converter={StaticResource MyConverter}, ElementName=mover, Mode=OneWay}"/>
</StackPanel>
If you're attempting to change the Visibility of a control based on the ActualWidth of another control, you'll either need to use a IValueConverter or you're own type of MarkupExtension (inherit from Binding or BindingBase).
Converter Option:
[ValueConversion(typeof(Double), typeof(Visibility))]
[ValueConversion(typeof(Double?), typeof(Visibility))]
public class MinimumLengthToVisibilityConverter : IValueConverter
{
public Double MinLength { get; set; }
public override Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture)
{
if ((value == null) || !(value is Double))
{
return DependencyProperty.UnsetValue;
}
return (((Double)value) > MinLength) ? Visibility.Visible : Visibility.Collapsed;
}
public override Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
MarkupExtension Option:
Read this blog post to get a better feel for how to implement this...
You can actually have the value in a parameter, so you can re-use the converter if you need to:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double cutoff = 0.0;
if(parameter is double)
{
cutoff = (double)parameter;
}
if (parameter is string)
{
Double.TryParse(parameter.ToString(), out cutoff);
}
if (value is double)
{
return ((double)value > cutoff) ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
And the XAML:
<StackPanel>
<Slider x:Name="slider" Height="36" Width="220" Maximum="500"/>
<Rectangle x:Name="mover" Height="12" Stroke="Black" Width="{Binding Value, ElementName=slider}"/>
<Rectangle x:Name="rectangle" Fill="#FFFF9E0E" Height="34" Width="112"
Visibility="{Binding ActualWidth, Converter={StaticResource ActualWidthToVisibilityConverter},
ElementName=mover, Mode=OneWay, ConverterParameter=100}"/>
</StackPanel>

How converter null to ImageNull.jpg

This code not work?
column don't show
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Tag="{Binding photo}" MaxHeight="50">
<Image.Source>
<BitmapImage UriSource="{Binding photo, Converter={StaticResource ConvertNullImageKey}}" />
</Image.Source>
</Image>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
Converter:
public class ConvertNullImage : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var image = new BitmapImage();
try
{
image = new BitmapImage(new Uri(value.ToString()));
return image;
}
catch { return new BitmapImage(new Uri("http://upload.wikimedia.org/wikipedia/commons/1/1c/No-Symbol.png")); }
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}
What you are currently doing is taking an existing BitmapImage and trying to assign another BitmapImage to its UriSource. Have you tried this:-
<Image Tag="{Binding photo}" MaxHeight="50" Source="{Binding photo, Converter={StaticResource ConvertNullImageKey}}" />

Resources