Custom design time visibility attribute in WPF - c#

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

Related

Disable binding to static property during design-time

I like to bind to static properties whenever I can (e.g. when notification is not needed or when model anyway implement INotifyPropertyChanged for other purposes), e.g.:
Visibility="{Binding IsAdministractor, Source={x:Static local:User.Current}, Converter={local:FalseToCollapsedConverter}}"
The problem is that such evaluation works at design-time too, making it hard to work with designer.
Normal bindings doesn't work in design-time and I can utilize FallbackValue to specify design-time only values (I have never yet used FallbackValue in run-time).
Is there an easy way to make binding to static properties invalid (disable them) during design-time?
I can temporarily rename property, e.g. IsAdministrator123, but this is tedious.
You can check if you're in design mode either in the Converter or in the static Current or in the IsAdministractor(typo here?) property and just return whatever state you'd like to see.
EDIT:
Here's some code for a MarkupExtension (untested)
public class BindingWithDesignSupport : MarkupExtension
{
public BindingWithDesignSupport(){}
public BindingWithDesignSupport(BindingBase binding)
{
Binding = binding;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return DesignerProperties.GetIsInDesignMode(new DependencyObject()) ? DesignTimeValue : Binding.ProvideValue(serviceProvider);
}
public BindingBase Binding { get; set; }
public object DesignTimeValue { get; set; }
}
you should be able to use it like:
Visibility="{BindingWithDesignSupport {Binding IsAdministractor, Source={x:Static local:User.Current}, Converter={local:FalseToCollapsedConverter}},DesignTimeValue=Visibility.Visible}"
It's possible to attach converter to all such properties, which has FallbackValue (used in design-time) and Converter (to supply run-time converter) properties:
public class RuntimeConverter : MarkupExtension, IValueConverter
{
public object FallbackValue { get; set; }
public IValueConverter Converter { get; set; }
public RuntimeConverter() { }
public override object ProvideValue(IServiceProvider serviceProvider) => this;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
return FallbackValue;
if (Converter == null)
return value;
return Converter.Convert(value, targetType, parameter, culture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
return FallbackValue;
if (Converter == null)
return value;
return Converter.ConvertBack(value, targetType, parameter, culture);
}
}
then in design-time it is possible to change value returned by static property:
<!-- split in multiple lines for readability -->
Visibility="{Binding IsPowerUser, Source={x:Static local:User.Logged},
Converter={local:RuntimeConverter Converter={local:FalseToCollapsedConverter},
FallbackValue=Collapsed}}">
You could use design time data to put the design time view model into the state you want to design against.
Or for simple properties you can initialise them with the desired design time value in the viewmodel e.g.
public bool IsAdministractor { get; set; } = true;

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
}

Ways to bind Enums to WPF controls like Combobox, TabHeader etc

In my program (MVVM WPF) there are lot of Enumerations, I am binding the enums to my controls in the view.
There are lot of ways to do it.
1) To bind to ComboBoxEdit(Devexpress Control). I am using ObjectDataProvider.
and then this
<dxe:ComboBoxEdit ItemsSource="{Binding Source={StaticResource SomeEnumValues}>
This works fine but in TabControl header it doesn't.
2) So, I thought of using IValueConverter that didnt worked either.
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
if (!(value is Model.MyEnum))
{
return null;
}
Model.MyEnum me = (Model.MyEnum)value;
return me.GetHashCode();
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
on XAML:
<local:DataConverter x:Key="myConverter"/>
<TabControl SelectedIndex="{Binding Path=SelectedFeeType,
Converter={StaticResource myConverter}}"/>
3) The third way of doing this is to make a behavior dependency property
Something like this
public class ComboBoxEnumerationExtension : ComboBox
{
public static readonly DependencyProperty SelectedEnumerationProperty =
DependencyProperty.Register("SelectedEnumeration", typeof(object),
typeof(ComboBoxEnumerationExtension));
public object SelectedEnumeration
{
get { return (object)GetValue(SelectedEnumerationProperty); }
set { SetValue(SelectedEnumerationProperty, value); }
}
I want to know what is the best way to handle enumerations and binding to it. Right now I am not able to bind tabheader to the enums.
Here's a nicer way of doing it:
On your model, put this Property:
public IEnumerable<string> EnumCol { get; set; }
(Feel free to change the name to whatever suits you, but just remember to change it everywhere)
In the constructor have this (or even better, put it in an initialization method):
var enum_names = Enum.GetNames(typeof(YourEnumTypeHere));
EnumCol = enum_names ;
This will take all the names from your YourEnumTypeHere and have them on the property you'll be binding to in your xaml like this:
<ListBox ItemsSource="{Binding EnumCol}"></ListBox>
Now, obviously, it doesn't have to be a ListBox, but now you're simply binding to a collection of strings, and your problem should be solved.

Why isn't my type converter working

Tearing my hair out here! I have this type-converter:
class CouponBarcodeToVisibilityConverterColumn : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (DesignerProperties.IsInDesignMode)
{
if ((string)parameter == "123456")
{
return Visibility.Visible;
}
return Visibility.Hidden;
}
if (value == null)
{
return Visibility.Visible;
}
var barcodesWanted = ((string)parameter).Split(System.Convert.ToChar("_"));
var actualBarcode = (string)value;
return barcodesWanted.Any(barcodeWanted => barcodeWanted == actualBarcode) ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
I have a UserControl with the following Resources section:
<UserControl.Resources>
<converters:CouponBarcodeToVisibilityConverterColumn x:Key="CouponBarcodeToVisibilityConverter1"/>
</UserControl.Resources>
I have a model called Bet, it looks like this:
public class Bet : INotifyPropertyChanged
{
//Lots of other stuff
private string _barcode;
public string Barcode
{
get { return _barcode; }
set
{
if (value == _barcode) return;
_barcode = value;
OnPropertyChanged("Barcode");
}
}
//Lots of other stuff
}
In the ViewModel which is the DataContext of my user control I have an Observable Collection of Bet. Back to my user control, I have a stack panel, the data context of which is the aforementioned Observable Collection.
Inside the Stack Panel I have a DataGrid, the ItemsSource property is simply {Binding}, deferring the binding up the tree as it were.
Inside my DataGrid I have this column:
<DataGridCheckBoxColumn x:Name="IsEwColumn" Binding="{Binding Wagers[0].IsEw,UpdateSourceTrigger=PropertyChanged}" Header="Each Way" Visibility="{Binding Path=Barcode, Converter={StaticResource CouponBarcodeToVisibilityConverter1}, ConverterParameter=123456}" Width="Auto"/>
The other element of the binding works perfectly (the checkbox is ticked whenever it is supposed to be) but my type converter is not. The breakpoint doesn't even get hit. The Barcode property inside Bet is definitely equal to 123456.
What have I missed?
What you have here is a list of bets for the items source of the data grid.
If you think about it
Bet1 could evaluate to visible when passed via type converter.
Bet2 could evaluate to visible when passed via type converter.
Bet3 could evaluate to collapsed when passed via type converter.
How would the datacolumn be both visible and collapsed at the same time.
You can't bind to visibility like that, unless you had an overall variable on the list or something that it could bind to.

wpf command control visibility

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.

Categories