datatemplate listbox selected item - wpf

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.

Related

How to remove element from collection at child control level

I've created UserControl for adding/removing attributes using the buttons. It has ItemsControl with ObservableCollection of attributes bound to it as a ViewModel and button for adding new attribute to collection. Each new attribute creates an entity in collection which is also a UserControl with bound attribute ViewModel and button for deleting itself.
I wanted to write this functionality so the single attribute control (and other controls) can be reusable - and I use it in a few places. Currently adding new attributes works properly, but I can't find any working way for delete button to work properly and remove object from the collection.
I tried to refer through this.Parent, but CustomAttributeControl's parent is null, I tried to refer through Tag or use Prism.Core, but I couldn't implement anything properly for this to work and I couldn't find anyone with similar nested controls problem to base on. It's easy when there is no nested control for single attribute, but here I can't come up with anything. I'm fairly new to WPF and I feel there should be an easy way to do this.
single attribute control
attribute control's XAML:
<UserControl x:Class="xxx.UI.CustomAttributeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:models="clr-namespace:xxx.ViewModels.Attributes"
mc:Ignorable="d" >
<DockPanel Width="auto" HorizontalAlignment="Stretch" Margin="0,2">
<TextBox Text="{Binding Name}" Height="20" TextWrapping="Wrap" Width="160"/>
<TextBlock Width="60"/>
<ComboBox x:Name="DataType" Height="20" Width="120" SelectionChanged="DataType_SelectionChanged"/>
<TextBlock Width="10"/>
<TextBox Text="{Binding ListValues}" x:Name="ListValues" Height="20" TextWrapping="Wrap" Width="120"/>
<DockPanel HorizontalAlignment="Right">
<CheckBox IsChecked="{Binding Visible}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="20,0"/>
<Button x:Name="Delete" Content="X" Width="22" Height="20" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="20,0"/>
</DockPanel>
</DockPanel>
</UserControl>
list control
list control's XAML:
<UserControl x:Class="xxx.UI.CustomAttributesControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:xxx.UI"
mc:Ignorable="d">
<StackPanel>
<Label FontSize="20">Custom attributes</Label>
<StackPanel>
<DockPanel HorizontalAlignment="Stretch">
<Label Width="160" HorizontalAlignment="Left" HorizontalContentAlignment="Center">Attribute name</Label>
<TextBlock Width="60"/>
<Label Width="120" HorizontalAlignment="Left" HorizontalContentAlignment="Center">Attribute type</Label>
<TextBlock Width="10"/>
<Label Width="120" HorizontalAlignment="Left" HorizontalContentAlignment="Center">List values</Label>
<DockPanel HorizontalAlignment="Right">
<Label Width="60" HorizontalAlignment="Right" HorizontalContentAlignment="Center">Visible</Label>
<Label Width="60" HorizontalAlignment="Right" HorizontalContentAlignment="Center">Delete</Label>
</DockPanel>
</DockPanel>
<ItemsControl ItemsSource="{Binding}"> <!-- it's binding ObservableCollection of custom attributes from parent control -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:CustomAttributeControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<DockPanel HorizontalAlignment="Right">
<Button Margin="20,10" Click="AddAttribute">+ Add attribute</Button>
</DockPanel>
</StackPanel>
</StackPanel>
</UserControl>
Code for adding attribute in .xaml.cs:
private void AddAttribute(object sender, RoutedEventArgs e)
{
var attributes = (ObservableCollection<CustomAttribute>)DataContext;
attributes.Add(new CustomAttribute());
}

Listview DataTemplate inter UserControl unable to binding

I have this problem:
I have a ListView control in the form. There is a CustomControl in the DataTemplate of this ListView. I want this custom control to be bound to the Time property in the ViewModel of the current form, but it cannot be bound, but the DataTemplate Other controls in the middle can be bound, what is going on? I will be very grateful
Here is my window:
<ListView Grid.Row="2"
ItemsSource="{Binding PlanRotation}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="20 0 0 0" Orientation="Horizontal">
<TextBlock HorizontalAlignment="Center" Text="时间:" VerticalAlignment="Center" FontWeight="Bold" />
<TimeControl:DateTimePicker Tag="{Binding ElementName=myWin,Path=DataContext.Time,Mode=OneWayToSource}"
HorizontalAlignment="Center"
Height="28"
VerticalAlignment="Center"
Width="152"
Foreground="White"
BorderThickness="1"
BorderBrush="#FFABADB3"
Background="Black"
Grid.Column="1"/>
<ComboBox Text="{Binding ElementName=myWin,Path=DataContext.Scenes,Mode=OneWayToSource}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="80"
Height="21">
</ComboBox>
Here is my CustomControl TimeControl:DateTimePicker code:
<UserControl x:Class="ManagementProject.UserControls.TimeControl.DateTimePicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ManagementProject.UserControls.TimeControl"
xmlns:myTime="clr-namespace:ManagementProject.UserControls.TimeControl"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="25"
d:DesignWidth="150"
Width="150"
MaxHeight="25"
x:Name="dtpName"
Loaded="UserControl_Loaded" Tag="{Binding ElementName=textBlock1, Path=Text}">
<TextBox
Height="23"
HorizontalAlignment="Left"
Text="{Binding ElementName=dtpName,Path=Tag,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}"
Margin="4,3,0,0"
Name="textBlock1"
VerticalAlignment="Top"
Width="123" Foreground="White" Background="{x:Null}" BorderBrush="{x:Null}" SelectionBrush="{x:Null}" Style="{DynamicResource TextBoxStyle1}" />
My Custom control's TextBox's Text is assignment in the background.
I could only get straight up binding to work with a user control when it initialized. I ended up created a dependency property to be able to update the user control from outside it.
internal List<User> ContactlistContainer
{
get => (List<User>)GetValue(ContactlistContainerProperty);
set => SetValue(ContactlistContainerProperty, value);
}
internal static readonly DependencyProperty ContactlistContainerProperty =
DependencyProperty.Register("ContactlistContainerProperty", typeof(List<User>), typeof(User), new PropertyMetadata(new List<User>()));

how to bind .xml file content on a label stored on a url

i have an xml file ,i am trying to bind it to a label but not successfull yet,i used an xmldataprovider to bind it.here is the code for the template i used.,there are several task in my xml file,i am trying to bind the 1st one.
<Window.Resources>
<XmlDataProvider x:Key="TaskList" Source="http://store.tymesheet.com/templates/Graphic-Designer.xml" XPath="tasks"/>
<ControlTemplate x:Key="tasktemplate1">
<Canvas Height="40" Width="850">
<Label Content="{Binding XPath=task[1]}" Height="30" Width="170" Canvas.Top="5" Canvas.Left="150" Background="LightGray">
</Label>
<TextBox Height="30" Width="120" Canvas.Top="5" Canvas.Left="370" Background="AliceBlue"></TextBox>
<Label Canvas.Left="500" Canvas.Top="5">$</Label>
<Button Canvas.Top="8" Height="10" Width="30" Canvas.Left="600" ></Button>
</Canvas>
</ControlTemplate>
</Window.Resources>
and the code for the listbox where the template is used is here
<TabItem>
<Canvas Height="700" Width="850">
<ListBox ItemsSource="{Binding Path=TaskList}" x:Name="listBox" Height="700" Width="850">
<ListBoxItem Template="{StaticResource tasktemplate1}"/>
</ListBox>
</Canvas>
</TabItem>
i am not getting where my binding is going wrong,any help,thnx.
You can't set ItemsSource and manually add ListBoxItem at same time on ListBox. Either specify ItemsSource or add items based on your condition.
In your case if you want to show only first item, remove ItemsSource and set DataContext of ListBoxItem.
<ListBox x:Name="listBox" Height="700" Width="850">
<ListBoxItem DataContext="{Binding Source={StaticResource TaskList}}"
Template="{StaticResource tasktemplate1}"/>
</ListBox>

Set Text on combobox while getting data

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.

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