Force Refreshing WPF Bindings (one source) - c#

I have this situation:
A IsToolbarButtonsEnabledProperty DependencyProperties
A have plenty of other DependencyProperties in a class (a huge class, needs to be this way)
A serie of Buttons on a toolbar.
The (IsEnabled) property of each of these buttons is a function of (IsToolbarButtonsEnabledProperty) throught a special converter, the buttons a differenced by ConvertParameter ("PreviousButton", "NextButton"...)
Opacity="{Binding IsEnabled, RelativeSource={RelativeSource Self}, Converter={StaticResource OpacityBoolToIntConverter}, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Path=DPEnableLinks, Converter={StaticResource ToolButtonEnableConverter}, ConverterParameter='ZoomOut' }"
ToolButtonEnableConverter is a converter that compares ConverterParameter "PreviousButton" with other value of other dependency property (in class). I have to many DP to make one multivalueconverter, so I read them straight from my class ((MainWindow)App.Current.MainWindow;)
Questions
When I update other DPs the value isEnabled / Opacity, dont change. How to fix this?
Is there a general solution to make a Binding refresh everytime a DP changes.
(Repeating myself): I will be adding more and more DPs over time, so a MultiValueConverter seams odd.

One way to force the Binding to update is to create a (meaningless) property and add it to the Binding (using MultiBinding), and when you want to update your Binding you change that property, and all the Binding is updated.
I must add that the more "straightforward" way is to use MultiBinding to all the relevant properties. If you have way to many properties that you need to bind, maybe you should re-think if you can build this functionality some other way.

Related

WPF custom style TextBox "Text" two-way binding failed [duplicate]

Ok... this is leaving me scratching my head. I have two WPF controls--one's a user control and the other's a custom control. Let's call them UserFoo and CustomFoo. In the control template for CustomFoo, I use an instance of UserFoo which is a named part so I can get to it after the template is applied. That works fine.
Now both UserFoo and CustomFoo have a Text property defined on them (independently, i.e. not a shared DP using AddOwner. Don't ask...) that are both declared like this...
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(UserFoo), // The other is CustomFoo
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
null,
null,
true,
UpdateSourceTrigger.PropertyChanged
)
);
Notice specifically that the mode is set to TwoWay and the UpdateSourceTrigger is set to PropertyChanged, again for both.
So in the style template for CustomFoo, I want to bind CustomFoo's Text property as the source to the internal UserFoo's Text property. Normally, this is easy. You just set UserFoo's text property to "{TemplateBinding Text}" but for some reason it's only going one way (i.e. UserFoo is properly set from CustomFoo, but not the reverse), even though again, both DPs are set for two-way! However, when using a relative source binding instead of a template binding, it works great! Um... wha??
// This one works
Text="{Binding Text, RelativeSource={RelativeSource AncestorType={local:CustomFoo}}, Mode=TwoWay}"
// As does this too...
Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
// But not this one!
Text="{TemplateBinding Text}"
So what gives? What am I missing?
Found this forum post on MSDN: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/0bb3858c-30d6-4c3d-93bd-35ad0bb36bb4/
It says this:
A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with
{Binding RelativeSource={RelativeSource TemplatedParent}}
Note from OP: Contrary to what it says in the documentation, in actuality, it should be this...
{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}
I filed a complaint against the docs, and while they did add a sentence now stating they are always one-way, the code example still doesn't list the mode, but I guess it's better than nothing.)
The TemplateBinding transfers data from the templated parent to the property that is template bound. If you need to transfer data in the opposite direction or both ways, create a Binding with RelativeSource of TemplatedParent with the Mode property set to OneWayToSource or TwoWay.
More in: http://msdn.microsoft.com/en-us/library/ms742882.aspx
Looks like Mode=OneWay is one of the "Optimizations" of using a TemplateBinding
TemplateBinding does not support two-way binding, only Binding does that. Even with your BindsTwoWayBeDefault option, it won't support two-way binding.
More info can be found here, but to summarize:
However, a TemplateBinding can only
transfer data in one direction: from
the templated parent to the element
with the TemplateBinding. If you need
to transfer data in the opposite
direction or both ways, a Binding with
RelativeSource of TemplatedParent is
your only option. For example,
interaction with a TextBox or Slider
within a template will only change a
property on the templated parent if
you use a two-way Binding.

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.

Is a custom usercontrol created each time the datacontext changes?

This is more of a general question...
I have a user control that i've written (UserControl,not Custom Control). i'm using this control in the a DataGridColumn to provide lookup functionality..much like this:
<DataGridTemplate ColumnHeader="Company">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<lookupCtl:LookUpCTL SelectedCompany="{Binding Company, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
CompanyChangedCommand="{Binding DataContext.CompanyChangedCmd, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
What i'm noticing is that whenever the dataconext changes for the parent/containing control, the constructor of LookUpCTL is called. Is this expected behavior? Anyway to prevent this? as i don't see why this necessary...the single instance of the control should be able to refresh itself from the datacontext i think.
Edit: googling is not providing any clear answers...but from what i've read, it may be the Datagrid that's the issue. since my control is used in a datagrid, each time the grid's itemsource changes, does it destroy and recreate the controls? i can see sense in it doing so..but not sure if that is the reason for what i'm seeing. Assuming it is...is there a way to have the datagrid reuse instances of the usercontrol rather than create new ones when the datagrid's itemsource changes?
It does appear that the reason usercontrols used as DataTemplate columns for a datagrid are destroyed and recreated when the itemsource for the datagrid is changed. in my case the solution was to use a normal grid given that i had always 4 items in my list that was used as the itemsource for the grid. This is not ideal and not a solution for N-item lists..but in my case it vastly improved performance since my usercontrol performed some intensive datbase lookups on initialization to cache data.

Passing values to DataTemplates with attached properties

I'm utilizing a data grid which has three columns of type DataGridTemplateColumn. These columns share almost identical behaviors and, as a consequence, utilize almost identical templates. The templates are copy-paste with a few resources changed out.
I would like to refactor the templates in to a generic version which uses an attached property to provide the necessary data. I've tried this but have been unable to access the property from inside the CellTemplate.
Methods I've tried are:
Bindings using RelativeSource: TemplatedParent.
Bindings using RelativeSource with various AncestorTypes.
Adding FrameworkPropertyMetadataOptions.Inherits to the FrameworkPropertyMetadata of the attached property.
The CellTemplate seems to have an odd degree of separation from its surroundings. What am I missing. If nothing, what is the appropriate solution to this problem?
A code example from you would have been helpful, but assuming that you have attached your property to the DataGrid, you should be able to bind to it from the CellTemplate using the following (untested):
<TextBlock Text="{Binding Path=(YourNamespace:YourClassName.YourAttachedPropertyName),
RelativeSource={RelativeSource AncestorType=DataGrid}, FallbackValue=''}" />
If you attached the property to the DataGridTemplateColumn, you would use:
<TextBlock Text="{Binding Path=(YourNamespace:YourClassName.YourAttachedPropertyName),
RelativeSource={RelativeSource AncestorType=DataGridTemplateColumn}, FallbackValue=''}" />
The FallbackValue property is not required, but it's a good practice to use it to avoid binding errors if the binding source can't be found.

Binding in DynamicResource ResourceKey wpf mvvm

I want to bind the style of button on the basis of if else condition. I have created one string property in the viewmodel and bind to the button's style attribute like this:
<Button x:Name="copd" Content="COPD"
Command="{Binding COPDReadingsCommand}"
Style="{DynamicResource ResourceKey={Binding CheckCopd}}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="20" FontWeight="Bold" />
I am looping through the resourceDictionary and getting all the keys. Using if else i am changing the string property value(CheckCopd) in if else.
I am getting the desired values in if else but style is not getting applied to the button when I execute my application. It only displays the generic button style.
How to bind the DynamicResource ?
Kindly Suggest?
Thank You.
You cannot use bindings on the DynamicResource properties, as it does not derive from DependencyObject. You would either need to set the Style property directly from code-behind, or just use a Binding.
You could use a Style for the Button type, which has a DataTrigger based on a custom property that dynamically changes the look. But in this case, you need a single Style, which changes it's setters based on your condition. It would not allow you to change the Style property itself dynamically.
You can try this... I came up with a way to create a DynamicResourceBinding on which you can use a converter to achieve the results you want. (You theoretically could also just use styles and triggers, but I digress...)
How do you create a DynamicResourceBinding that supports Converters, StringFormat?

Categories

Resources