DataGrid Selected Item property getting executed on itemsource Change - silverlight-4.0

I have a Silverlight project and I am using the MVVM pattern.
I have a GridView control and I am assigning its ItemSource from a ViewModel. It's SelectedItem is bound to a ViewModel property.
On clicking a button I am updating the ItemSource of the Grid. But my problem now is the SelectedItem bound property is also getting executed when I update the ItemSource.
Is there a way that I can stop the SelectedItem property from getting executed on updating the ItemSource?
This is my DataGrid
<sdk:DataGrid x:Name="DataGrid" Width="400"
Height="511" Visibility="Visible"
SelectionMode="Single"
ItemsSource="{Binding DetailInfo, Mode=TwoWay}"
SelectedItem = {Binding SelectedAgent} ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Auto" AutoGenerateColumns="False"
CanUserReorderColumns="False" CanUserResizeColumns="True" IsReadOnly="True"
CanUserSortColumns="True">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn x:Name="detailRank" Binding="{Binding Rank}" Header="#" Width="40"/>
<sdk:DataGridTextColumn x:Name="detailName" Binding="{Binding Name}" Header="Reps" Width="160"/>
<sdk:DataGridTextColumn x:Name="detailRevenue" Binding="{Binding Revenue, StringFormat=\{0:C0\}}" Header="Revenue" Width="70"/>
<sdk:DataGridTextColumn x:Name="detailProfit" Binding="{Binding Profit, StringFormat=\{0:C0\}}" Header="Profit" Width="58"/>
<sdk:DataGridTextColumn x:Name="detailMargin" Binding="{Binding Margin, StringFormat=\{0:P0\}}" Header="Margin" Width="55"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
In my view model i have a property that is bind to the SelectedItem in Grid
private Agent _selectedAgent;
public Agent SelectedAgent
{
get{ return this._selectedAgent; }
set
{
this._selectedAgent = value;
RaisepropertyChanged("SelectedAgent");
}
}
Now when the ItemSource gets updated the SelectedAgent property gets executed again.

Related

UWP Bind to ObservableCollection declaratively

I have a simple UWP page; there is a public ObservableCollection in the page code-behind:
public ObservableCollection<Book> MyObservableColl{ get; } = new ObservableCollection<Book>();
(note the collection consists of a single item)
I would like to bind to the collection; here is what I tried:
<StackPanel x:Name="stackPanel"
Grid.Row="2"
Margin="50"
DataContext="{x:Bind MyObservableColl, Mode=OneWay}">
<TextBox x:Name="txtTitle"
TextWrapping="Wrap"
Text="{x:Bind Title, Mode=OneWay}" />
</StackPanel>
The visual studio designer complains "the property Title was not found".
I appreciate any help to bind my text boxes to the Observable Collection.
the property Title was not found
txtTitle TextBox can't access Book item where in the MyObservableColl collection directly, you need place txtTitle under items control's ItemTemplate.
For example
<ListView ItemsSource="{x:Bind MyObservableColl, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Book">
<StackPanel>
<TextBox Text="{x:Bind Title}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For more info please refer to listview document.
Update
For single item please refer to this xaml
<StackPanel
x:Name="stackPanel"
Grid.Row="2"
Margin="50"
DataContext="{x:Bind MyObservableColl[0], Mode=OneWay}">
<TextBox Text="{Binding Title}"/>
</StackPanel>

How to make a column with combobox in Avalonia Ui in DataGrid?

Is it possible in Avalonia Ui DataGrid to implement a column with combobox editing cells, that is, to be able to edit a cell simply by opening this very combobox and the user can simply choose from the options provided ?. I tried to implement a DataGrid like this but ran into a problem. I connected the Nuget Avalonia.DataGrid library, connected the styles in App.axaml as it says. As a result, the combobox appears in the DataGrid, but there is no dropdown in it, although the same combobox works fine outside the DataGrid. What is wrong in this code?
//ViewModel
public List<int> Test3 {get;set;}
//View Window
<DataGrid Items="{Binding Tests}" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*" Header="Route" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="combo" Items="{Binding Path=DataContext.Test3, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
You forgot to add the property Tests to your ViewModel.
Also it would probably be good to have a conditional SelectedItem, but that's out of context...
I used this code:
//ViewModel
public List<int> Test3 { get; set; } = new List<int>(new int [] {1, 2, 3});
public List<int> Tests { get; set; } = new List<int>(new int[] { 1, 2 });
//XAML
<DataGrid Items="{Binding Tests}" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*" Header="Route" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="combo" Items="{Binding Path=DataContext.Test3, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Which gives me that result:
In case you did all that and your bindings are working, but you still did not get my result, you would need to provide further context (e.g. which Themes you used, on which operating you run the program, etc.).
Another possible solution is to use the Tag Property according to code example below.
<DataGrid x:Name="myDataGrid"
Items="{CompiledBinding myDataGridItems}"
SelectedItem="{CompiledBinding mySelectedItem}"
Tag="{CompiledBinding myComboBoxItems}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Route">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Items="{Binding Tag, ElementName=myDataGrid}"
ItemTemplate="{StaticResource ComboBoxItemTemplate}" Background="Transparent" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>

Binding ObservbleCollection to Combo box in XAML - Windows phone

I tried to bind an ObservableCollection variable to a ComboBox in the XAML. The data is not binding.
XAML File
<ComboBox x:Name="cmbCity" Height="44" Width="150" Grid.Row="4"
ItemsSource="{Binding}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="5" Text="{Binding lstCity}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Code behind (After navigating to another page)
protected override void OnNavigatedTo(NavigationEventArgs e)
{
UserInfo userInfo = new UserInfo();
userInfo.UserName = "Gayathri";
userInfo.Country = "India";
userInfo.State = "TN";
ObservableCollection<string> cityInfo = new ObservableCollection<string>();
cityInfo.Add("Chennai");
cityInfo.Add("Cuddalore");
cityInfo.Add("Pondicherry");
cityInfo.Add("Villupuram");
userInfo.lstCity = cityInfo;
this.DataContext = userInfo;
}
Here I am passing values in the DataContext. The data is getting bound to the textbox but not the Combobox.
Output:
You're bindings are slightly wrong.
They should be like this:
<ComboBox x:Name="cmbCity" Height="44" Width="150" Grid.Row="4"
ItemsSource="{Binding lstCity}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="5" Text="{Binding}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
(I've moved the reference to lstCity)
Previously you were binding the whole DataContext to the ComboBox and then each TextBlock to the Collection of strings.
You need to bind the ItemsSource of the ComboBox to the collection and then each TextBlock should contain one of the strings.

ListBox and ApplicationBar: last element padding

I have a ListBox and ApplicationBar with Opacity=.5. I want that ListBox items are under the ApplicationBar.
Like figure:
But when I scrolled to end of list then last element of ListBox is under the ApplicationBar.
I want that last element is over ApplicationBar.
Can I add padding for a last element of the ListBox (LongListSelector)? How can solved this issue?
UPDATE
<ListBox Name="MyListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<i:Interaction.Triggers>
<ec:DataTrigger Binding="{Binding RelativeSource=
{RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}"
Value="True">
<ec:ChangePropertyAction PropertyName="Padding" Value="0,0,0,72"/>
</ec:DataTrigger>
</i:Interaction.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Background="Red"
Width="400"
Height="120"
Margin="15">
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
UPDATE 2
My problem can be easily solved by using LongListSelector. Just add empty ListFooterTemplate with Height = ApplicationBar height.
You can use converter to check if it's last item in listbox and in case yes, set padding to desired value via DataTrigger.
Check my answer over here for converter code. Just for sake of completeness of this answer i will post that converter code here:
public class IsLastItemInContainerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
DependencyObject item = (DependencyObject)value;
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
return ic.ItemContainerGenerator.IndexFromContainer(item)
== ic.Items.Count - 1;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and use it like this:
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource=
{RelativeSource Self},
Converter={StaticResource IsLastItemInContainerConverter}}"
Value="True">
<Setter Property="Padding" Value="5"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
edit: Didn't see the update to the original question. The below remains for additional detail.
This solution is for Windows Phone 8 only (although you could use the LongListSelector from the Windows Phone Toolkit if you are targeting 7.1/5).
I'd replace the ListBox with the LongListSelector from the SDK
<Grid>
<controls:LongListSelector ItemTemplate="{StaticResource Item}" ListFooterTemplate="{StaticResource Footer}" />
</Grid>
and for the templates add
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="Item">
<StackPanel Background="Red"
Width="400"
Height="120"
Margin="15">
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="Footer">
<Border Height="72" />
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
Maybe simplest solution is to customize ItemsPanel property on ListBox:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Margin="0,0,0,150"/> <!-- set margin to show some 'blank' space after last item -->
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
...
</ListBox>
But be aware that by default ListBox uses VirtualizedStackPanel as ItemsPanel. If you change it to StackPanel, it may bring some performance penalty. This is solution is suitable for lists with few items.

How to get control parent DataContext for element to element databinding?

Suppose I have a user control which datacontext is bound to a VM. This VM has a property for a list MyList.
Inside this user control I have a ComboBox, I want to set following kind of xaml
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel HorizontalAlignment="Stretch">
<sdk:DataGrid ItemsSource="{Binding YourList}" IsReadOnly="True" AutoGenerateColumns="False" >
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<!-- ...... -->
<sdk:DataGridTemplateColumn Header="User" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ElementName=LayoutRoot, Path=DataContext.MyList}" DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding UserID}" ></ComboBox>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</StackPanel>
</Grid>
but it is not working.
How to resolve this problem?
This worked form me. This was the ItemSource for a ComboBox that was within a DataGrid:
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=sdk:DataGrid},
Path=DataContext.Teams}">
Are you trying to get to the main VM from within the UserControl? take a look at this solution. http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx