Binding in DynamicResource ResourceKey wpf mvvm - c#

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?

Related

How to change style for a single LayoutDocument?

Suppose I have this xaml:
<avalonDock:DockingManager>
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Horizontal">
<avalonDock:LayoutDocumentPaneGroup>
<avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocument Title="Main Panel">
</avalonDock:LayoutDocument>
</avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocument Title="Panel 02">
</avalonDock:LayoutDocument>
</avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocument Title="Panel 03">
</avalonDock:LayoutDocument>
</avalonDock:LayoutDocumentPane>
<!--
Other LayoutDocumentPane's here...
-->
</avalonDock:LayoutDocumentPaneGroup>
</avalonDock:LayoutPanel>
</avalonDock:LayoutRoot>
</avalonDock:DockingManager>
Now I need put a different style only for "Main Panel", by example, a red background. All other panels ("Panel 02", "Panel 03", etc...) must be unchanged. All samples I found are to change the entire theme, but I need change only one LayoutDocument element.
You need to use DataTemplates, TemplateSelector, or Converters and you need to give them something that can differantiate between the items you want to change and those you do not want to change.
A WPF Converter on the style property could, for example, use the Title (if its unique across your app) to return a corresponding style for each document. But this would be a very poor implementation - use an enumeration property in the class to make this one more robust.
An even better solution is the usage of a TemplateSelector based on a class hierarchy of inherating classes over your document viewmodel - but this is more involved - but there are some samples to look at: Here is one that does the same for LayoutAnchorables.
You might simply change the Style of LayoutDocument adding a DataTrigger that would change background color basing on a property set on your ViewModel.
That property should be set to true (if the logic behind is binary but should be more complex if needed) just on the ViewModel of your MainPanel.
Please have a look to the Theme.xaml of AvalonDock and search for <Style TargetType="{x:Type avalonDockControls:LayoutDocumentTabItem}">. Inside that style you can easily access The ViewModel binded to any TabItem by simply access {Binding LayoutItem.Model.<my_property>

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.

Force Refreshing WPF Bindings (one source)

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.

DisplayMemberPath Behavior

I was wandering if someone can explain to me how the Dependency Property DisplayMemberPath works?
I am trying to create Custom ItemsControl that has property like DisplayMemberPath of a ComboBox, in otherwords after setting the ItemsSource I want to be able to specify the Property to Display.
At the moment if I do somthing like:
<cc:MyControl ... DisplayMemberPath="MyObjectDescription" ... >
(Yes I have overridden the DisplayMemberPath, its besides the point).
It displays a list of items, but they each Display "MyObjectDescription", instead of the value that that Property holds for each object in the ItemsSource.
And I believe its because I am missing something in regards to how DisplayMemberPath Property works.
Thanks All. :)
There are two types of DisplayMemberPath. One that supports Binding and one where you have to set a string value. In your case as I can see you wish to implement the second one. To do so create a property inside your custom control of type string and name it DisplayMemberPath. Override the methode OnInitialized in your container with your custom logic where you tell the container to manipulate the path of the binding to DataContext by changing binding's path to the string value as you specified in DisplayMemeberPath. WPF calls OnInitalized once any control is completely initalized but before its about to get rendered. I hope this helps you any futher.
I'm assuming your control is like MyControl and MyControlItem like ListBox and ListBoxItem.
You can access the DisplayMemberPath of MyControl when the MyControlItem is being created and use it to get the data from the DataContext.
Bit late to party, but maybe other could be helped
If your purpose is barely to use Itemscontrol over ListBox/View, you may consider to define the Datatemplate for the itemscontrol's Items instead of packing this in a Usercontrol:
<ItemsControl ItemsSource="{Binding myObjectCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding myObjectProp}"/> (or whatever...)
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Accessing inner controls of UserControl

I am building a custom UserControl which would allow me to place text inside a ProgressBar. The problem is, none of the ProgressBar's DependencyProperties get transferred over. Here is the XAML for my custom UserControl.
<UserControl
x:Class = "MyProgram.MyCustomProgressBar"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid>
<ProgressBar Name="uiProgressBar" />
<Label Name="uiLabel" />
</Grid>
</UserControl>
How can I access and set the Minimum, Maximum, Value, etc. from XAML when I start using this UseControl.
<local:MyCustomProgressBar x:Name="uiLoadTime" ??.uiProgressBar.Maximum="50" />
I am hoping I don't need to redefine a bunch of DependencyProperties in order to get this functionality.
The usual way is to use a DependencyProperty... it's not so bad once you got used to it really.
Use the "propdp" built in snippet in the code-behind of your usercontrol.
Let's take the ProgressBar.Maximum example:
Make an integer dependencyproperty with a default value of 100 (or whatever you like), name it InnerProgressBarMax.
In your UserControl's XAML, you bind it this way:
<ProgressBar Maximum="{Binding InnerProgressBarMax, ElementName=myUsrCtrl}" />
When you use the control in another part of your application, simply enter a value like this:
<local:MyCustomProgressBar x:Name="uiLoadTime" InnerProgressBarMax="50" />
Rinse & repeat for each property you want to expose.
Edit:
If you really need to have 50+ DP exposed, you could bring down the hastle by specifying smart default values for your DPs.
To do that, when you create a DP, set the parameter of new PropertyMetadata(YOUR_DEFAULT_VALUE)
Once that is done, your control may expose many DPs, but you'll only have to set a few manually in the XAML code that uses the control.
The alternative to wrapping everything in DependencyProperties is to let the UserControl's consumer provide the ProgressBar. It could look like this:
<local:MyCustomProgressBar x:Name="uiLoadTime">
<local:MyCustomProgressBar.ProgressBar>
<ProgressBar Maximum="50" />
</local:MyCustomProgressBar.ProgressBar>
</local:MyCustomProgressBar>
Then in MyCustomProgressBar.xaml.cs, you would expose a public property for a ProgressBar. In its setter, modify the properties however you see fit, then add it to the UserControl's root Grid.

Categories

Resources