XAML - ListViewItem - IsEnabled Binding - c#

Please put me out of my misery:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsEnabled" Value="{Binding MyBoolField}" />
</Style>
</ListView.ItemContainerStyle>
Where MyBoolField is a property available on each item in the ListView's assigned ItemsSource, and is of course of type bool.
The desired behaviour is that the IsEnabled property of each ListViewItem is bound to the MyBoolField property of the object it contains (an element from the ListView's ItemsSource). The example above however pays no attention to this binding and is always true.
If I set the value to false statically, the item becomes disabled as expected.
I can only assume this is an issue of scoping, or a restriction on the use of bindings in this particular scenario, however I am unable to find any documentation to support this.
Perhaps it is useful to know that bindings set up in the DataTemplate assigned to this ListView's ItemTemplate all work okay, so the problem is hopefully not that fundamental/stupid.
Points from the Comments
There is no relevant output in the debug 'Output' window.
Binding the MyBoolField property elsewhere works fine, as such the underlying data source is providing a Boolean value correctly and this seems to be solely an issue of binding it in this context.

Ok, reading this post it seems that its a known limitation of WinRT, maybe you find something useful there.
One thing i would also try, because the OP in that post said something regarding that is. Using a Self binding, and use Path=DataContext.MyBoolField
Further reading, this is a limitation from Silverlight, which WinRT was build upon. So this is a workaround which should also work for WinRT

Related

Default Value for Control Template binding in WPF MVVM

Probably a dumb question but to make a default value for binding in a WPF ControlTemplate what is the best way in terms of performance?
I've tried several option:
Priority binding: It didn't work, probably my bad...
ControlTemplate Trigger: Works well, I use it on a property which always return true in my case:
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="TextBoxWidth" Value="300" />
</Trigger>
</ControlTemplate.Triggers>
FallBackValue: Works well too.
Is it better to work with trigger, FallBackValue or is there another way to do it?
Thanks in advance
----------------- UPDATE ----------------
After doing more research it seems that the best way to achieve my goal is simply using the styles...
I don't know why it didn't work in the first place but just doing this seems to work:
<Style TargetType="local:EditableWidthText">
<Setter Property="TextBoxWidth" Value="300"/>
</Style>
No need for FallbackValue anymore. It works when there is a binding, when there is no binding and when it's overrided by another style. Exactly what I need.
Thanks Sinatr for your comment about performance of FallbackValue.
Fyi Priority Binding:
PriorityBinding lets you associate a binding target (target) property with a list of bindings.
The first binding that returns a value successfully becomes the active binding.
https://msdn.microsoft.com/en-us/library/system.windows.data.prioritybinding%28v=vs.110%29.aspx
I never used template selector nor datatemplate, but I think it's a bit overkill for my need, no?
----------------- UPDATE #2----------------
#Sinatr:
I've a Mainviewmodel which contains several ViewModel binded to several usercontrols displayed into the MainView.
(Something like one of my other post: Navigate through UserControl with MVVM LIGHT (WPF))
But this controlTemplate is for a looklessControl (something quite simple, juste a label and a textbox).
In this LookLess Control I've created 4 dependency properties.
In the control template I've binded 2 of them to the Text/Content propertie of the Textbox/Label
and two to their width. (I want the user to be able to create forms in the future, binding way).
For example the label looks like this in the ControlTemplate:
<Label
Width="{Binding Path=LabelWidth,
RelativeSource={RelativeSourceAncestorType=local:EditableWidthText}}"
Content="{Binding Path=LabelText,
RelativeSource={RelativeSource AncestorType=local:EditableWidthText}}"/>
I just want the width to be equals to 130 when there is no binding defined.
But I don't want problem of performance because of a binding failed or something like this.
Template selector are very interesting, but I don't think that applied in my case.
There is no switching within the datas, it's just a default value. So I don't think that apply either.
(But maybe I'm wrong :p )
So maybe I think that styles are the way to go?

How to bind resources properties in a DataTemplate

Hello all I have the following data template:
<DataTemplate DataType="Integer">
<StackPanel>
<xctk:IntegerUpDown Minimum="{Binding XPath=Min}"
Maximum="{Binding XPath=Max}"
Increment="{Binding XPath=Inc}"
ClipValueToMinMax="True"
AllowSpin="True">
<xctk:IntegerUpDown.Resources>
<converters:Parameter x:Key="IntegerParameter"
CurrentDevice="{Binding ElementName=Dock, Path=DataContext.CurrentDevice}"
ParameterName="{Binding RelativeSource={RelativeSource TemplatedParent}, XPath=#RegisterName}"
ParameterType="Integer">
</converters:Parameter>
</xctk:IntegerUpDown.Resources>
<xctk:IntegerUpDown.Value>
<Binding XPath="#Name"
Converter="{StaticResource IntegerDataConverter}"
ConverterParameter="{StaticResource IntegerParameter}"
Mode="TwoWay"/>
</xctk:IntegerUpDown.Value>
</xctk:IntegerUpDown>
</StackPanel>
</DataTemplate>
Aim of this data template is to call the converter to set the value of the IntegerUpDown control reading it from an external device.
Details on how to contact the device are stored in the converters:Parameter class (derived from dependency object). Two way means that the same mechanism should be used with ConvertBack to write the value to the device.
MultiBinding is not an option since the ConvertBack method could not be used to "create" all the parameters from a single integer value.
This template works almost as intended: I get an instance of the Parameter class for each item the data template is applied to.
Unfortunately the values for CurrentDevice (that should bind to the DataContext property CurrentDevice of the window named "Dock") and ParameterName (that should bind to an Xml attribute of the Xml Node the DataTemplate is applied to) are always null.
I'm sure the issue is in the way I try to bind the Parameter properties, but I'm not able to figure out the correct syntax. Any idea on how to get the result (I can't believe this can't be done... ).
Thanks for any help you can provide
As you may guess my idea was trying to find a workaround for the "you can't bind ConverterParameter" issue.
After further research on internet I found this post:
Bindable Converter Parameter
from this ntg123 guy. It actually solves my problem allowing to somehow bind the ConverterParameter to multiple sources using a syntax almost identical to the standard one.
It is based on a custom MarkupExtension and works really well in situations where Multibinding is not possible.

StoryBoard object becomes read-only when set by a Style

I have an attached behavior that has a single attached property of type StoryBoard. I want to set this property on every item in a ListView. The XAML looks something like this:
<Grid>
<Grid.Resources>
<Storyboard x:Key="TheAnimation" x:Shared="False">
<DoubleAnimation From="0.0" To="1.0" Duration="0:0:0.20"
Storyboard.TargetProperty="Opacity" />
</Storyboard>
</Grid.Resources>
<ListView>
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="local:MyBehavior.Animation"
Value="{StaticResource TheAnimation}" />
</Style>
</ListView.Resources>
</ListView>
</Grid>
So far so good. Then the code in 'MyBehavior' tries to do this:
private static void AnimationChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var listViewItem = d as ListViewItem;
if (d == null)
return;
var sb = e.NewValue as Storyboard;
if (sb == null)
return;
Storyboard.SetTarget(sb, listViewItem);
sb.Begin();
}
But an InvalidOperationException is thrown on the call to StoryBoard.SetTarget(): "Cannot set a property on object 'System.Windows.Media.Animation.Storyboard' because it is in a read-only state." If I inspect the Storyboard in the debugger, I can see that both its IsSealed and IsFrozen properties are set to true.
By contrast, if I set MyBehavior.Animation directly on the ListView so that I don't need to use a Style, the StoryBoard arrives unsealed and I am able to set the target and run it successfully. But that's not where I want it.
Why is my StoryBoard being sealed, and is there anything I can do to prevent this?
Update: I can solve my problem by adding this right after the null check:
if(sb.IsSealed)
sb = sb.Clone();
But I'm still curious what's going on. Apparently something somewhere (Style? Setter?) is freezing/sealing the object in Setter.Value.
I'm far from an expert in WPF, so I cannot explain the finer details of why this was the choice Microsoft made. But as I understand it, the main issue is that the object that is declared as a resource is likely to be shared with multiple other objects. As such, you are prevented from modifying it.
If you still want to go the resources route, it is possible that you can treat the resource as {DynamicResource...} instead of {StaticResource...} and that might allow you to modify the object that's been used for some other object. As I said, I'm not an expert in WPF and I admit to still being a bit cloudy on the different between DynamicResource and StaticResource, but I have a vague recollection that it addresses this scenario. :)
I've done some research on this, and think I've worked out most of what's going on. The short answer is that this behavior is by design. The MSDN Styling and Templating page for .net 4.0 says flat-out that "once a style has been applied, it is sealed and cannot be changed." Comments with Style.IsSealed back this up. But that's the Style itself; I'm dealing with an object contained in a Style's Setter's Value. Well, Style.Seal seals all its Setters, and Setter.Seal seals its Value. With that info in hand (head), none of what happened here is particularly shocking. But there's still no explanation for why all this sealing is being done in the first place. There are claims here and here that it is related to thread safety. That seems reasonable, but I would speculate further that, if all objects that consume a particular Style share a single Style object (and I don't know if that's the case or not), the sealing might be done for the simple reason that you don't want one consumer modifying the Style and accidentally changing everyone else.
All this seems to mean that there is no general solution to the problem, and it will need to be solved on a case-by-case basis. In my case, the solution was simply to clone the Storyboard and then operate on that clone.

What does exactly <Expander Header="{Binding}"> do?

While creating a simple custom expander, I encountered the problem where items inside IT wouldn't bind. I found the fix on this link:
http://codeoverload.wordpress.com/2012/03/04/wpf-expander-headertemplates-dont-forget-the-binding/
Which happens to treat that exact same issue, however what I understand from it is "found this by luck, not really sure why it worked ;D"
My question being now: why does adding Header={Binding} fixes the issue. Indeed from the fact binding wouldn't work, it seems it's due to the DataContext, but I don't see how this should fix it.
Thanks for explaining; hopefully this isn't a duplicate >.<
From the docs
Gets or sets the data used for the header of each control.
That object being a binding against the DataContext, or plain text, or whatever.
I'd bet the implementation looks to see if the value is text, and if so, throws it into the default header template which could be something as simple as
<TextBlock Text="{Binding}" />
If you declare a template for the header, the DataContext will be whatever you assign to the Header property. The DataContext of the Expander doesn't flow automatically to the header template, apparently.

How can I prevent flickering when binding a boolean to the visibility of a control

I have a boolean property in my ViewModel, named lets say IsNotSupported that is used to show some warning information if a sensor is not supported. Therefore I use a BooleanToVisibilityConverter, that is added in the ressources:
<phone:PhoneApplicationPage.Resources>
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</phone:PhoneApplicationPage.Resources>
and bind it to the stackpanel containing the warning:
<StackPanel x:Name="NotSupportedWarning" Visibility="{Binding IsNotSupported,
Converter={StaticResource BooleanToVisibilityConverter}}">
That works all quite well, but when loading the page, and the sensor is supported, the warning appears for just a fraction of a second and disappears afterwards. I know that this flickering is caused by the binding not having happened yet and therefore defaulting to visible.
That flicker it is annoying as hell... It should rather default to collapsed and be made visible only after it is clear that the warning should be shown. Also, this would avoid a second layouting pass after the binding and could therefore have positive performance impacts.
I had this problem over and over, and found nothing about it in the internet until I found this SO question, that is closely related, but is not found if searched for windows phone instead of silverlight. Both the problem and the solution might seem simple, but I really bugged me quite a long time, so I thought it might be a good idea to write a Q&A-style question about it to help others that are facing the same issue.
The solution is simple after you have seen it. You can control the default value of the binding (if the binding didnt happen yet) with FallbackValue. Your stackpanel XAML would look like:
<StackPanel x:Name="NotSupportedWarning" Visibility="{Binding IsNotSupported,
FallbackValue=Collapsed,
Converter={StaticResource BooleanToVisibilityConverter}}">
This way you get rid of the flicker and it does not have to be relayouted after the binding, if the warning stays hidden.
you can bind directly to a Visibility type of property instead of boolean and keep that property to collapsed by default plus you can implement INotifyPropertyChanged

Categories

Resources