Access ListBoxItem-Controls from code-behind - silverlight

in my Silverlight 4 application I have a listbox for which I created an itemtemplate:
<DataTemplate x:Key="ItemTemplate">
<Grid Background="{StaticResource BrushCharacteristicListBoxItemBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="TextBlockCharacteristicName" Text="{Binding Name}" TextTrimming="WordEllipsis" ToolTipService.ToolTip="{Binding Name}" Margin="6,0,2,0" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock x:Name="TextBlockSeperator" Text="=" Grid.Column="1" VerticalAlignment="Center" />
<Border Grid.Column="2" HorizontalAlignment="Right" Margin="2,2,6,2" Background="{Binding FunctionState, Converter={StaticResource ConvertCharacteristicFunctionState2Color}}">
<TextBlock x:Name="TextBlockCharacteristicValue" Text="{Binding CalculatedValue, Converter={StaticResource ConvertDouble2Display}}" Padding="2,0" Foreground="{StaticResource BrushCharacteristicListBoxItemBackground}" ToolTipService.ToolTip="{Binding ValueOrFunc}" MaxWidth="72"/>
</Border>
</Grid>
</DataTemplate>
Now I want to access the Controls defined in the template (i.e. TextBlockCharacteristicName) from the code behind. I need this to manually adapt the size of the Controls, which can't be done in an other way.
I hooked into the LayoutUpdated event, but did not found a way to access the controls.
I have tried it with
((StackPanel)ListBoxCharacteristics.GetItemsHost()).Children
which gives me a the list of the ListBoxItems, but there seems to be no way to get the controls from there. Can anyway help me out with this problem?
Thanks in advance,
Frank

Get the small VisualTreeEnumeration chunk of code from this blog: Visual Tree Enumeration.
Now you can find your "TextBlockCharacteristicName" elements with this code:-
foreach (var textBlock in ListBoxCharacteristics.Descendents()
.OfType<TextBlock>()
.Where(t => t.Name == "TextBlockCharacteristicName") )
{
// Do stuff with each Text block.
}

Related

Bind to single object in viewmodel

I got this property in my viewmodel:
private PushPinModel selectedPushPinModel;
public PushPinModel SelectedPushPinModel
{
get { return selectedPushPinModel; }
set
{
selectedPushPinModel = value;
RaisePropertyChanged(() => SelectedPushPinModel);
}
}
And I want to bind the view to show which one is selected:
<ContentControl DataContext="{Binding SelectedPushPinModel}" VerticalAlignment="Top">
<ContentControl.ContentTemplate>
<DataTemplate>
<Grid Height="100" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="20*"/>
<RowDefinition Height="38*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="91*"/>
<ColumnDefinition Width="389*"/>
</Grid.ColumnDefinitions>
<Border Opacity="0.95" Width="480" Padding="0,0,0,0" BorderThickness="0" HorizontalAlignment="Left" BorderBrush="Transparent" Background="White" Grid.ColumnSpan="2" Grid.RowSpan="2"/>
<Image Width="70" Height="70" HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding Icon}" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" />
<TextBlock Text="{Binding Header}" Grid.Column="1" Grid.Row="0" Style="{StaticResource TextboxLabelStyle}"/>
<TextBlock Text="{Binding Body}" Grid.Column="1" Grid.Row="1" Style="{StaticResource DefaultTextBlockStyle}"/>
</Grid>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl >
However I can't get it to work. The bindings is not showing in the view and I'm not getting any binding errors. Is it the correct way to bind to a single object?
I much rather having it like this instead of binding directly with {Binding SelectedPushPinModel.Body} which more dirty.
Any suggestions how to accomplish this?
Thanks
Try this:
<Label Content="{Binding SelectedPushPinModel}" />
See what that gives you (if anything). Also, check the 'output' window for errors.
This line:
<ContentControl DataContext="{Binding SelectedPushPinModel}">
will only work if the DataContext for the ViewModel (Class) has been properly bound higher on the page. If it isn't then the Label binding provided above will show blank.
Solved it, replaced DataContext on the ContentControl with Content
<ContentControl Content="{Binding SelectedPushPinModel}" VerticalAlignment="Top">
Thanks to sircodesalot for pointing me to the right direction!

StackPanel expanding outside size of parent grid

I'm pretty new with WPF, so apologies if I'm missing something obvious. I have this template that is bound to items in an obs. collection. I'm trying to get it so that the 2nd column, the "test test..." part has a variable width that fills all the available space in the parent grid.
What I'm finding though, is that my code automatically shows all the text for that "test test..." text box as opposed to just binding to the available space in the grid, and instead creates the scroll bar that you see below.
I instead, want that "test test" to be cut off so that everything else fits so that no scroll bar appears (that when, if the user resizes the screen then that "test test..." textbox will automatically resize to fit the new space). Is there a way to do that?
My code for that template is as follows:
<DataTemplate x:Key="MainTemplate">
<Grid Margin="4" ClipToBounds="True">
<Grid.Resources>
<local:BooleanToHiddenVisibility x:Key="boolToVis"/>
</Grid.Resources>
<StackPanel Orientation="Vertical" ClipToBounds="True">
<Grid Width="Auto" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" Name="checkViewTextBox"/>
<TextBlock Grid.Column="1" Text="{Binding OriginalQuote}" FontWeight="Bold" TextTrimming="WordEllipsis" FontStyle="Italic" ClipToBounds="True"/>
<TextBlock Margin="10,0,0,0" Grid.Column="2" Text="plane :" FontWeight="SemiBold" Width="60"/>
<TextBlock Margin="5,0,0,0" Grid.Column="3" Text="{Binding Mid}" Width="40"/>
<TextBlock Margin="10,0,0,0" Grid.Column="4" Text="data2 :" FontWeight="SemiBold" Width="60"/>
<TextBlock Margin="5,0,0,0" Grid.Column="5" Text="{Binding MidTwo}" Width="40"/>
<TextBlock Margin="10,0,0,0" Grid.Column="6" Text="data3:" FontWeight="SemiBold" Width="60"/>
<TextBlock Margin="5,0,0,0" Grid.Column="7" Text="{Binding MidThree}" Width="40"/>
<Button Margin="10,0,0,0" Content="History" Grid.Column="8" Click="History_Click" Width="40"/>
</Grid>
<StackPanel Orientation="Horizontal" Visibility="{Binding Path=IsChecked, ElementName=checkViewTextBox, Converter={StaticResource boolToVis}}">
<StackPanel.Resources>
<Style BasedOn="{StaticResource tbstyle}" TargetType="{x:Type TextBlock}" />
</StackPanel.Resources>
<!--Other stuff thats working ok-->
</StackPanel>
</Grid>
</DataTemplate>
Any help is much appreciated!
P.S. I've been adding random proprieties hoping one will work, so if looks like I have random things on there, that's probably why....
Well, not sure it will help you but some words about WPF layout.
It has two steps: measure and arrange.
At the first stage, the control tries to calculate its desired state. StackPanel asks its children about their desired sizes. It does not limit their size. (TextBlock with the binding to OriginalQoute has no explicitly set width!)
At the second stage, control is arranged.
Stack panel is allowed to occupy the whole left space of the column but it arranges its children as if its size was unlimited, so TextBlock shows the text completely.
The question is how to limit the size of the TextBlock?
Try binding
<TextBlock Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=ActualWidth}"/>

Windows Phone 7 Silverlight DataTemplate HyperlinkButton content

I'm trying to make a list that is populated by external data and I have a datatemplate for it.
Each element of the list is composed of an image and two textblocks, and is linked to a specific page.
I'm trying to do this but when I wrap the structure with an HyperlinkButton, I just get a blank page.
I don't know if I'm doing something stupid wrong or it's not possible to have so many items in an HyperlinkButton. If it's not possible to do it this way, can someone guide me to the best solution to do this? Here's the code:
<Grid x:Name="ContentPanel" Margin="0,140,0,0" Background="White">
<ListBox HorizontalAlignment="Stretch" Name="itemList" VerticalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<HyperlinkButton>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="480">
<Grid.Background>
<ImageBrush ImageSource="/app;component/Images/degradat_cela.png" Stretch="UniformToFill" AlignmentY="Top" AlignmentX="Left" />
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="430*" />
</Grid.ColumnDefinitions>
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="38" Width="38" Grid.RowSpan="2" Grid.Column="0" Grid.Row="0" BorderThickness="1" BorderBrush="#FFFF003F" Padding="1">
<Image HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="listImage" Width="36" Height="36" Source="{Binding image}" />
</Border>
<TextBlock Margin="5 12 0 0" Grid.Column="1" Grid.Row="0" Name="title" Foreground="Black" Text="{Binding title}" FontWeight="Bold" FontSize="18" />
<TextBlock Margin="5 0 0 8" Grid.Column="1" Grid.Row="1" Name="description" Foreground="Black" Text="{Binding subtitle}" FontSize="14" />
</Grid>
</HyperlinkButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I will also accept any suggestions to make my code better, as I'm new to .NET and I probably don't do things the best way!
Remove the HyperlinkButton and instead use the SelectionChanged event of the ListBox. So add this property to your ListBox:
SelectionChanged="myListBox_SelectionChanged"
Then in your code behind do this:
private void myListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if ((sender as ListBox).SelectedIndex == -1)
return;
NavigationService.Navigate(new System.Uri(string.Format("/Drilldown.xaml?Index={0}",(sender as ListBox).SelectedIndex),System.UriKind.Relative));
}
This code assumes a drilldown page that uses a query string to change it's layout. This is just for example. If instead of index you wanted to reference some property of the bound item you could instead do something like this (assuming an ID property):
int itemID = ((sender as ListBox).SelectedItem as MyApp.Model.myItem).ID;
NavigationService.Navigate(new System.Uri(string.Format("/Drilldown.xaml?ID={0}",itemID),System.UriKind.Relative));

Combo Box with a button in the Items Template

I would like to add a button to the combobox ItemTemplate, that allows the user to click it and remove the clicked item.
This is what i have so far:
<dxe:ComboBoxEdit Name="cboUserCustomReports"
Width="300" Height="Auto"
Margin="0,5,0,5"
ItemsSource="{Binding Path=UserReportProfileList,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"
EditValue="{Binding Path=UserReportProfileID,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
ValueMember="UserReportProfileID"
DisplayMember="ReportName"
PopupClosed="cboUserCustomReports_PopupClosed">
<dxe:ComboBoxEdit.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="23"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding XPath=ReportName}"
VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
<Button Grid.Column="1"
Width="23" Height="23"
VerticalAlignment="Center" HorizontalAlignment="Right">
<Button.Template>
<ControlTemplate>
<Image Source="/RMSCommon;component/Resources/Delete.ico"></Image>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
</DataTemplate>
</dxe:ComboBoxEdit.ItemTemplate>
</dxe:ComboBoxEdit>
My problem is that my Displaymember is not showing in the TextBlock and only the image of the button template is showing.
Here is a picture of what it looks like:
How do i solve my problem?
Thanks
DisplayMember will not work if you have defined a DataTemplate. However I have seen that you have a TextBlock with a XPath-binding to ReportName. This should do the trick. Check this binding, I assume that there in is the mistake. Check the Visual Studio output-window for binding errors.
<TextBlock Grid.Column="0"
Text="{Binding XPath=ReportName}"
VerticalAlignment="Stretch" HorizontalAlignment
Are you shure that you need an XPath-binding? If you're not sure, try to replace Text="{Binding XPath=ReportName}" through Text="{Binding ReportName}". Maybe this is the only problem.

Having a heck of a time getting object property values into textboxes

I am new to the MVVM design pattern, and I am working on a project to automate shipping processes.
The particular problem that I am having is I have a UserControl (my EditShipmentView) which when it loads, assigns it's ViewModel to its DataContext. The ViewModel is passed a recordID which it uses to pull the entity that represents a shipment. It does this successfully, as I can see it in Mole (visualizer).
Below is a XAML fragment showing the first couple of TextBoxes, and what I thought the bindings should look like.
<local:SnazzyForm Background="#FF318AE1">
<Grid Margin="6,0,0,0">
<TabControl Style="{DynamicResource SnazzyTabControl}" TabStripPlacement="Left" Background="{x:Null}" BorderBrush="{x:Null}" Margin="0,0,0,50">
<TabItem Header="Overview" Style="{DynamicResource TransparentTabItems}">
<Grid Margin="6,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel DataContext="{Binding Path=ShipmentRecord}">
<TextBlock HorizontalAlignment="Left" Text="Contact Info" TextWrapping="Wrap" Style="{DynamicResource TitleText}"/>
<Path Fill="#FFFFB900" Stretch="Fill" HorizontalAlignment="Left" Width="200" Height="2" Data="M0,16.5 L278.5,16.5" Stroke="#FFFFB900"/>
<StackPanel Margin="0,10,0,0">
<Grid Margin="0,16,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".40*"/>
<ColumnDefinition Width=".60*"/>
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Right" Text="Company" TextWrapping="Wrap" VerticalAlignment="Top" Style="{DynamicResource FieldLabel}" TextAlignment="Right" Margin="0,2,9,0"/>
<TextBox Text="{Binding Path=CompanyName, Mode=TwoWay, UpdateSourceTrigger=LostFocus, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" TextWrapping="Wrap" d:LayoutOverrides="Height" Grid.Column="1"/>
</Grid>
<Grid Margin="0,16,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".40*"/>
<ColumnDefinition Width=".60*"/>
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Right" Text="Contact" TextWrapping="Wrap" VerticalAlignment="Top" Style="{DynamicResource FieldLabel}" TextAlignment="Right" Margin="0,2,9,0"/>
<TextBox Grid.Column="1" Text="{Binding Path=ContactName}" TextWrapping="Wrap" d:LayoutOverrides="Height"/>
</Grid>
So, to recap...
EditShipmentView (Inherits from SnazzyForm)
DataContext is EditShipmentViewModel
EditShipmentViewModel.ShipmentRecord is populated (successfully) with a shipment object
ShipmentRecord.CompanyName is a string which obviously should return the name of a company.
Keep in mind this is only my most recent attempt. Previously I have not bound the Stackpanels DataContext and had the Textboxes bound as such "{Binding Path=ShipmentRecord.CompanyName}", and what seems like a hundred different variations. What hair I have left is rapidly receding. Please, think of my hair, send help.
Cory
Show us your code? Chances are your view model is just not notifying the view when it changes. If your bindings are incorrect (not resolved) you will see output to that effect in Visual Studio's debug output window. Check that as well.
Make sure that EditShipmentViewModel (likely culprit) and ShipmentRecord implement INotifyPropertyChanged.
If the data is loaded after the initial view is setup, and the EditShipmentViewModel class doesn't raise a PropertyChanged event for ShipmentRecord, then the View (xaml) will never know to update the binding, and you'll see an empty string.

Resources