wpf binding issue with ItemsSource - wpf

<ItemsControl ItemsSource="{Binding DataViews}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<DataGrid MaxHeight="500" VerticalScrollBarVisibility="Auto" VerticalAlignment="Stretch" Margin="0,0,10,0" MaxColumnWidth="450"
RowStyle="{StaticResource DataGridRowSql}" Style="{StaticResource DataGridStyleSQL}"
ColumnHeaderStyle="{StaticResource StyleDataGridColumnHeaderDefault}" ItemsSource="{Binding}"
IsReadOnly="{Binding RelativeSource={RelativeSource AncestorType=Page},Path=Locked}"
RowEditEnding="DataGrid_RowEditEnding" >
<DataGrid.CommandBindings>
<CommandBinding Command="Copy" Executed="CommandBinding_Executed"></CommandBinding>
</DataGrid.CommandBindings>
<DataGrid.InputBindings>
<KeyBinding Key="C" Modifiers="Ctrl" Command="Copy"></KeyBinding>
</DataGrid.InputBindings>
</DataGrid>
<GridSplitter Background="Red" Height="10" HorizontalAlignment="Stretch" ResizeDirection="Rows" ResizeBehavior="PreviousAndNext"></GridSplitter>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel VerticalAlignment="Stretch"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
hi, I need to have the updated data in the DataGrid_RowEditEnding event, since the e.Row doesn't have the updated data, so I thought about adding <ItemsControl ItemsSource = "{Binding DataViews, Mode = TwoWay, UpdateSourceTrigger = PropertyChanged}" > but it doesn't work, where am I wrong?

You will get the updated value in the CellEditEnding event handler if you just set the UpdateSourceTrigger property of the bindings to PropertyChanged.
If you are using auto-generated columns, you could handle the AutoGeneratingColumn for the DataGrid to do this:
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
DataGridBoundColumn dataGridBoundColumn = e.Column as DataGridBoundColumn;
if (dataGridBoundColumn != null)
{
dataGridBoundColumn.Binding = new Binding(e.PropertyName) { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
}
}

Related

WPF display listview item in a Image control

I have a Listview and next to it an Image control. I have set CollectionOfCapturedImages for my Listview's ItemsSource.
public ObservableCollection<BitmapImage> CollectionOfCapturedImages { get; } = new ObservableCollection<BitmapImage>();
<ListView x:Name="testListView" ItemsSource="{Binding CollectionOfCapturedImages}" MouseLeftButtonDown="testListView_MouseLeftButtonDown" Height="345" Margin="567,10,10,0" VerticalAlignment="Top">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="1" HorizontalAlignment="Center" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding}" Height="150" Width="150"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
How could I display selected Listview item (BitmapImage) in my Image control?
I have tried to add MouseLeftButtonDown="testListView_MouseLeftButtonDown"
private void testListView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
newlyAddedImage.Source = testListView.SelectedItem;
}
how can I get this working?
Did you try to just bind the Source property of the Image to the SelectedItem property of the ListView?
<Image x:Name="newlyAddedImage" Source="{Binding SelectedItem, ElementName=testListView}" />

Binding to ViewModel instance from View

I have program which initializes PersonsViewModel in MainWindowViewModel's constructor.
public MainWindowViewModel()
{
PersonsViewModel viewModel = new PersonsViewModel();
}
In MainWindow.xaml, PersonsViewModel and PersonsView are connected.
<Window.Resources>
<DataTemplate DataType="{x:Type vm:PersonsViewModel}">
<vw:PersonsView />
</DataTemplate>
</Window.Resources>
I use viewModel as ItemsControl ItemsSource.
<ItemsControl ItemsSource="{Binding viewModel}" Margin="4" />
Now my program opens UserControl and I need to set instance of PersonsViewModel to UserControl.DataContext.
<UserControl.DataContext>
<vm:PersonsViewModel />
</UserControl.DataContext>
Am I creating a new instance of PersonsViewModel. If I am doing so, then how I can bind it to PersonsViewModel instance? Because I have following code in UserControl. I have PersonsList bound to ItemsSource and I need to bind Command to PersonsViewModel instance.
<ItemsControl ItemsSource="{Binding PersonsList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Width="50" Text="{Binding Name}" />
<Button Content="Ok" Width="20" Margin="3" Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}}, Path=DataContext.Command}" CommandParameter="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can remove the UserControl.DataContext and Add ItemsControl.ItemTemplate. Since each ItemsControl is bound to List of person viewmodel. Each item will get the viewmodel as its datacontext. Refer the below code.
<ItemsControl ItemsSource="{Binding ViewModels}" Margin="4">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type vm:PersonsViewModel}">
<vw:PersonsView />
</DataTemplate>
</ItemsControl.ItemTemplate>

Binding to the UserControl which contains the ItemControl data

I created a UserControl (MediaList) which contains an ItemControl which is binded to a property "ToolsBar". The idea is to allow to add custom button/controls from outside the MediaList control.
My problem is that i'm trying to add a button into the ToolsBar which have a binding to the UserControl itself. I don't override the DataContext of my MediaList (UserControl) to be "this" since i'm needing to use my DataModel which is defined in the root window.
Maybe the way I'm doing this is complety wrong?
Here is an exemple of the window which use a custom button to the MediaList :
<localControls:MediaList x:Name="NewMediaList">
<localControls:MediaList.ToolsBar>
<Button Content="{StaticResource ResourceKey=MoveToPlaylist}"
IsEnabled="{Binding ElementName=NewMediaList, Path=SelectedMedia, Converter={localConverters:ObjectToBool}}"/>
</localControls:MediaList.ToolsBar>
</localControls:MediaList>
Until now I tried multiple kind of binding without success such as :
{Binding ElementName=MediaListControl, Path=SelectedMedia, Converter={localConverters:ObjectToBool}}"
{Binding RelativeSource={x:Static RelativeSource.Self}, Path=SelectedMedia, Converter={localConverters:Debug}}
{Binding SelectedMedia, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}
{Binding SelectedMedia, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type localControls:MediaList}}}
Take note I write them back from my memory and that I also tried with (and without) setting the DataContext of the ItemControl and StackPanel (which contains the ItemControm) from MediaList.xaml to be the MediaList object itself.
MediaList.xaml:
<UserControl x:Class="MediaPlaylist.Controls.MediaList"
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:localConverters="clr-namespace:Suisse.MediaPlaylist.Converters"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
x:Name="MediaListControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid Grid.Row="0"
AutoGenerateColumns="False"
ItemsSource="{Binding ElementName=MediaListControl, Path=Playlist.Medias}"
SelectedItem="{Binding ElementName=MediaListControl, Path=SelectedMedia, Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTextColumn Header="Title"
Binding="{Binding Title}"
IsReadOnly="True"/>
<DataGridTextColumn Header="File"
Binding="{Binding FilePath}"
IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right"
Grid.Row="1">
<ItemsControl ItemsSource="{Binding ElementName=MediaListControl, Path=ToolsBar}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Separator Visibility="{Binding ElementName=MediaListControl, Path=ToolsBar.Count, Converter={localConverters:ObjectToVisibility}}" />
<Button
HorizontalAlignment="Right"
Content="Delete"
Click="OnDelete_Click"
IsEnabled="{Binding ElementName=MediaListControl, Path=SelectedMedia, Converter={localConverters:ObjectToBool}}"/>
</StackPanel>
</Grid>
Thanks
First, you are trying to assign binding data to ItemsSource property of ItemsControl, which is completely wrong.
Instead of that you can declare ItemsControl dependency property in your MedialList.xaml.cs
public partial class MediaList : UserControl
{
public MediaList()
{
InitializeComponent();
}
public static DependencyProperty ToolsBarProperty = DependencyProperty.
Register("ToolsBar", typeof(ItemsControl), typeof(MediaList));
public ItemsControl ToolsBar
{
get { return (ItemsControl)GetValue(ToolsBarProperty); }
set { SetValue(ToolsBarProperty, value); }
}
}
You can then update MediaList xaml as
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right"
Grid.Row="1">
<ContentControl Content="{Binding ElementName=MediaListControl, Path=ToolsBar}">
</ContentControl>
Then you can assign any collection template from outside to ToolBar property as
<localControls:MediaList>
<localControls:MediaList.ToolsBar>
<ItemsControl >
<ItemsControl.Items>
<Button Content="{StaticResource ResourceKey=MoveToPlaylist}"
IsEnabled="{Binding ElementName=NewMediaList, Path=SelectedMedia, Converter={localConverters:ObjectToBool}}"/>
<Label>Hello </Label>
<Label> How are you?</Label>
</ItemsControl.Items>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</localControls:MediaList.ToolsBar>
</localControls:MediaList>
Hope this will solve your problem.
Note: I have just moved out ItemsControl defined inside MediaList user control and replaced it with ContentControl. This allows to set any template from outside to Content property of ContentControl.

How to focus on combo box in wpf on Mouse Left button down?

<ComboBox TextSearch.TextPath="MemberFullName" IsEditable="True" Height="23" VerticalAlignment="Center" Grid.Row="1" Grid.Column="1" Margin="5,0,0,0" ItemsSource="{Binding MemberCollection}" SelectedItem="{Binding SelectedSearchMember,Mode=TwoWay,ValidatesOnDataErrors=True}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MemberFullName}" VerticalAlignment="Center"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
On Mouse Left Button Down it become Editable
If you use MVVM pattern, add to your ViewModel variable:
private bool _isEditableComboBox = false;
public bool IsEditableComboBox
{
get { return _isEditableComboBox; }
set { _isEditableComboBox = value; RaisePropertyChanged(() => IsEditableComboBox); }
}
Add to your project assembly: System.Windows.Interactivity
Add to your View namespace to this assembly:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Change your ComboBox to this:
<ComboBox TextSearch.TextPath="MemberFullName" IsEditable="{Binding IsEditableComboBox, UpdateSourceTrigger=PropertyChanged}" Height="23" VerticalAlignment="Center" Grid.Row="1" Grid.Column="1" Margin="5,0,0,0" ItemsSource="{Binding MemberCollection}" SelectedItem="{Binding SelectedSearchMember,Mode=TwoWay,ValidatesOnDataErrors=True}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding TurnOnEditMode}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MemberFullName}" VerticalAlignment="Center"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
And you must add to your ViewModel this command:
public ICommand TurnOnEditMode { get; private set; }
private void OnTurnoOnEditMode()
{
IsEditableComboBox = true;
}

Silverlight: DataGrid inside ListBox. Binding on DataGrid Column to a parent listbox's ItemsSource property. Silverlight

I'm a little puzzled with this one. I have a Collection called "AllProducts", which has a collection inside called "ProductGroups" (to group items separately) which inside contain a collection of "Product" objects called "LineItems" (the actual items).
To set this up, I have set a ListBox with a DataGrid inside the itemtemplate for the ListBox's Items. Setting the ItemsSource of the listbox to "ProductGroups" and the DataGrid(In the itemtemplate) has an ItemsSource pointing to LineItems.
The DataGrid contains Columns:
"Select" -- A checkbox and a radiobutton
"Image" -- string
"Name" -- string
"Description" -- string
"Price" -- string
The "ProductGroup" collection has a bool property called "IsListItem" per group, which is supposed to tell me if you can select multiple or a single item for that group (hence the checkbox and radiobutton in the first column of the DataGrid). I want the checkbuttons and radiobuttons visibility property to be bound to "IsListItem" bool which I have already set up with a BoolToVisibility converter with an "IsInverted" property to switch them back and forth.
The problem that I'm running into is that I want the first column of the DataGrid which contains the checkboxes/radiobuttons to be bound to the IsLineItem of ProductGroups (which is the ListBox's ItemsSource. But Since the DataGrid's ItemsSource is bound to LineItems, the DataContext of the DataGrid is set to LineItems and I can't access anything outside of it.
Here's some code to help:
ListBox XAML:
<sdk:TabItem Header="Pmt" x:Name="Payment">
<Canvas x:Name="PaymentRoot" DataContext="{Binding Products.ProductGroups}">
<Rectangle Height="418" Canvas.Top="-14" Width="560" Style="{StaticResource MappingRectangleBG}" />
<StackPanel Canvas.Left="20" Canvas.Top="20" Width="520" Height="360">
<ListBox x:Name="lstProductGroups" ItemsSource="{Binding}" ItemTemplate="{StaticResource ProductListItem}" />
</StackPanel>
</Canvas>
</sdk:TabItem>
ListBox ItemTemplate XAML:
<sdk:DataGrid x:Name="dgLineItems" ItemsSource="{Binding LineItems}">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Select">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Visibility="{Binding IsListType, Converter={StaticResource boolToVisibilityConverter}}" />
<RadioButton Visibility="{Binding IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}" GroupName="{Binding GroupName}"/>
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Image">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding ImageUrl}" Height="50" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn Header="Item Name"
Binding="{Binding Name}" />
<sdk:DataGridTextColumn Header="Item Price"
Binding="{Binding Price}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</StackPanel>
</DataTemplate>
And my Objects:
public class AllProducts
{
public IEnumerable<ProductOptionGroup> ProductGroups;
}
public class ProductOptionGroup
{
public string GroupName;
public IEnumerable<Product> LineItems;
public bool IsListType;
}
public class Product
{
public int ID;
public int OrdinalNumber;
public string Name;
public string Description;
public Decimal Price;
public string ImageUrl;
public CartItemType Type;
}
(MichaelS): I tried setting it to the Parent "PaymentRoot" Canvas' DataContext but it isn't doing anything for me. Here is what I tried:
<CheckBox Visibility="{Binding ElementName=PaymentRoot, Path=DataContext.IsListType, Converter={StaticResource boolToVisibilityConverter}}" />
<RadioButton Visibility="{Binding ElementName=PaymentRoot, Path=DataContext.IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}" GroupName="{Binding ElementName=PaymentRoot, Path=DataContext.GroupName}"/>
(MichaelS): here's how it's set up in my VM:
private AllProducts products;
public AllProducts Products
{
get
{
return products;
}
set
{
//Products.ProductGroups[0].LineItems[0].
products = value;
RaisePropertyChanged("Products");
}
}
Update:
The below code won't work since it's a known issue that was discovered late in the Silverlight 3 timeframe.
Setting the Binding in the LoadingRow event using column.GetCellContent(e.Row) should solve the issue.
In this particular case , you want be able to do that since the dataGrid itself is a dataTemplate of another control.
Try this:
Wrap your datagrid with another Grid. Name it, and use it for the element binding.
This code should work:
<StackPanel>
<Grid x:Name="GridDataHolder">
<sdk:DataGrid x:Name="dgLineItems" ItemsSource="{Binding LineItems}">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Select">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource boolToVisibilityConverter}}" />
<RadioButton Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}" GroupName="{Binding ElementName=GridDataHolder, Path=DataContext.GroupName}"/>
</StackPanel>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Image">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding ImageUrl}" Height="50" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn Header="Item Name"
Binding="{Binding Name}" />
<sdk:DataGridTextColumn Header="Item Price"
Binding="{Binding Price}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
</StackPanel>
By the way, i'm not sure if binding works with public members, you may need to change those binded members to public properties.
Finally got it fixed! What I had to end up doing was getting rid of the DataGrid altogether because a lot of controls from the toolkit seem to have that bug not being able to bind outside even through Element Binding.
I turned the DataGrid into a ListBox with another DataTemplate for the LineItems completely customizing the look of it to achieve a similar look that I had with the DataGrid.
Also to note: I tried at first binding to the StackPanel outside of the DataTemplate through Element Binding but it seemed to have a problem with that. So I set the grid inside the DataTemplate's DataContext and then I made the checkbox and radiobutton bound to the grid inside the Parent Listbox's dataTemplate through element binding and that did the trick!
Here is some working code for anybody who runs into this same issue later on!:
<DataTemplate x:Key="LineItemsTemplate">
<StackPanel Orientation="Horizontal">
<StackPanel Height="100" Width="100">
<StackPanel Height="40" Orientation="Vertical">
<RadioButton Content="{Binding Name}" Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource boolToVisibilityConverter}}" GroupName="{Binding ElementName=GridDataHolder, Path=DataContext.GroupName}"/>
<CheckBox Content="{Binding Name}" Visibility="{Binding ElementName=GridDataHolder, Path=DataContext.IsListType, Converter={StaticResource inverseBoolToVisibilityConverter}}"/>
</StackPanel>
<Image Source="{Binding ImageUrl}" Height="50" />
</StackPanel>
<TextBlock TextWrapping="Wrap" Text="{Binding Description}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ProductListItem">
<StackPanel x:Name="GridDataHolder">
<TextBlock TextWrapping="Wrap" Text="{Binding GroupName}" VerticalAlignment="Top" d:LayoutOverrides="Width"/>
<ListBox x:Name="lstProductGroups" ItemsSource="{Binding LineItems}" ItemTemplate="{StaticResource LineItemsTemplate}">
</ListBox>
</StackPanel>
</DataTemplate>
<sdk:TabItem Header="Pmt" x:Name="Payment">
<Canvas>
<Rectangle Height="418" Canvas.Top="-14" Width="560" Style="{StaticResource MappingRectangleBG}" />
<ScrollViewer Height="389" Width="545" x:Name="PaymentRoot" DataContext="{Binding Products.ProductGroups}">
<StackPanel Orientation="Vertical" ScrollViewer.VerticalScrollBarVisibility="Auto" Width="500" HorizontalAlignment="Center">
<ListBox x:Name="lstProductGroups" ItemsSource="{Binding}" ItemTemplate="{StaticResource ProductListItem}" />
</StackPanel>
</ScrollViewer>
</Canvas>
</sdk:TabItem>
Thanks MichaelS for all your help! You got me going the right way!

Resources