XAML Binding path to variable - c#

I need to bind the text property of a text box to an item stored in a Dictionary and I have to get it by dictonary's key name , but the problem is that the name is binding in the Tag property and I have no more information since it is built by a static resource into a style
This would be what I want to do:
In the code behind:
Dictionary<string,string> filters = new Dictionary...... ;
In XAML
<Style TargetType="{x:Type DataGridColumnHeader}" x:Key="StyleName">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Tag="{Binding}" Text="{Binding Path=filters[Tag]}", Mode= TwoWay}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
In this case Tag in "filter[Tag]" is not a dictionary's key but a property Tag of Textbox.
Does somebody know if it is possible to do that? or another way to build. this?
Thanks.

Related

Attached property always has a default value in a style

I'm working with WPF and I want to use attached properties to work with some styling things in the validation of the controls (my example of the problem is really simple, binding a simple text).
This is my attached property:
public class ToolTipExtension
{
public static readonly DependencyProperty ShowToolTipProperty = DependencyProperty.RegisterAttached(
"ShowToolTip", typeof(string), typeof(ToolTipExtension), new PropertyMetadata("Deffault"));
public static void SetShowToolTip(DependencyObject element, string value)
{
element.SetValue(ShowToolTipProperty, value);
}
public static string GetShowToolTip(DependencyObject element)
{
return (string) element.GetValue(ShowToolTipProperty);
}
}
I have a simple style dictionary like this
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:at="clr-namespace:CarpetaTecnicaWPF.AttachedProperties"
>
<Style TargetType="{x:Type TextBox}" x:Key="Blah" >
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(at:ToolTipExtension.ShowToolTip)}" FontSize="50"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
As you can see, I'm trying to bind the Text property to my attached property.
In my Page, I'm using the style like this:
<TextBox Style="{StaticResource Blah}" at:ToolTipExtension.ShowToolTip="Prueba?"/>
The thing is, the value Prueba? does not appear. When I inspect the tree, I see this:
But in runtime, the result of the binding is Deffault
What am I doing wrong?
Your binding is incorrect.
The TemplatedParent in this case is not what you actually need. The ControlTemplate for the error is not applied to the text box itself, it's a stand-alone control template. So you are just getting a default value from a wrong FrameworkElement.
To access the text box your error template is applied to, you need to use the AdornedElementPlaceholder in your ControlTemplate. From that AdornedElementPlaceholder, you can access your text box via the AdornedElement property.
Here is an example:
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<AdornedElementPlaceholder x:Name="adorner"/>
<TextBlock Text="{Binding ElementName=adorner, Path=AdornedElement.(at:ToolTipExtension.ShowToolTip)}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>

TabControl - ToggleButtons as TabSeletors (XAML-Only Logic)

Currently I have a set of ToggleButtons.
I would like to show a different Tab of my TabControl depending on which button is checked. Basically the same bahaviour like when a differnet Tab is selected. Not sure if my needs are nonsense but anyways. I want the SelectedTab to change depending on which button is clicked. Moreover my ToggleButtons are RadioButtons stlyed to Togglebuttons (I only want one to be checked at a time). I want to try to achieve my needs only in XAML (if even possible).
So here's part of my XAML:
<Window.Resources>
<sys:Int32 x:Key="CurrentTab"></sys:Int32>
<Style TargetType="RadioButton" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="Aqua"></Setter>
</Trigger>
</Style.Triggers>
<Setter Property="Background" Value="Transparent"></Setter>
</Style>
</Window.Resources>
<TabControl Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
SelectedIndex="{StaticResource CurrentTab}">
<TabItem Visibility="Collapsed"></TabItem>
<TabItem Visibility="Collapsed"></TabItem>
</TabControl>
What I was thinking of would be something like (pseudoCode):
<Setter Target="{StaticResource CurrentTab}" Value="{ButtonsToolTip}></Setter>
Basically is it even possible to assign values to variables in XAML and if it is - how ?
As an example on why and what I try to achieve is something like this GUI:
You cannot change value of a primitive type declared as resource using xaml. But you can use a property of an object to act as your variable. Eg;
<sys:Int32 x:Key="IntKey">12</sys:Int32>
is non-modifiable using XAML. But, Value property of DictionaryEntry (shown below) is modifiable, despite the fact that like int(IntKey), DEKey is non-modifiable too.
<coll:DictionaryEntry x:Key="DEKey" Key="TagKey" Value="100"/>
If I try to change integer(IntKey) via binding , it won't allow. Eg; <TextBox Text="{Binding Mode=OneWay,Source={StaticResource IntKey}}"/> , Mode must be OneWay. TwoWay, OneWayToSource values are not allowed.
But I can write
<TextBox Text="{Binding Value,Source={StaticResource DEKey}}"/>
and any textbox value will be updated in Value of DictionaryEntry(DEKey). Note, two-way binding won't work as DictionaryEntry is not a DependencyObject. But you can now change your variable (Value property) the way you like. But only concern is : changes to Value property will not be reflected back in bounded control.
Yes, you can make use of above information to show Tabs w.r.t. radiobuttons with approach given below. For binding to work properly both ways, we need a DependencyObject and a DependencyProperty, so we use FrameworkElement and its Tag property.
This Tag property now mimics your Variable in question.
<Window.Resources>
<FrameworkElement x:Key="rbTagHolder" Tag="0"/>
</Window.Resources>
...
<ItemsControl x:Name="RadioButtonList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding TabName}" Tag="{Binding TagValue}" GroupName="Choice">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction TargetObject="{DynamicResource rbTagHolder}" PropertyName="Tag" Value="{Binding Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type RadioButton} }}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</RadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
...
<TabControl x:Name="TabCtrl" SelectedIndex="{Binding Tag, Source={StaticResource rbTagHolder}}"> ... </TabControl>
Code-behind
RadioButtonList.ItemsSource = new[] { new { TabName = "Tab1", TagValue = "0" }, new { TabName = "Tab2", TagValue = "1" },
new { TabName = "Tab3", TagValue = "2" }, new { TabName = "Tab4", TagValue = "3" }};
Just in case you don't know how to use Blend Behaviors.
A. Include following namespaces :
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
B. Add references to : Microsoft.Expression.Interactions, System.Windows.Interactivity On my system these are found in
C:\Program Files (x86)\Microsoft SDKs\Expression\Blend.NETFramework\v4.0\Libraries
There is no way to change the value of a StaticResource with an Event trigger in XAML alone. This will have to be done by binding your StaticResource to a ViewModel's property or using code behind.

WPF Tab Data Template - Controls retain values when new tabs are created

I have a problem with the WPF tab control.
I have a TabControl, with the ItemsSource bound to an ObservableCollection. I created a data template for the header/content portion of the tabs. The content portion contains a custom control, with a bunch of labels and text boxes. For the text boxes that are editable when a new tab is created that data carries over and appears in the new tab. Not sure if it's a problem with my XAML or something in the view model. Here's my code for the XAML:
<UserControl.Resources>
<DataTemplate x:Key="TabItemHeaderTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding AdFile.Name}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="TabItemContentTemplate">
<MyView:MyCustomControl/>
</DataTemplate>
<Style x:Key="TabItemContainerStyle" TargetType="TabItem">
<Setter Property="Header" Value="{Binding}"/>
<Setter Property="HeaderTemplate"
Value="{StaticResource TabItemHeaderTemplate}"/>
<Setter Property="Content" Value="{Binding}"/>
<Setter Property="ContentTemplate"
Value="{StaticResource TabItemContentTemplate}"/>
</Style>
</UserControl.Resources>
<TabControl Grid.Row="3" ItemsSource="{Binding OpenedFiles}" x:Name="_myTabControl" SelectedItem="{Binding Path=CurrentDataControlViewModel, Mode=TwoWay}" SelectionChanged="TabControlSelectionChanged" ItemContainerStyle="{StaticResource TabItemContainerStyle}"/>
Not sure what other information I should provide. Maybe this is a common problem and I am just not setting something up correctly? Basically I just want to be able to create a new instance of the control for every tab...
Thanks in advance.
It sounds as though your ViewModel is a Singleton, being cloned, or you're trying to populate the new tab with the existing ViewModel.
If you're using MEF, remember to set the [PartCreationPolicy] attribute to NonShared.

WPF listbox. Skip underscore symbols in strings

I have some WPF ListBox which is dynamically populating with items. Something like this :
ListBox.Items.Add
(new ListBoxItem { Content = new CheckBox { IsChecked = true, Content = "string_string"} );
The problem is with checkbox content. It's showing on GUI like "stringstring"...
How to escape the "_" symbols ? (I get strings dynamically)
You can add the text in a TextBlock and put that TextBlock inside your Chekbox, TextBlock does not support _ mnemonic characters. Here's what I mean, in xaml, but you can easily convert this to code:
<CheckBox IsChecked="True">
<TextBlock>string_string</TextBlock>
</CheckBox>
The default template for the CheckBox contains a ContentPresenter whose RecognizesAccessKey is set to true. If the content is a string (which it is in your case), then the ContentPresenter creates an AccessText element to display the text. That element hides the underscore until the Alt key is pressed because it will treat it as a mnemonic. You can either retemplate the CheckBox such that its ContentPresenter's RecognizesAccessKey is false or better yet just provide a DataTemplate as the ContentTemplate which contains a TextBlock. If you're not sure if the content will be a string then you can set the ContentTemplateSelector and in code provide a DataTemplate which contains a TextBlock only if the item is a string. e.g.
<ListBox xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ListBox.Resources>
<DataTemplate DataType="sys:String" x:Key="stringTemplate">
<TextBlock Text="{Binding}" />
</DataTemplate>
<Style TargetType="CheckBox">
<Setter Property="ContentTemplate" Value="{StaticResource stringTemplate}" />
</Style>
</ListBox.Resources>
<ListBoxItem>
<CheckBox Content="A_B" ContentTemplate="{StaticResource stringTemplate}"/>
<!-- Or use the implicit style to set the ContentTemplate -->
<CheckBox Content="A_B" />
</ListBoxItem>
</ListBox>
Use a double underscore string__string, since in WPF, the _ is the mnemonic character.
Even better, just solve this issue in xaml and create a collection in your view model (or code-behind).
I had the same problem in a DataGrid. Similarly to AndrewS, I added a style for TextBlock, but did not use DataTemplate or ContentTemplate. This way the setters in ColumnHeaderStyle were applied :) However, this solution works only for single underscores, eg. "a_b", but not for "a__b".
<DataGrid>
<DataGrid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding}"/>
</Style>
</DataGrid.Resources>
<DataGrid.ColumnHeaderStyle>
<!-- my setters here do not get overridden -->
</DataGrid.ColumnHeaderStyle>
</DataGrid>

How can I swap controls based on a dependency property?

I am creating a custom control.
I want the template for this control to use different controls for the root control based on the value of a dependency property called CanExpand. CanExpand is defined in the custom control class.
If CanExpand is true, I want to display using an Expander:
<ControlTemplate ...>
<Expander ...>
<!--...-->
<ContentPresenter/>
</Expander>
</ControlTemplate>
If CanExpand is false, I want to display using a HeaderedContentControl instead:
<ControlTemplate ...>
<HeaderedContentControl ...>
<!--...-->
<ContentPresenter/>
</HeaderedContentControl>
</ControlTemplate>
I thought of using a DataTemplateSelector, but this is a ControlTemplate not a DataTemplate and there is no selector property for the Template of a control.
I can't set the different controls to visible/hidden with a Trigger because the child content can only live under one control. Also, I don't think you can change the Content property using a Trigger.
Any suggestions?
Thanks.
Inside your Style, set the ControlTemplate property for the default state and then have a Trigger which sets the ControlTemplate property to a different template. For example:
<Style ...>
<Setter Property="ControlTemplate">
<ControlTemplate ...>
</ControlTemplate>
</Setter>
<Style.Triggers>
<Trigger Property="YourProperty" Value="WhateverValue">
<Setter Property="ControlTemplate">
<ControlTemplate ...>
</ControlTemplate>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Keep in mind you can have a trigger on the same property for multiple values, each value getting a completely different template.

Categories

Resources