Set Text on combobox while getting data - wpf

I'm trying to display a default text in a ComboBox while I'm fetching data from a source, but it doesn't show anything.
<ComboBox
Grid.Row="1"
Grid.Column="2"
Text="Hepper"
ItemsSource="{Binding Builds}"
SelectedItem="{Binding SelectedBuild}"
DisplayMemberPath="VersionNo"
IsReadOnly="True"
IsEnabled="{Binding SelectedBuildEnable}"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="180"
Height="30"
MinWidth="180" />

you can try to set the ComboBox.SelectedValue Property instead of ComboBox.Text.
I prefer to show another TextBlock above the ComboBox to display a default text:
<!-- don't forget to define the converter in your resources -->
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</UserControl.Resources>
<!-- your Control -->
<ComboBox
Grid.Row="1"
Grid.Column="2"
x:Name="ComboBoxElement"
ItemsSource="{Binding Builds}"
SelectedItem="{Binding SelectedBuild}"
DisplayMemberPath="VersionNo"
IsReadOnly="True"
IsEnabled="{Binding SelectedBuildEnable}"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="180"
Height="30"
MinWidth="180" />
<TextBlock
Grid.Row="1"
Grid.Column="2"
Visibility="{Binding IsEnabled, ElementName=ComboBoxElement, Converter={StaticResource BooleanToVisibilityConverter}}"
IsHitTestVisible="False"
Text="Hepper"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Margin="15,5" />
I guessed that your ComboBox becomes enabled if the data is fetched. Otherwise you have to use another binding for the visibility.

According to MSDN, the ComboBox.Text property
Gets or sets the text of the currently selected item.
Therefore, you could temporarily add an item into your ComboBox with your required message, select it and then remove it before filling the ComboBox when your data arrives.

Related

Overriding parent control's datacontext with local datacontext

I have a Groupbox in which i have multiple Textboxes. All these Textbox derive their Datacontext from that of Groupbox but one of the Textbox in the group needs a different Datacontext.
<GroupBox Header="My Group" Height="150" Width="1132" DataContext="{Binding ContextA}" >
<Grid>
<Label x:Name="lblA" Content="Policy Number:" Margin="6,12,970,92" />
<TextBox x:Name="txtbA" Margin="155,12,0,0" HorizontalAlignment="Left" Height="24" TextWrapping="Wrap" Text="{Binding ValueA}" VerticalAlignment="Top" Width="278" Grid.ColumnSpan="2"/>
<Label x:Name="lblB" Content="Policy Type:" Margin="612,10,334,88" Height="30"/>
<TextBox x:Name="txtbB" Margin="801,12,0,0" HorizontalAlignment="Left" Height="24" TextWrapping="Wrap" DataContext="{Binding ContextB}" Text="{Binding ValueB}" VerticalAlignment="Top" Width="278"/>
</Grid>
</GroupBox>
In the above code txtbA uses the Datacontext same as that of Groupbox.
I want txtbB to have a separate Datacontexti.e. ContextB
But the ContextB is not getting assigned to txtbB. How to solve the problem?
Note:
ContextAand ContextB= list of Entity Framework models.
WPF binding engine look for property in current DataContext. So, in your case binding engine is looking for property ContextB in class ContextA since textBox is inheriting DataContext from parent GroupBox.
What you can do is use more verbose definition for ContextA like this:
<GroupBox Header="My Group" Height="150" Width="1132"
DataContext="{Binding}"> <-- HERE Or can remove setting DC altogether.
<Grid>
<Label x:Name="lblA" Content="Policy Number:" Margin="6,12,970,92" />
<TextBox x:Name="txtbA" Margin="155,12,0,0" HorizontalAlignment="Left"
Height="24" TextWrapping="Wrap"
Text="{Binding ContextA.ValueA}" <-- HERE
VerticalAlignment="Top"
Width="278" Grid.ColumnSpan="2"/>
<Label x:Name="lblB" Content="Policy Type:" Margin="612,10,334,88"
Height="30"/>
<TextBox x:Name="txtbB" Margin="801,12,0,0" HorizontalAlignment="Left"
Height="24"
TextWrapping="Wrap" DataContext="{Binding ContextB}"
Text="{Binding ValueB}" VerticalAlignment="Top" Width="278"/>
</Grid>
</GroupBox>

datatemplate listbox selected item

here's my xaml:
<Window x:Class="WpfTest.Search"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Search" Height="600" Width="1024">
<Window.Resources>
<DataTemplate x:Key="listBoxTemplate" xmlns:ns="clr-namespace:MyConverters">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<ns:ImageConverter x:Key="MyImageConverter" />
</StackPanel.Resources>
<Image Source="{Binding Path=thumb, StringFormat=/WpfTest;component/Images/{0}, Converter={StaticResource MyImageConverter}}" Height="100" Width="130" Margin="5"></Image>
<StackPanel Orientation="Vertical" Width="247">
<TextBlock Text="{Binding recipeName}" Height="60" Padding="15" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Center"></TextBlock>
<TextBlock Text="{Binding cuisine}" Height="60" Padding="15" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox Margin="12,96,0,0" Name="lstSearchResult" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="704" Height="445" ItemsSource="{Binding Tables[0]}" ItemTemplate="{StaticResource listBoxTemplate}" SelectionChanged="lstSearchResult_SelectionChanged">
</ListBox>
<TextBox Height="31" HorizontalAlignment="Left" Margin="12,49,0,0" Name="txtSearchRecipe" VerticalAlignment="Top" Width="518" FontSize="16" />
<Button Content="Search" Height="31" HorizontalAlignment="Left" Margin="555,49,0,0" Name="btnSearchRecipe" VerticalAlignment="Top" Width="161" Click="btnSearchRecipe_Click" />
</Grid>
</Window>
now i want to open a new form based on the item I clicked on the listbox, passing the new form the data from the selected item's textblock. how do i do that?
If I'm reading this correctly you don't need to do anything special to access the TextBlock controls in the DataTemplate. You just need to take advantage of your bindings by adding a SelectedItem binding using TwoWay binding to your ListBox.
If you're using MVVM, I would suggest you map a Command on your button click event to your View Model passing the SelectedItem as the command parameter. Then, in the command handler, cast the SelectedItem to the type you expect (this should be the type of object in the collection you've bound to your ListBox ItemsSource). You can then send the properties bound to the TextBlocks to the view model of your new window. If setup propertly these items should exist in your SelectedItem. Then set the window's DataContext to the corresponding window viewmodel and show it.
If you're just using code behind, simply cast the SelectedItem to the type used in the ListBox ItemsSource collection. Then pass the properties bound to the TextBlocks to the new window. Then show the window.

How do I Raise an Event when the Binding is completed?

I have a TextBox in my application that i am developing and the binding is done in the xaml
I want to be able to raise an event when the binding of the TextBox Text Property is completed meaning when the text is loaded/changed through binding into the TextBox how do i achive this?
I tried TextChanged Event also Loaded Event but no luck right after the Binding is complected so how do i do it?
<ListBox x:Name="listBoxCategories" Background="Transparent" BorderThickness="0" Grid.Row="4" Grid.ColumnSpan="2" Margin="0" Padding="0" ItemContainerStyle="{StaticResource ListBoxItemStyle}" ItemsSource="{Binding ElementName=discussion_categoryDomainDataSource, Path=Data}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="stackPanelCategory" Orientation="Vertical" Margin="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBlock x:Name="TextBlockCategoryId" Text="{Binding Path=CategoryID}" />
<toolkit:Expander IsExpanded="True" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Style="{StaticResource ForumExpanderStyleRight}">
<toolkit:Expander.Header>
<TextBlock FontSize="16" FontWeight="Bold" Foreground="White" Margin="4,0,4,0" Text="{Binding CategoryName}" LayoutUpdated="TextBlock_LayoutUpdated" />
</toolkit:Expander.Header>
<ListBox x:Name="listBoxBoards" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Transparent" BorderThickness="0" Margin="0" Padding="0" ItemContainerStyle="{StaticResource ListBoxItemStyle}" ItemsSource="{Binding CategoryBoards}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0" HorizontalAlignment="Stretch" x:Name="GridBoard">
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</toolkit:Expander>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
at this line
<TextBlock x:Name="TextBlockCategoryId" Text="{Binding Path=CategoryID}" />
I want an event where when the Binding is completed i want to give a different data source for the list box under the parent stack panel so i need the binding event so when i have the catedory id int he text block which later will be hidden in the xaml ( which now is not collapsed for testing reasons )
This is a slightly peculiar thing to want to do, it might help if you tell us why you are wanting to do this?
However, with no other information to hand, I will propose a solution.
If the TextBox API events do not provide the infomation you need, try handing the LayoutUpdated event. This event fires each time layout occurs, which is typically as elements ae added to the visual tree. WHen this event fires inspect your TextBox.Text property to see if it is set.
This solved the problem for me :)
<TextBlock FontSize="16" FontWeight="Bold" Foreground="White" Margin="4,0,4,0" Text="{Binding CategoryName}" Loaded="TextBlock_Loaded" />
Loaded event in the inner Text block rather than the upper textblock because by the time this is loaded the upper text block's text is already bound so i can retrive the ID :)

Binding inside listbox itemtemplate problems

I have two separate binding problems with listboxes with an itemtemplate which contains a texbox.
1) One listbox binds to a list of strings. How can I display each string inside the textboxes created and allow two way binding at the same time? Two way binding isn't allowed without specifying a Path or XPath.
<ListBox Height="231" HorizontalAlignment="Left" Margin="0,167,0,0" Name="listBoxKeys" VerticalAlignment="Top" Width="219" ItemsSource="{Binding Path=SelectedPlatform.Keys}" SelectedItem="{Binding Path=SelectedKey,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<TextBox Text="{Binding Mode=OneWay}" Margin="0,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And 2) I use another listbox which binds to some generic list of a custom KeyValuePair class. The itemtemplate contains a textbox and combobox. The textbox text is bound to the key property of each KeyValuePair object and the combobox selecteditem to the value property. My problem is that I want the combo to get filled by a list of strings declared in my viewmodel which will be changing on runtime. The window's datacontext is the viewmodel where the list is declared. I don't know the exact syntax I need to use to bind the combobox itemssource there. Here's my code :
<ListBox Height="393" HorizontalAlignment="Left" Margin="0,72,0,0" Name="listBoxActions" VerticalAlignment="Top" Width="254" ItemsSource="{Binding Path=SelectedPlayer.ControlProfile.MappedActions}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<TextBox Text="{Binding Key, Mode=TwoWay,UpdateSourceTrigger=LostFocus}" Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<ComboBox Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center" ItemsSource="{Binding ?}" SelectedItem="{Binding Value, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem is that the two-way binding on the source itself cannot work because it would mean that the whole object (string), for which the data template is created, must be replaced when user changes the text in the text box. Obviously, this will not work. Two-way binding will work only on a writable property of the bound object.
In your case I would suggest creating a view model for the items in the list box (basically a view model for your strings) and expose a Value property on it and bind to it in the data template:
<ListBox Height="231" HorizontalAlignment="Left" Margin="0,167,0,0"
Name="listBoxKeys" VerticalAlignment="Top" Width="219"
ItemsSource="{Binding Path=SelectedPlatform.KeyViewModels}"
SelectedItem="{Binding Path=SelectedKey,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<TextBox Text="{Binding Value, Mode=TwoWay}" Margin="0,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
1) Pavlo Glazkov seems to have a good answer to me
2) This is down to the DataContext for the ComboBox now being the key value pair rather than the ViewModel. There may be other ways to do this but the one that I've used before is to set the bindings RelativeSource source back to it's parent ItemsControl.
RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}
Something like:
<ListBox Height="393" HorizontalAlignment="Left" Margin="0,72,0,0" Name="listBoxActions" VerticalAlignment="Top" Width="254" ItemsSource="{Binding Path=SelectedPlayer.ControlProfile.MappedActions}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<TextBox Text="{Binding Key, Mode=TwoWay,UpdateSourceTrigger=LostFocus}" Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<ComboBox Margin="10,0,0,0" Height="Auto" MinWidth="80" MaxWidth="80" HorizontalAlignment="Left" VerticalAlignment="Center" ItemsSource="{Binding DataContext.Keys, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" SelectedItem="{Binding Value, Mode=TwoWay}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Binding ComboBox Item with a text property of different DataContext

I have a ComboBox as below. What I want is to bind the SelectedItem value to a Text property of a DataContext so that another DataTemplate can show the Image. Please note that the ComboBox and target Image elements are on two different DataTemplates so that's why I need to update the Text property (ImageName) of DataContext in the backend.
<ComboBox x:Name="cboOverlay" Grid.Row="0" Grid.Column="1" SelectedIndex="0" >
<ComboBoxItem Name="BC_OL" IsSelected="True">
<StackPanel Orientation="Horizontal">
<Image Source="Images\BC_OL.jpg" Width="100" Height="25" Canvas.Top="0" Canvas.Left="0" />
<TextBlock Width="100" VerticalAlignment="Center" TextAlignment="Center"><Bold>Image1</Bold></TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem Name="Indian_OL">
<StackPanel Orientation="Horizontal">
<Image Source="Images\Indian_OL.jpg" Width="100" Height="25" Canvas.Top="0" Canvas.Left="0" />
<TextBlock Width="100" VerticalAlignment="Center" TextAlignment="Center"><Bold>Image2</Bold></TextBlock>
</StackPanel>
</ComboBoxItem>
</ComboBox>
<Image Source="{Binding Path=Image}" Width="81" Height="25" Canvas.Top="0" Canvas.Left="0" />
You can set each item to have a specific data context.
I'm not sure in your xaml which item you are trying to set, I think it's the last line the
<Image Source="{Binding Path=Image' ... />
You can just specify the data context for that control.
Edit In reponse to comments
Since you are trying to get the selected item from the combo box and trying to send that over to the image, why not just pass it in as a value into the class that is holding the image.
I think you could do this in xaml but I'm not entirely sure how to do it.
It seems like you're trying to do something like this:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<DockPanel>
<TextBox DockPanel.Dock="Top" x:Name="Source">x1</TextBox>
<ComboBox DockPanel.Dock="Top" x:Name="myComboBox"
SelectedValue="{Binding ElementName=Source, Path=Text, Mode=TwoWay}">
<sys:String>1</sys:String>
<sys:String>22</sys:String>
<sys:String>333</sys:String>
<sys:String>4444</sys:String>
</ComboBox>
<TextBlock DockPanel.Dock="Top"
Text="{Binding ElementName=myComboBox, Mode=OneWay, Path=SelectedItem.Length}"/>
</DockPanel>
</Page>
The ComboBox is bound to the text of the TextBox using two-way binding, so when you select an item from the ComboBox it updates the TextBox, and when you type a value into the TextBox that's in the ComboBox's list it changes the selected item in the ComboBox.
The TextBlock is bound to a property of the selected item in the ComboBox. Whenever the selected item changes, whether because the user selected a new one or the value in the TextBox changed, the TextBlock gets updated.
But I'm confused by all your talk about data contexts. None of the objects in the example you posted have data contexts.

Resources