UWP Combobox items scrolls to mid for no reason - c#

I noticed that in a combobox which has some itemsource attached to it, when there is no selected item it tends to scroll to middle of the item instead of starting at the top (first item) and when an item is selected it does sometime scroll to the selected item.
So I want to scroll to first item when no item is selected. For that I tried following fixes.
Code
private void ComboBoxKeyboardSelectionBehavior_DropDownOpened(object sender, object e)
{
var comboBox = (ComboBox) sender;
if(comboBox.SelectedIndex == -1)
{
//var scrollviewer = comboBox.GetScrollViewer();
//scrollviewer.ChangeView(0, 0, null);
//var allItems = comboBox.Items.ToList();
//var cccc = comboBox.Items.Count;
//var firstItem = allItems.First();
var ci = comboBox.ContainerFromIndex(0) as ComboBoxItem;
if (ci != null)
{
ci.StartBringIntoView();
}
}
else
{
var ci = comboBox.ContainerFromIndex(comboBox.SelectedIndex) as ComboBoxItem;
if (ci != null)
{
ci.StartBringIntoView();
}
}
}
WinRTXamlToolkit.Controls.Extensions gave me the option to get scrollviewer and then try the ChangeView method but that isn't working. I got the First item from the list successfully and used the ContainerFromItem method but it returned me null. So I also tried ContainerFromIndex method and provided index as 0 because that is supposed to be the first item, but that aint working either.
In case of selected item (else statement) it is working fine with ContainerFromIndex(comboBox.SelectedIndex) but just to test when I tried it with ContainerFromItem it returned null.
Just FYI, this event is in an attached behavior to the combobox style but that shouldn't matter because behavor works flawlessly for selected item scenario.

If you want to scroll to the first item when there is no selected item, you need to change the behavior of the DropDown of a ComboBox instead of ScrollViewer of a ComboBox.
The DropDown of a ComboBox is acutally a Popup, and the position where to show the Popup is defined in the code behind, and we can’t access to it. One workaround is finding the Popup and relocate it when it is opened, but using this method we need to calculate the VerticalOffset property each time when it is opened, and there are quite many scenarios for different value of VerticalOffset.
Therefore, we suggest you custom a control whose behavior like a ComboBox and position to the first item when no item is selected. For example:
Create a UserControl:
<Button x:Name="rootButton" BorderBrush="Gray" BorderThickness="2" Click="Button_Click" MinWidth="80" Background="Transparent" Padding="0">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Width="{Binding ElementName=rootButton, Path=ActualWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="32" />
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind selectedItem, Mode=OneWay}" Grid.Column="0" VerticalAlignment="Center" FontSize="15" HorizontalAlignment="Center" />
<FontIcon Grid.Column="1" FontSize="12" FontFamily="Segoe MDL2 Assets" Glyph="" HorizontalAlignment="Right"
Margin="0,10,10,10" VerticalAlignment="Center" />
</Grid>
<FlyoutBase.AttachedFlyout>
<MenuFlyout Placement="Bottom" x:Name="menuFlyout">
<MenuFlyoutItem Text="Item 1" Click="MenuFlyoutItem_Click" />
<MenuFlyoutItem Text="Item 2" Click="MenuFlyoutItem_Click" />
<MenuFlyoutItem Text="Item 3" Click="MenuFlyoutItem_Click" />
<MenuFlyoutItem Text="Item 4" Click="MenuFlyoutItem_Click" />
<MenuFlyoutItem Text="Item 5" Click="MenuFlyoutItem_Click" />
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
And the code behind in this UserControl:
public sealed partial class CustomComboBox : UserControl, INotifyPropertyChanged
{
public CustomComboBox()
{
this.InitializeComponent();
selectedItem = "";
}
private string _selectedItem;
public string selectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("selectedItem"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void MenuFlyoutItem_Click(object sender, RoutedEventArgs e)
{
var item = sender as MenuFlyoutItem;
selectedItem = item.Text;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout(sender as Button);
}
}
You can use the CustomComboBox in other page like this:
<local:CustomComboBox VerticalAlignment="Center" HorizontalAlignment="Center" />
By defalult this CustomComboBox will show its DropDown list under it.
In addition, you can also consider using other control such as a ListBox to directly replace the ComboBox to avoid the situation.
Update:
Currently, the ComboBox control does not provide related APIs for setting the starting position of DropDown in a Style, but we have a workaround to get the ScrollViewer inside the DropDown,and then call the ChangeView method to change the position. For example:
Define a custom combo box inherited from ComboBox class to get the ScrollViewer:
public class TestComboBox : ComboBox
{
public ScrollViewer InternalScrollViewer;
protected override void OnApplyTemplate()
{
InternalScrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer;
base.OnApplyTemplate();
}
}
Call the ChangeView method to change the position after items are initialized by using Task.Delay() in the ComboBoxKeyboardSelectionBehavior_DropDownOpened event handler:
await Task.Delay(50);
comboBox.InternalScrollViewer.ChangeView(0, 0, 1);
Note, use TestComboBox instead of ComboBox in XAML.

Related

C# XAML UWP - MenuFlyoutItem List not updating consistently in MenuFlyoutSubItem

this is probably a simple solution - its just a bit long to explain.
I add custom list view items to a ListView at run-time. Each ListView item has a Name, a Bool and a button. The button when clicked displays a Flyout menu which has subitem menu as shown in the image. The subitem menu should only display the name of all other items not itself. The correct behavior is shown in the first image as the "Item 4" menu button was clicked we only see Items 0 to 3 listed in the submenu.
The issue is that if i navigate to a submenu and then later add new items to the listbox, the new items never appear in the submenu for the older items previously navigated to. Like in the image below, where i clicked Item 1 button but only Item 0 and Item 2 are listed and for some reason Items 3 and 4 are not.
Firstly there is a complete minimum VS2019 solution demonstrating the behavior i'm describing above on GitHub here, though i have summarised what i think are the key bits of code below.
Non-boiler plate XAML header (MainPage.Xaml)
xmlns:local="using:DynamicFlyoutMenuTest.ViewModels"
The main ListView defintion and its DataTemplate as well as a button to add ListView items at run-time:
<StackPanel>
<Button Name="AddCustomListItemBtn" Click="AddCustomListItemBtn_Click">Add Custom ListItem</Button>
<ListView
Name="LayerListBox"
Height="Auto"
BorderBrush="{ThemeResource SystemBaseLowColor}"
BorderThickness="1.0"
ItemsSource="{x:Bind ViewModel.MyCustomListItems}">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid Padding="2" Background="{ThemeResource SystemBaseLowColor}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="190" />
<ColumnDefinition Width="132" />
</Grid.ColumnDefinitions>
<TextBlock Style="{ThemeResource CaptionTextBlockStyle}" Text="Name" />
<TextBlock
Grid.Column="1"
Style="{ThemeResource CaptionTextBlockStyle}"
Text="Active" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate x:Name="TableDataTemplate" x:DataType="local:MyCustomListItem">
<Grid Height="48" AutomationProperties.Name="{x:Bind ItemName}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="190" />
<ColumnDefinition Width="132" />
<ColumnDefinition Width="132" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Padding="10"
VerticalAlignment="Center"
Text="{x:Bind ItemName, Mode=OneWay}" />
<CheckBox
Grid.Column="1"
VerticalAlignment="Center"
IsChecked="{x:Bind isEditing, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Button
Name="exportLayerButton"
Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
<Button.Flyout>
<MenuFlyout Opening="MenuFlyout_Opening">
<MenuFlyoutItem
Name="Action1Btn"
Click="Action1Btn_Click"
Text="Action 1" />
<MenuFlyoutItem
Name="Action2Btn"
Click="Action2Btn_Click"
Text="Action 2" />
<MenuFlyoutSubItem x:Name="SubActionsBtn" Text="Choose Sub Action">
<MenuFlyoutItem Name="NoSubActionBtn" Text="None" />
</MenuFlyoutSubItem>
</MenuFlyout>
</Button.Flyout>
<Polygon
Fill="Black"
Points="0,0 6,4,0,8"
Stroke="Black" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
MainPage.xaml.cs - Add Item to List and Update Flyout Sub Menu Items
private void MenuFlyout_Opening(object sender, object e)
{
//make MenuFlyoutSubItem list all Items in ListView except the one triggering this function
var menuFlyout = sender as MenuFlyout;
// get the menu list we want to add to
MenuFlyoutSubItem menuSubItems = menuFlyout.Items.Where(x => x.Name == "SubActionsBtn").FirstOrDefault() as MenuFlyoutSubItem;
// get the active maplayerlistitem (that triggered this menu opening event)
MyCustomListItem myCustomListItem = (menuFlyout.Target as Button).DataContext as MyCustomListItem;
menuSubItems.Items.Clear();
foreach (var targetItem in ViewModel.MyCustomListItems)
{
if (myCustomListItem.ItemName != targetItem.ItemName)
{
var tItem = new MenuFlyoutItem();
tItem.Text = targetItem.ItemName.ToString();
//tItem.Click += new Windows.UI.Xaml.RoutedEventHandler(DoSomethingBtn_Click);
menuSubItems.Items.Add(tItem);
}
}
}
private void AddCustomListItemBtn_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
// Update ListView
var newItem = new MyCustomListItem();
newItem.ItemName = "Item " + ViewModel.MyCustomListItems.Count.ToString();
newItem.isEditing = false;
ViewModel.MyCustomListItems.Add(newItem);
}
MainViewModel.cs
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Microsoft.Toolkit.Mvvm.ComponentModel;
namespace DynamicFlyoutMenuTest.ViewModels
{
public class MainViewModel : ObservableObject
{
public ObservableCollection<MyCustomListItem> MyCustomListItems = new ObservableCollection<MyCustomListItem>();
public MainViewModel()
{
}
}
public class MyCustomListItem : INotifyPropertyChanged
{
public MyCustomListItem()
{
}
private bool _isEditing;
public bool isEditing
{
get { return _isEditing; }
set
{
_isEditing = value;
NotifyPropertyChanged(this, "isEditing");
}
}
private string _itemName;
public string ItemName
{
get { return _itemName; }
set
{
_itemName = value;
NotifyPropertyChanged(this, "ItemName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged(object sender, string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(sender, e);
}
}
}
}
EDIT
You can view the issue in video at https://www.youtube.com/watch?v=yPNNtsS-n5Q
You can reproduce the issue from the GitHub source by
adding 3 items to the ListView using the "Add..." button.
Navigating to the submenuFlyout of each ListViewItem
Add 2 more Listview Items using the "Add..." button
navigate to the submenuFlyout of the two new items and finally
navigate to submenuFlyout of the original 3 items and see that they haven't updated to reflect the additional ListView items added.
I found a workaround by removing the exsiting MenuFlyoutSubItem and adding a new one each time the Flyout is opened. So it's not ideal, but it does work.
If anyone has as an actual solution, id be happy to mark it as such.
Otherwise here is the workaround:
private void MenuFlyout_Opening(object sender, object e)
{
//make MenuFlyoutSubItem list all Items in ListView except the one triggering this function
var menuFlyout = sender as MenuFlyout;
// get the menu list we want to add to
MenuFlyoutSubItem menuSubItems = menuFlyout.Items.Where(x => x.Name == "SubActionsBtn").FirstOrDefault() as MenuFlyoutSubItem;
// get the active maplayerlistitem (that triggered this menu opening event)
MyCustomListItem myCustomListItem = (menuFlyout.Target as Button).DataContext as MyCustomListItem;
menuFlyout.Items.Remove(menuSubItems);
menuSubItems = new MenuFlyoutSubItem();
menuSubItems.Name = "SubActionsBtn";
menuSubItems.Text = "Choose Sub Action";
foreach (var targetItem in ViewModel.MyCustomListItems)
{
if (myCustomListItem.ItemName != targetItem.ItemName)
{
var tItem = new MenuFlyoutItem();
tItem.Text = targetItem.ItemName.ToString();
//tItem.Click += new Windows.UI.Xaml.RoutedEventHandler(DoSomethingBtn_Click);
menuSubItems.Items.Add(tItem);
}
}
menuFlyout.Items.Add(menuSubItems);
}

Make specific ListView item not clickable in Universal Windows Platform

I am using a ListView element in my XAML:
<ListView
x:Name="myList"
IsItemClickEnabled="true"
ItemClick="onDrawerItemClick"
SelectionMode="Single"
ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListView.ItemTemplate>
<DataTemplate>
<Grid
Width="260">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="44" />
<ColumnDefinition
Width="*" />
</Grid.ColumnDefinitions>
<Image
x:Name="image"
Source="{Binding myIcon}"
Grid.Column="0" />
<TextBlock
Text="{Binding myTxt}"
Grid.Column="1" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and I populate it using Bind property like so:
List<MyObj> listData = a list with title + image uri;
myList.ItemsSource = listData;
I need to disable click only for some items depending on some value from MyObj in my list but the others to have it. In Android we use adapter for that, how should I handle it here?
First, you should create a new bool property called Disabled inside your MyObj object.
Then, subscribe to myList's ContainerContentChanging event where you have access to the ListViewItem and its corresponding Item, which in this case is your MyObj. So, if MyObj.Disabled is true, make that ListViewItem non-clickable.
private void myList_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
var listViewItem = args.ItemContainer;
if (listViewItem != null)
{
var model = (MyObj)args.Item;
if (model.Disabled)
{
listViewItem.IsHitTestVisible = false;
// OR
//listViewItem.IsEnabled = false;
}
}
}
Keep in mind that you might want to use listViewItem.IsEnabled = false if you want that item to appear dimmed. This is because the default ListViewItemstyle has a Disabled state that reduces its Opacity; while setting listViewItem.IsHitTestVisible = false won't change its appearance in any way.
The listView is a strange control as it does not have any mechanism to disable selection.
So what I suggest you do is rather handle the event that notifies the framework that an item has been selected by attaching an event handler to ItemSelectionChanged and in there perform a deselect on the item:
yourListView.ItemSelectionChanged += yourListView_ItemSelectionChanged;
private void yourListView_ItemSelectionChanged(
object sender,
ListViewItemSelectionChangedEventArgs e)
{
if (e.IsSelected)
e.Item.Selected = false;
}
Please let me know if my answer helps :)

Flipview doesn't maintain selectedindex after returning from mail app via launcher

I am facing an issue with FlipView. I am sharing the minimalistic project, which represent my usecase in original app, http://1drv.ms/163kHCR.
I have two pages. First is MainPage.xaml. It has a flipview with five times. First four has just textblock and fifth one has one button. Clicking on it I will be redirected to Next.xaml. Please note MainPage has NavigationCacheMode as NavigationCacheMode.Required [Which is required for my original app]. So last known index of FlipView is 4.
In Next page there's a button clicking on it, opens the mail client via launcher. Now when I press back from mail client I would be navigated to Next page and pressing back one more time, I will be on MainPage and selected index will be 4, that's correct. Now when I swipe to right to see FlipViewItem with index 3, it immediately show me first FlipViewItem with index 0. It just skips all the items till index 0.
Is there anything wrong in the code?
MainPage.Xaml
<Grid Grid.Row="1" x:Name="ContentRoot">
<FlipView x:Name="fv">
<FlipViewItem>
<TextBlock Text="1" FontSize="50" />
</FlipViewItem>
<FlipViewItem>
<TextBlock Text="2" FontSize="50" />
</FlipViewItem>
<FlipViewItem>
<TextBlock Text="3" FontSize="50" />
</FlipViewItem>
<FlipViewItem>
<TextBlock Text="4" FontSize="50" />
</FlipViewItem>
<FlipViewItem>
<Button Content="Next" Click="btnNext_Click" />
</FlipViewItem>
</FlipView>
</Grid>
MainPage.Xaml.cs
public MainPage()
{
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
this.navigationHelper.SaveState += this.NavigationHelper_SaveState;
NavigationCacheMode = NavigationCacheMode.Required;
}
private void btnNext_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(Next));
}
Next.xaml (NavigationCacheMode is not set)
<Grid Grid.Row="1" x:Name="ContentRoot">
<Button Content="Mail" Click="btnMail_Click" />
</Grid>
Next.xaml.cs
private async void btnMail_Click(object sender, RoutedEventArgs e)
{
var mailto = "mailto:?to=windows#microsoft.com&subject=Email&body=body";
await Windows.System.Launcher.LaunchUriAsync(new Uri(mailto));
}
This seems like a known bug that affects the FlipView control when you get back to it in a cached page. Not sure what the best workaround is, but you could try a few things - calling InvalidateScrollInfo() on the ScrollViewer in the FlipView's template, resetting the SelectedIndex value (perhaps set it to some other value and then immediately to the previous one), maybe even reset ItemsSource.
In support of Filip Skakun's answer (I'm too totem low to post a comment.)
DeviceUtility.FindControl<ScrollViewer>(this.FlipView, typeof(ScrollViewer)).InvalidateScrollInfo();
public static List<UIElement> GetAllChildControls(DependencyObject parent)
{
var controList = new List<UIElement>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var childControl = VisualTreeHelper.GetChild(parent, i);
if (childControl is UIElement)
{
controList.Add(childControl as UIElement);
}
controList.AddRange(GetAllChildControls(childControl));
}
return controList;
}
public static T FindControl<T>(DependencyObject parentContainer, Type controlType)
{
var childControls = GetAllChildControls(parentContainer);
var control = childControls.OfType<UIElement>().Where(x => x.GetType().Equals(controlType)).Cast<T>().First();
return control;
}

Reach a TextBlock from a specific ListViewItem from the ListView in Windows Phone 8.1 XAML programmatically

I am a new developer on Windows Phone 8.1, I am try to reach a specific ListView item from the ListView collection and be able to color it or color the TextBock inside of it, But I can't reach the item or reach any of items inside of ListView, Please take a look for my below code :
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
SQLiteRT db1 = new SQLiteRT();
var db_connection = await db1.Connection("MyDB.sqlite");
List<MyTBL> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;");
db_connection.Close();
LV_Options.ItemsSource = t_list;
}
// my List View called LV_Options
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView lv1 = sender as ListView;
if (lv1 == null)
return;
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
tb.FontSize = 17; // here I got debug error (it not worked !!!!!!!)
var item = LV_Options.Items.ElementAt(3); // this seems not work also !!!!
item.BackColor = Color.LightSteelBlue;
}
As you can see above, I tried to reach a specific item by LV_Options.Items.ElementAt(3) but it doesn't work! I also tried to reach the TextBlock from the selected List view item, but also not worked !
(Updated)
XAML code :
<!-- Title Panel -->
<StackPanel Grid.Row="0" Margin="19,0,0,0">
<TextBlock Name="TB_Rslt" Text="Here result of your answer" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
<TextBlock Text="page title" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
</StackPanel>
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,10,19,15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Name="TB_Question" Text="Choose Answer " Margin="0,0,25,0" HorizontalAlignment="Right" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" />
<TextBlock Name="TB_EnWord" Text="" Margin="90,0,15,0" HorizontalAlignment="Left" FontWeight="Bold" FontSize="22" FontFamily="Verdana" RenderTransformOrigin="0.5,0.5" TextAlignment="Right" />
<StackPanel Grid.Row="1" Margin="5,22,0,0">
<ListView Name="LV_Options" SelectionChanged="LV_Options_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding AMean1}" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
<Button Name="Btn_Answer" Content="Ansewr" HorizontalAlignment="Left" Grid.Row="1" VerticalAlignment="Bottom" Click="Btn_Answer_Click"/>
My application is a quiz application that offer 4 choices/options as answers for each question, and when user select a true answer, I want to highlight the true answer(true choice) by make its background to green, and if the user selected wrong answer/option I want to make the background of that answer (a specific List View item) with red.
Any help please ?
You're not going to be able to access an element inside a data template like that. Instead, leverage the binding to a view model to set the color and other view-related properties. First, create a wrapper view model for your data class:
public class MyTBLViewModel : INotifyPropertyChanged
{
public MyTBL Entity
{
get { return _entity; }
}
private readonly MyTBL _entity;
public Brush Highlight
{
get { return _brush; }
set
{
_brush = value;
RaisePropertyChanged("Highlight");
}
}
private Brush _highlight;
public double ItemFontSize
{
get { return _itemFontSize; }
set
{
_itemFontSize = value;
RaisePropertyChanged("ItemFontSize");
}
}
private Brush _itemFontSize;
public MyTBLViewModel(MyTBL entity)
{
_entity = entity;
_highlight = new SolidColorBrush(Colors.Transparent);
_itemFontSize = 12;
}
public event PropertyChangedEventArgs PropertyChanged;
protected void RaisePropertyChanged(string propName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propName));
}
}
Use this as your ItemsSource:
List<MyTBLViewModel> t_list = db1.GetTable("SELECT * FROM MyTBL LIMIT 4 ORDER BY RANDOM() ;")
.AsEnumerable().Select(entity => new MyTBLViewModel(entity)).ToList();
Now in your view, bind the view elements to "Highlight" and "ItemFontSize", and to any other properties you like:
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6" Background="{Binding Highlight}">
<StackPanel VerticalAlignment="Top" Margin="10,0,0,0">
<TextBlock Name="TB_AMean1" Text="{Binding Entity.AMean1}" TextWrapping="Wrap"
FontSize="{Binding ItemFontSize}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Finally, you can get the data item from the SelectionChangedEventArgs -- use it to update your view-related properties:
private void LV_Options_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Color.LightSteelBlue);
item.ItemFontSize = 17;
}
foreach (var item in e.RemovedItems.OfType<MyTBLViewModel>())
{
item.Highlight = new SolidColorBrush(Colors.Transparent);
item.ItemFontSize = 12;
}
}
var item = LV_Options.Items.ElementAt(3);
This line is incorrect. It will not return you a TextBlock. I don't know what a .BackColor is, and it should not compile. The Items property in a ListView will return you a list of ListViewItems. If you want to access the inside element from a ListViewItem, you'll need to access the ContentTemplateRoot property.
Do not use var ever. It lets you assume that you know the type, whereas if you explicitly typed the declaration you would realize you're doing it wrong.
MyTBL wrd = lv1.SelectedItem as MyTBL;
if (wrd == null)
return;
TextBlock tb = lv1.FindName("TB_AMean1") as TextBlock;
What is a MyTBL type? FindName is only available to framework DependencyObjects so I'm assuming it's a user control? You have to provide a lot more code to show us what you're doing and what you're setting the ListView's ItemsSource and ItemTemplate with and what these errors are and how you have 2 breaking debug errors at once and what the error messages are.
Comprehending runtime error messages is a huge part of being a good developer.

WPF: Easiest way to add control to grid based on ListView selection

I have a ListView which contains items that should represent certain settings, which can be changed by the user. I am looking for the easiest way to link the ListViewItem to a custom user control.
What I have now:
<ListView
Grid.Row="0"
Grid.Column="0"
SelectionChanged="SettingsListViewSelectionChanged">
<ListViewItem x:Name="PathSettings" Content="Path"/>
<ListViewItem x:Name="HideShowTvShows" Content="Hide/Show TV Shows"/>
</ListView>
And then in the code behind I figure out which item was clicked, and attach the corresponding UserControl to the Grid.
private void SettingsListViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listView = e.Source as ListView;
if (listView != null)
{
SettingsContentPanel.Children.Clear();
if (listView.SelectedItem.Equals(_pathSettings))
{
SettingsContentPanel.Children.Add(_pathSettings);
_pathSettings.SetValue(Grid.RowProperty, 0);
_pathSettings.SetValue(Grid.ColumnProperty, 1);
}
if (listView.SelectedItem.Equals(_hideShowTvShowsSettings))
{
SettingsContentPanel.Children.Add(_hideShowTvShowsSettings);
_hideShowTvShowsSettings.SetValue(Grid.RowProperty, 0);
_hideShowTvShowsSettings.SetValue(Grid.ColumnProperty, 1);
}
}
}
And the Grid itself:
<Grid
x:Name="SettingsContentPanel"
Grid.Row="0"
Grid.Column="2"
Grid.ColumnSpan="2" />
Is there a way to get rid of the boiler plate code behind and use XAML for this purpose?
Looks like you're looking for a ContentPresenter:
<ContentPresenter x:Name="SettingsContentPanel"
Content="{Binding SelectedItem, ElementName=MyLstView}"/>

Categories