wpf command control visibility - c#

I have a custom command:
public static class CommandLibrary
{
private static RoutedUICommand cmdMyCommand = new RoutedUICommand("My command", "MyCommand", typeof(CommandLibrary));
public static RoutedUICommand MyCommand{ get { return cmdMyCommand ; } }
}
and I register a binding like this
CommandManager.RegisterClassCommandBinding(typeof(SomeClass), new CommandBinding(CommandLibrary.MyCommand, new ExecutedRoutedEventHandler(myCommandExecuteHandler), new CanExecuteRoutedEventHandler(myCommandCanExecuteHandler)));
And in generic.xaml I have a Buton with Command property set. The button is being properly enabled/disabled based on logic in myCommandCanExecuteHandler.
But now I would like to also control this button's visibility (independent of CanExecute which is mapped to IsEnabled). How do I approach that problem?
A discussion about the same problem is available here: http://social.msdn.microsoft.com/forums/en-US/wpf/thread/c20782f8-2d04-49d3-b822-f77b4b87c27a/, but somehow the idea that CanBeSeen is a property of RoutedUICommand derived class does not appeal to me.

you can bind the the visibility attribute in xaml to the value which decides button's visibility
<Button Content="Button" Height="23" Visibility="{Binding someclass, Converter={Binding VisibitlityConverter}}"/>
and use a converter to convert bool value to callpsed or visible
class visibilityConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (bool)value == true? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}

Do you want to make the button to be visible when the button is enabled/disabled... If then you have to bind the IsEnabled property to Visibility property using the Boolean to Visibility converter...

I ran into a very similar problem today.
"Sometimes" the CanExecute binding is being ignored when the visibility of the button is set collapsed state by the visibility converter. I said "sometimes" because, if I put a breakpoint in the visibility converter, it alters the behaviour.
When the visibility is changed to Visible - the CanExecute is not being called again. A mouse click anywhere on the UI refreshes the CanExecute binding, which makes it work as expected.
I worked around this issue by binding to the Button IsEnabled property directly to a property on my viewmodel, which reflects what my CanExecute does.

Related

Custom design time visibility attribute in WPF

I have a complex window with various controls that are visible or collapsed based on bool values. I want to add a custom attribute to show all of these controls during design time.
My implementation of the attribute looks like this:
public static class CustomAttributes
{
private static bool? _inDesignMode;
public static readonly DependencyProperty Visibility = DependencyProperty.RegisterAttached(
"Visibility",
typeof(Visibility),
typeof(CustomAttributes),
new PropertyMetadata(VisibilityChanged));
private static bool InDesignMode
{
get
{
if (!_inDesignMode.HasValue)
{
var prop = DesignerProperties.IsInDesignModeProperty;
_inDesignMode =
(bool)DependencyPropertyDescriptor.FromProperty(prop, typeof(FrameworkElement)).Metadata.DefaultValue;
}
return _inDesignMode.Value;
}
}
public static Visibility GetVisibility(DependencyObject dependencyObject)
{
return (Visibility)dependencyObject.GetValue(Visibility);
}
public static void SetVisibility(DependencyObject dependencyObject, Visibility value)
{
dependencyObject.SetValue(Visibility, value);
}
private static void VisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!InDesignMode)
return;
d.SetValue(Control.VisibilityProperty, e.NewValue);
}
}
In XAML I use it like this:
<Button Visibility="{Binding SomeBoolValue, Converter={StaticResource BoolToVisibility}}"
helper:CustomAttributes.Visibility="Visible"
/>
However, it does not seem to work. I use some other custom attributes like this and they do their job, but visibility doesn't trigger, it just stays collapsed in the design view. What am I missing?
Edit:
Thank you for pointing me to the right direction. The solution to my problem did not require the custom attribute as I first assumed it would. To achieve the design-time behavior that I wanted, I modified the converter implementation as suggested in the accepted answer below.
Think a little deeper about the logic you created.
The UI element does not have TWO Visibility properties, it is the only one.
But you want to manipulate this property in two ways at the same time: through the binding and the attached property.
Thus, you have created competition between them for this property.
And the property will take on the value that will be assigned to it last.
The attached property will be triggered only once when the Button is initialized (from the example).
And the binding will be triggered when the Data Context and/or its SomeBoolValue property changes.
But the Data Context of the Window is set later than the initialization of the UI elements of this Window.
I see several solutions.
The easiest one, if you need to ALWAYS show elements in Design Mode, is to add the appropriate logic to the converter.
In its simplest form, an example of such a converter:
/// <summary>Bool to Visibility converter.</summary>
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BooleanToVisibilityConverter : IValueConverter
{
public static bool IsDesignMode { get; } = DesignerProperties.GetIsInDesignMode(new DependencyObject());
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool val)
return IsDesignMode || val
? Visibility.Visible
: Visibility.Collapsed;
return DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Binding enum with propertychanged handler not raising converter

I'm not new in C# programming with WPF and I've never needed to do this, but now I need it and I'm stuck for some time now with it. I need to bind an enum that has attached it's OnPropertyChanged method to raise a converter every time the enum changes. I've got the following code for the enum:
private WindowState windowstate;
public enum WindowState
{
INITIAL = 0,
LANGUAGE = 1,
SENSOR = 2,
PARAMETERS = 3,
LEGAL = 4,
PRIVACY = 5,
ABOUT = 6,
MANUAL = 7
}
public WindowState State
{
get { return windowstate; }
set { windowstate = value; OnPropertyChanged("State"); }
}
And on the xaml where I bind the enum I've got this:
Color="{Binding State, Converter={StaticResource ButtonMenuColor}, ConverterParameter=language, ElementName=userControl}"
What I want is to change the color of a button depending on the value of the enum. Is it possible to make it this way or WPF, for some reason, does not support this?
This is the converter code:
class ButtonMenuColor : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Lynx.Windows.Herramientas.WindowState state = (Lynx.Windows.Herramientas.WindowState)value;
string param = parameter as string;
if (state.ToString().ToLower() == param)
return Application.Current.FindResource("white") as SolidColorBrush;
return Application.Current.FindResource("buttonmenu_color") as SolidColorBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
what come into my head are :
change binding mode to two way. add updateSourceTrigger =
PropertyChanged , NotifySourceUpdated = True
try a fallback value checking your binding is correct or not.
maybe your control loads before your value set.
and put your enum value as
{x:static Namespace:Class.WindowState+LANGUAGE }
Seems you are binding to a user control, but your property is in a viewmodel?
So change your binding to
Color="{Binding DataContext.State, Conv...}"
So you are binding to the State property of your userControl's viewmodel. If the State is a DependencyProperty of your userControl the binding should work.

Binding Visibility propety of text block to Stack.Any

I have a TextBlock as follow:
<TextBlock Text="You don't have any more items." Visibility="{binding}"
and in code behind I defined a Stack called items as follow:
private Stack<Item> _items;
How do I bind the text visibility in xaml to visible when _item.Any is false?
There are several steps to achieving what you want to do and they are all described here
You need to create a value converter similar to this;
public class EmptyCollectionToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var collection = (Stack<int>) value;
return collection.Any() ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then you need to add a reference to is in your resource dictionary in your xaml like this;
<views:EmptyCollectionToVisibilityConverter x:Key="EmptyCollectionToVisibilityConverter"/>
Finally bind your property in your view model to the visibility of your control and give the binding the converter like this;
Visibility="{Binding Items, Converter={StaticResource EmptyCollectionToVisibilityConverter}}"
Your property will probably need to be an observableCollection (which will mean changing the value converter example I gave you slightly.
I'd probably go with:
private Stack<Item> _items;
// bind to this property using converter
public bool IsVisible => !(_items?.Any(...) ?? false);
You shouldn't expose your _stack directly, but e.g. use methods to do something (because you need to rise notification every time you push/pop an item):
public void PushItem(Item item)
{
_items.Push(item);
OnPropertyChanged(nameof(IsVisible)); // implement INotifyPropertyChanged
}

C# Binding with static resource

I need to set background color of my controls, depending on a punch of ruler. So, I am trying to use converters to do that.
In my XAML:
<TextBox Background="{Binding Converter={StaticResource BackgroundConverter}, ConverterParameter='UserName'}">
In my converter I find for a rule for "UserName". But I use the entire binding object for that:
object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
var person = (value as PersonBase).Person;
if (person.state == editing)
return GetRulesFor(parameter);
else
return Brushes.Silver;
It works in the first time screen is showing, but I need to update these properties when user edit form, cancel, etc.
How can I set my binding for this to happen ?
You can make a new property in the viewmodel and call it State, and return the person.state. When you change the state of the person object is changed just call OnPropertyChanged("State").
public class YourViewModel : INotifyPropertyChanged
{
// ... your code here
public StateObjectType State
{
get {return person.state;}
}
// when you modify the person state just call OnPropertyChanged("State")
}
In your view bind the textbox
<TextBox Background="{Binding State,Converter={StaticResource BackgroundConverter}, ConverterParameter='UserName'}">
This will make your code works.

Combobox selection change in XAML

I have a Combobox and two buttons in my UserControl. Is it possible to set those button to change the selected index of the Combobox directly in XAML?
I have done this by two approaches:
Code-behind
private void nextBut_Click(object sender, RoutedEventArgs e)
{
combo.SelectedIndex++;
}
private void prevBut_Click(object sender, RoutedEventArgs e)
{
combo.SelectedIndex--;
}
Or by binding commands to those buttons and define that command in my ModelView.
I have another question about XAML and I really don't know if ask a different question or use this opportunity that you are already reading me! I'm sure it has to be straightforward (at least for WPF gurus around here):
I have a ItemsControl that holds that UserControl, but there may be several or none (because you can create more, or delete). I want a Checkbox outside that is enabled or not depending if there are or not elements in my ItemsContol (disable if there is nothing). I think this can be done with Command Validation but looks difficult to me as I'm new in this world. This also could be done with codebehind but I would like to avoid it. (Like defining a bool property bound to that Checkbox, as write something like if(myItems.Count==0)
I'd rather bind the SelectedItem property to some property in the ViewModel, and bind these buttons to some Commands in the ViewModel. This way keep the state data (selectedItem) in the ViewModel, and can use that to perform any additional logic required, removing the need for code behind.
For the CheckBox, I'd rather put a bool property in the ViewModel, and notify that whenever you add/remove items.
public bool HasItems {get {return Items.Any(); } }
public void AddItem()
{
//...Add Items
NotifyPropertyChanged("HasItems");
}
public void RemoveItem()
{
//...Remove Item
NotifyPropertyChanged("HasItems");
}
This removes the need for an additional converter.
For the checkbox issue, it comes under the generic issue of converting a quantity into a bool. A canonical WPF answer would be bind the checkbox IsChecked property to the collection and route it through an IValueConverter. Here is a converter to do just that...
public class QuantityToBoolConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
try
{
IEnumerable items = value as IEnumerable;
if (items != null)
{
return items.OfType<object>().Any();
}
}
catch
{
return value;
}
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return null;
}
}
To deploy it, you would need to declare it in your Xaml as a resource...
<Window.Resources>
<converters:QuantityToBoolConverter x:Key="QuantityToBoolConverter"/>
</Window.Resources>
And then bind the IsChecked property to your items and declare the converter...
<ListBox Name="mylb">
</ListBox>
<CheckBox IsChecked="{Binding ElementName=mylb, Path=ItemsSource, Converter={StaticResource
QuantityToBoolConverter}}"></CheckBox>
For the combobox SelectedIndex issue, you can check out the CollectionViewSource docs. Here You can manipulate this in your ViewModel to move the current selection. And there's tons of sample code to examine. Knowing the ICollectionView will serve you well as a WPF developer.

Categories