WPF Issues with binding to styled button - c#

I have created a RadioButton style which I use across my application. The display part of which uses the content presenter to display whatever content I added to the button:
<ContentPresenter>
<ContentPresenter.ContentTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{TemplateBinding Content}" />
</Grid>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
I'm then attempting to bind a decimal with a string formatter to the styled button like so:
<RadioButton Content="{Binding Stake, StringFormat={}{0:C}}" Style="{DynamicResource NeutralSelectorButtonStyle}" />
Stake is a decimal within a ViewModel which is set as the DataContext. When I run this up the content coming through is blank.
I made a change using a label in the DataTemplate rather than a TextBlock, this displayed the decimal but had not formatted it.
Can anyone explain why this is happening and possibly provide a solution.
If you require any more information just ask :)
Thanks in advance.

You are almost there just instead of setting the string format inside binding you should use ContentStringFormat property when in ContentControls.
Take a look at this Label (it works with any content control):
<Label Content="{Binding Path=MaxLevelofInvestment}" ContentStringFormat="Amount is {0}"/>
ContentPresenter also has this property:
http://msdn.microsoft.com/en-us/library/system.windows.controls.contentpresenter.contentstringformat%28v=vs.110%29.aspx
Try it out. I hope it works for you.

Related

ContentPresenter in ItemControl.ItemTemplate to show displaymemberpath of itemscontrol

I want to know is there anyway to put contentpresenter in itemtemplate of an itemscontrol to display my data. I don't want hard code binding like Text="{Binding username}" cause I am building a custom control, I think ContentPresenter is what I want. But after I tried using contentpresenter, it give me stackoverflowexception.
<ItemsControl ItemsSource="{Binding SelectedItems, ElementName=listbox}" DisplayMemberPath={Binding DisplayMemberPath}">
<ItemsControl.ItemPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="Separator" Text=", "/>
<ContentPresenter/>
<!--<TextBlock Text="{Binding username}"/>-->
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
That's my code.
If without those seperator and itemtemplate, I able to display my data by just using the displaymemberpath, but it stack all the name together. I still finding any solution to solve it. I hope you can provide some ideas to do this.
The answer is no, you can't. A ContentPresenter is supposed to be used in a ControlTemplate, not a DataTemplate, so it is not the right control to use. From the linked page on MSDN:
You typically use the ContentPresenter in the ControlTemplate of a ContentControl to specify where the content is to be added.
What you can do alternatively, is to declare a number of DataTemplates in a Resources section (complete with Binding Paths) for different types of data and omit the x:Key directives, eg. do not name them. Also, do not specify one for the ItemsControl.ItemTemplate.
When doing this, WPF will implicitly select the correct DataTemplate for the relevant data type and so you can have different outputs for different data types. See the The DataType Property section of the Data Templating Overview page on MSDN for further explanation of this technique.
Yes, and it works well. Outside of a ContentControl's template, you must bind the Content by hand:
<ContentPresenter Content="{Binding username}"/>
I do this a great deal and it never misbehaves. ContentPresenter seems to be implemented for general use. I wonder if the API docs overstate its relationship to ContentControl.
I found an easier way to solve this problem by using horizontal listbox. Thanks for responses

Forcing a ListBox to re-render

Background:
I have a ListBox containing items defined by DataTemplates. Right now, if an object in the list has the property IsEditable set to true, the item's property information will be displayed inside of textboxes (via DataTemplate change), instead of textblocks (so the user can edit the content of that list item)
IsEditable is toggled on/off by a button inside of each list item. I have been told that we need to keep the state of all objects consistent, which means I can't just rebind the ItemsSource and lose everything.
Currently, I'm using this to re-render:
this.lbPoints.Dispatcher.Invoke(DispatcherPriority.Render, new Action(() => { }));
Question:
The aforementioned code snippet KIND OF does its job. By "kind of", I mean, it does eventually cause my data to become re-rendered, but only when I scroll to the bottom of the list and then scroll back up to the item i'm trying to re-render.
1) How can I re-render the data immediately without having to scroll around to get it to show up?
The guys commenting are right that you're going about this the wrong way... there is rarely a need to force a ListBox to re-render. You're probably causing yourself some additional grief trying to switch the DataTemplates (although it is possible). Instead of that, think about data binding the TextBox.IsReadOnly property to your IsEditable property:
<TextBox IsReadOnly="{Binding IsEditable}" Text="{Binding Text}" />
Another alternative is to use a BooleanToVisibilityConverter to show a different Grid in your DataTemplate when your IsEditable property is true. Unfortunately, that Converter doesn't have an inverse operation, so you could create an IsNotEditing property to bind to the Grid in the DataTemplate that is originally displayed. I'm not sure if that's clear... see this example:
<DataTemplate DataType="{x:Type YourPrefix:YourDataType}">
<Grid>
<Grid Visibility="{Binding IsNotEditing, Converter={StaticResource
BooleanToVisibilityConverter}}">
<!-- Define your uneditable UI here -->
</Grid>
<Grid Visibility="{Binding IsEditing, Converter={StaticResource
BooleanToVisibilityConverter}}">
<!-- Define your editable UI here -->
</Grid>
</Grid>
</DataTemplate>
You could also define your own BooleanToVisibilityConverter class that has an IsInverted property, so that you can just use the one IsEditing property. You'd need to declare two Converters still, like this:
<Converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<Converters:BoolToVisibilityConverter x:Key="InvertedBoolToVisibilityConverter"
IsInverted="True" />
Then your XAML would be like this:
<Grid Visibility="{Binding IsEditing, Converter={StaticResource
InvertedBoolToVisibilityConverter}}">
<!-- Define your uneditable UI here -->
</Grid>
<Grid Visibility="{Binding IsEditing, Converter={StaticResource
BoolToVisibilityConverter}}">
<!-- Define your editable UI here -->
</Grid>

Accessing a list picker inside a PanoramaHeader Template

I have a panorama control in which I have create a header template to add a list picker inside it. (Just like the peoples hub to select social accounts)
<DataTemplate x:Key="PanoramaItemHeaderTemplate">
<ContentPresenter>
<StackPanel Height="129">
<TextBlock Text="{Binding}" FontSize="72" Margin="0,7,0,0" />
<toolkit:ListPicker x:Name="listPick" Margin="0,-21,0,0" BorderThickness="0">
<toolkit:ListPickerItem Content="twitter"></toolkit:ListPickerItem>
</toolkit:ListPicker>
</StackPanel>
</ContentPresenter>
</DataTemplate>
The panorama control is inside the MainPage.xaml file and I want to have access to the listpicker from the code behind to be able to populate it, and handle it selection events.
I don't know how to do this. I tried adding the x:name property to the list picker I don't have access to it in the MainPage code behind.
Any idea on how to approach this is very welcomed, thanks!
From what you have now, the quickest way to do what you want is to traverse the visual tree
See here for the implementation:
How to access a specific item in a Listbox with DataTemplate?
You cannot access the ListPicker by x:Name because it is not unambiguous: there is a ListPicker generated for each PanoramaItem in your Panorama. So the first question is, is it really the think you want to do? If so you need to populate it using a binding (ItemSource)
You can access an element inside another resource, consider this example:
<Grid Name="myGrid">
<StackPanel x:Name="stack1">
<TextBlock x:Name="abc"/>
</StackPanel>
</Grid>
We can only access the Grid myGrid in code by default. To get reference to the StackPanel we can do this:
StackPanel myStack=myGrid.FindName("stack1") as Stackpanel;
After that we can get reference to the TextBlock:
TextBlock myTextBlock=myStack.FindName("abc") as TextBlock;
You can modify myTextBlock after that as you may like. You can apply the same technique in your case and it will work.
Hope that helps :).

Editing child objects of a combo box using c# and Wpf

Backgorund
I am currently writing a program that allows a user to select a manufacture from a combo box. The combo box is created in wpf using the following wpf code segment:
<ComboBox Height="23" Margin="40.422,128.423,229.908,0" Name="itemProductManufacture" ToolTip="Click to open drop down menu" VerticalAlignment="Top" Text="Select A Manufacture" SelectionChanged="itemProductManufacture_SelectionChanged" DropDownOpened="itemProductManufacture_DropDownOpened">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ManufactureId}" Width="0"/>
<Image Name="itemManufactureImage" Source="{Binding ManufactureImage}" Height="15" Width="70" Stretch="Uniform"/>
<TextBlock Text="{Binding ManufactureName}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The data is provided form a database and each entry has a Image, a name and an Id (intentionally not shown)
Problem
I am trying to code the behaviour of the combo box so when it is open the image height is 50 and when it is closed it is 15 this is so the image is larger when it is first displayed and then smaller once selected so it doesn't take up too much space on the form.
I have tried editing the image propities using code but am unable to accsess it using its name or any other children of the combo box.
Thanks
Jonathan
As you are using data template you won't be able to access the directly by its name.
Try something like this -
Image image = this.itemProductManufacture.ItemTemplate.FindName("itemManufactureImage", this) as Image;
One thing I am not clear is whether you want to change image size for all the items or the selected one? If you need to access the image for a particulat item in combobox you may have to use the ItemContainerGenerator.ContainerFromItem, as explained in following posts -
WPF - ItemsControl - How do I get find my "CheckBox" item that is in the ItemTemplate?
http://www.sitechno.com/Blog/HowToUseAttachedPropertiesAsAnExtensionMechanismForACheckedListbox.aspx
look at this, To know the various ways of finding controls - How can I find WPF controls by name or type?
You can edit image properties from code using binding. Or you can use triggers in Datatemplate. When comboboxitems checked properties change, you can change height property of corresponding image
Try this:
<Image Height = "{Binding Path=IsDropDownOpen,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ComboBox}},
Converter={StaticResource myBoolToHeightConverter}}" />
An example for Converter here

WPF Hyperlink Child

I have a WPF Hyperlink that I am able to click and get its NavigateUri property just fine. However, I want to be able to bundle some additional information with the Hyperlink so I can process it in my event handler. This is how it looks right now:
<TextBlock Grid.Row="0">
<Hyperlink ToolTip="{Binding Path=Contact.ToolTipPersonalEmail}"
Name="ContactHyperlink" Foreground="#FF333333"
RequestNavigate="HandleContactEmailClicked"
NavigateUri="{Binding Path=Contact.Email}"
>
<TextBlock Text="{Binding Path=Contact.Fullname}" Width="Auto"
HorizontalAlignment="Stretch"
TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{Binding Path=Data1}" Name="data1" Visibility="Collapsed" />
<TextBlock Text="{Binding Path=Data2}" Name="data2" Visibility="Collapsed" />
</Hyperlink>
</TextBlock>
Basically, in my event handler, I want to be able to access the data inside the two textblocks that have visibility = "Collapsed" (data1 and data2). I liken this to "hidden" data in an HTML form.
I tried messing with the "Inlines" property of Hyperlink but that's not working, and since this is inside a DataTemplate I can't access data1 and data2 by name in my code.
Any ideas?
Thanks.
creating textblocks to hold that data is somewhat... overkill. I'd go with one of these two options:
use databinding, to place a specific
object into the hyperlink, then to
get it back, all you need to do, is
access the DataContext of the
hyperlink,and it will provide you
the class which holds data1 and
data2
attach the object which
populates data1 and data2 into the
Hyperlink's TAG attribute
In your event handler you can do something like this:
ContentPresenter presenter = (ContentPresenter)sender.TemplatedParent;
DataTemplate template = presenter.ContentTemplate;
TextBlock textBlock = (TextBlock)template.FindName("data1", presenter);
Probably not the prettiest way, but it works for me.

Categories

Resources