TargetUpdated does not work - c#

I have a ListBox that is defined like this
<ListBox ItemsSource="{Binding List, ElementName=UI}" x:Name="listBox" SelectionChanged="listBox_SelectionChanged" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="grid1" Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding ItemId}"/>
<TextBlock Grid.Column="1" Text="{Binding Message, NotifyOnTargetUpdated=True}" TargetUpdated="TextBlock_TargetUpdated"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The app has a search feature, that allows the user to search for certain text (also a substring) in the list (in column 1, which is bound to 'Message').
The matched substring shall be highlighted as bold or italic.
I'm planning to use the inline feature of the TextBlock. Therefore I want to use the TargetUpdated callback to parse the contend of the TextBlock to insert e.g. Bold() or Italic().
My problem is, that the CallBack function TextBlock_TargetUpdated is not called.
Any idea why?

I realized, that I was missing a NotifyPropertyChanged("Message"); in the class that represents the data in the attached list.

Related

C# WPF Get Selected Combobox Binding Fields

I have a combo box that has a data template with 3 fields bound from a data table.
The problem I have is I want to find out which item I have selected in the combobox and get access to one of the bound fields.
The SelectedIndex gives me the position but I want the id so I can pass that directly to the Insert method.
You can see below I have 3 fields on for each combo box item.
I would like to identify the primary key for the selected item, "uid"
<ComboBox Name="cboCombo" Width="300" Height="42" TabIndex="3"
ItemTemplate="{StaticResource ComboBoxKey}"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
SelectedValuePath="uid"
FontSize="12"/>
<DataTemplate x:Key="ComboBoxKey}"">
<Grid Height="35" Width="300" ShowGridLines="false">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="75"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding uid
Style="{StaticResource txtStyle}"></TextBlock>
<TextBlock Grid.Column="1" Text="{Binding field_1}"
Style="{StaticResource txtStyle}"
TextWrapping="Wrap"></TextBlock>
<TextBlock Grid.Column="2" Text="{Binding field_2}"
Style="{StaticResource txtStyle}"></TextBlock>
</Grid>
</DataTemplate>
I think i've got it:
DataRowView dr = (DataRowView)cboComboBox.SelectedItem;

WPF ListBox Layout (dynamic column width considering all rows at once)

Is there a way to make sure that the Width="auto" property considers the Width of all elements in a list instead of calculating it individually for every row in the list?
<ListBox x:Name="listBox" HorizontalContentAlignment="Stretch" DockPanel.Dock="Top">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" />
<TextBlock Grid.Column="1" Text="{Binding Value}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I tried this, but as the length of the Name is different for each column, the Width of the Name column of every row is different. Thus the second column starts at a different x position.
You can use SharedSizeGroup property in the ColumnDefinition like this:
<ColumnDefinition SharedSizeGroup="A"/>
Also have a look at this: Grid Size Sharing in WPF.

How to Bind all ListBox's Items to the same Property?

I have a ListBox with the following DataTemplate:
<DataTemplate x:Key="ItemTmp">
<Border Name="Border" BorderBrush="Aqua" BorderThickness="1" Padding="5" Margin="5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Item1}"></TextBlock>
<TextBlock Grid.Column="1" Text="{Binding Path=Item2}"></TextBlock>
<TextBox Grid.Column="2" Text="{Binding Path=UpdatedGrade,UpdateSourceTrigger=LostFocus,Mode=TwoWay }" />
</Grid>
</Border>
</DataTemplate>
</UserControl.Resources>
Means, I want that everytime user writes something in one of the text boxes , it will update the same field in the ViewModel - UpdatedGrade , problem is that it doesn't work.
When I just bind a single TextBox to this field, it does works, for example:
TextBox Grid.Row="3" Text="{Binding Path=UpdatedGrade,UpdateSourceTrigger=LostFocus,Mode=TwoWay }"></TextBox>
Does anyone have any idea how can I do it?
The DataContext of a ListBox item is of the individual item in the collection, so it's trying to find to a Property of that item.
As long as this is not a windows store app, you can do something like this:
Text="{Binding Path=DataContext.UpdatedGrade, UpdateSourceTrigger=LostFocus, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=UserControl}}"
with win8 apps you can't find ancestor as easily, so you'd have to give the name of the element that contains the context
Text="{Binding Path=DataContext.UpdatedGrade, UpdateSourceTrigger=LostFocus, Mode=TwoWay, ElementName=MyUserControl}"
I'm unsure of how this would act--binding directly to the textbox--it might update UpdatedGrade in the DataContext, but again, I'm not sure.
Text="{Binding Path=Text, UpdateSourceTrigger=LostFocus, Mode=TwoWay, ElementName=MyTextBox}"

Address individual objects in an ItemsControl template in silverlight & C#

I have a silverlight application with an ItemsControl which shows a list of items with values and units assigned to them...
Some DataType 1.8 XY
Datatype2 15.6 Units
Other Datatype 1.8 XTZ
The issue I have is that the units are custom and hence I cannot know in advance how long they will be and I need them to line up as shown. So, on the fly, I want to address each of the unit textblocks, find the one with the largest width and set the rest to the same (or set the column to that width).
How can I address each of the textblocks generated in the items control individually in C#?
Here is the xaml so far
<ItemsControl Name="DataTypesGrid" ItemsSource="{Binding}" Margin="0" BorderBrush="{x:Null}" Foreground="White" Background="{x:Null}" IsEnabled="True">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Margin="0,2,0,0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Left" Grid.Column="0" FontSize="15" />
<TextBlock Text="{Binding Value}" HorizontalAlignment="Right" Margin="0,0,4,0" FontSize="15" Grid.Column="1" />
<TextBlock Text="{Binding Unit}" HorizontalAlignment="Left" FontSize="15" Grid.Column="2" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Thanks for the help
Cap
First get hold of the code for the VisualTreeEnumeration extension methods from here.
Now add a Name property to your unit TextBlock in the data template Name="unitText".
Given the presence of the VisualTreeEnumeration extension methods you can now create a "query" for the boxes:-
IEnumerable<TextBlock> unitBlocks = DataTypesGrid.Descendents()
.OfType<TextBlock>()
.Where(t => t.Name == "unitText");
You can hang on to unitBlocks for as long as DataTypesGrid exists. Using For Each on it will return the latest contents of the ItemsControl. You can use .ToList() on it if you need to temporarily create a List<TextBlock>.

How could I make this display for listbox?

I have a databound listbox which is actually displaying two columns of data. It is displayed as follows:
<UserControl.Resources>
<DataTemplate x:Key="AlignedPairs">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Fruits}" Grid.Column="0" />
<TextBlock Text="->" TextAlignment="Center" Grid.Column="1" />
<TextBlock Text="{Binding Colors}" Grid.Column="3" />
</Grid>
</DataTemplate>
</UserControl.Resources>
<ListBox Name="lbStuff" Grid.ColumnSpan="2" Grid.Row="1"
ItemTemplate="{StaticResource AlignedPairs}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Then Itemsource set in codebehind.
Based on some logic however, I would like to set either a line or a item in one of the columns, e.g. a fruit to red, or the line to bold. I have code to work out which Fruit or Color I would like to differentiate (by color/bold) in the code behind, but I can't figure out, especially given the custom listbox display, how I could go about setting a particular item to a different color/bold.
Does anyone have any ideas?
Let me know if any further code is required. Cheers.
edit: all I really want to be able to do is make the problem as easy as possible... loop through each item in the listbox and check with a string, if there is a match SOMEHOW visually distinguish this item in the listbox/listview. There is no need to make this any more complicated than it needs to be. Why you are not able to individually set an items foreground color is beyond me!
edit 2:
It looks like I almost get there with the following (but it throws exception and doesn't work)
foreach (var li in ListView.Items)
{
if (someCriteria == true)
{
((ListViewItem) li).Foreground = Brushes.Red;
//exception throw as this is the actual object stored in this location (the Fruit object for example) not the row or listviewitem I want to change the color of so it can't be cast :(
}
}
This is where the ViewModel design pattern really helps you out.
Presumably you have a class that exposes the properties Fruit and Color. Make a wrapper class that exposes both those properties and also exposes, say, FruitBackgroundBrush and ItemBackgroundBrush. Then you can just bind to those properties in your template, e.g.:
<DataTemplate x:Key="AlignedPairs">
<Grid Background={Binding ItemBackgroundBrush}>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Fruits}"
Background="{Binding FruitBackgroundBrush}"
Grid.Column="0" />
<TextBlock Text="->" TextAlignment="Center" Grid.Column="1" />
<TextBlock Text="{Binding Colors}" Grid.Column="3" />
</Grid>
</DataTemplate>
DataTriggers will take care of this. Here's a good primer: http://en.csharp-online.net/WPF_Styles_and_Control_Templates%E2%80%94Data_Triggers

Categories