Show a list of pages in ListView with XAML binding - c#

I have a program with several features. Each feature has a ViewModel, a MainView and OptionsView. MainView is displaying what the feature does, while the OptionsView is a View allowing the user to change the settings of the feature. OptionsView is stored in the MainView.
I want to centralise the Options into a MainOptions view under a ListView. I can get a List or ObservableCollection of the MainViews for each feature, however i have trouble getting the OptionsView of each feature.
I can display OptionsView in the MainView just fine, however when i try to use DataTemplate in a ListView in order to bind the list of MainViews to it and get the OptionViews it doesn't display anything, but it doesn't crash or output errors.
XAML of OptionsMain :
<Grid>
<ListBox Name="OptionsList" ItemsSource="{Binding Path=FeaturesPages, Mode=TwoWay}" Background="Transparent">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Frame Name="GroupItemFrame" Content="{Binding Path=OptionsPage, Mode=TwoWay}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Code behind :
public partial class OptionsMain : Page, INotifyPropertyChanged
{
private ObservableCollection<Page> _optionsPages = new ObservableCollection<Page>();
public ObservableCollection<Page> OptionsPages
{
get { return _optionsPages; }
set
{
_optionsPages = value;
NotifyPropertyChanged("OptionsPages");
}
}
public OptionsMain(ObservableCollection<Page> pages)
{
foreach (Page p in pages)
{
OptionsPages.Add(p);
}
Console.WriteLine("List size : {0}", OptionsPages.Count);
InitializeComponent();
DataContext = this;
Any insight on what might be the problem? Is there a better way of doing this?

This is kind of a tricky issue, and I don't see many ways to accomplish this, but I do have a way. The problem is that you need to call Frame.Navigate to the page for each and every frame. You can't just assign the content unless it's actually a control with content. So I am going to suggest a work around/hack of forcing the frame to navigate as it's being loaded.
Mainpage.xaml:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListBox Name="OptionsList" Background="Transparent">
<ListBox.ItemTemplate>
<DataTemplate>
<Frame Name="GroupItemFrame" Loaded="GroupItemFrame_Loaded" Width="100" Height="100" BorderBrush="Red" BorderThickness="2" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Mainpage.xaml.cs:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
List<Page> MyPages = new List<Page>();
MyPages.Add(new DisplayNumberPage());
MyPages.Add(new DisplayNumberPage());
MyPages.Add(new DisplayNumberPage());
MyPages.Add(new DisplayNumberPage());
MyPages.Add(new DisplayNumberPage());
OptionsList.ItemsSource = MyPages;
}
int Index = 1;
private void GroupItemFrame_Loaded(object sender, RoutedEventArgs e)
{
Frame MyFrame = sender as Frame;
MyFrame.Navigate(typeof(DisplayNumberPage), Index);
Index++;
}
}
DisplayNumberPage.xaml:
<Grid Background="Black">
<TextBlock x:Name="DisplayNumber" FontSize="30" Text="100" Foreground="White"/>
</Grid>
DispayNumberPage.xaml.cs:
public sealed partial class DisplayNumberPage : Page
{
public DisplayNumberPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
DisplayNumber.Text = e.Parameter.ToString();
}
}

I'm adding this as an answer so it can be visible.
I found the optimal answer to my question after i used the answer marked as correct. They both work, it's just another way, simpler i'd argue, to achieve the same result:
<ListBox Name="OptionsList" ItemsSource="{Binding Path=OptionsPages, Mode=TwoWay}" Background="Transparent">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Name="OptionsItemStack" Orientation="Vertical">
<Label Name="GroupItemLabel" Content="{Binding Path=Title, Mode=OneWay}" Foreground="White"/>
<Frame Name="GroupItemFrame" Content="{Binding}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
Notice the Content="{Binding}". It doesn't need a code behind to display the Page in the frame.
As stated, it was tested and works, no errors in the output either.

Related

WPF: Frame to receive data within a ItemsControl

I need a part of my Page unmovable, so I thought using a Frame, something like:
<StackPanel>
<Label Style="{StaticResource OneThirdColumnLabel}">Administrar papéis: Alterar papéis</Label>
<ItemsControl x:Name="PapeisIc">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Frame x:Name="_papeisAddFrame" Source="PapeisAdd.xaml" Height="50"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Then, the Frame would contain a Page with:
<ScrollViewer VerticalScrollBarVisibility="Visible">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<Label Style="{StaticResource LaterLabel}">Papel:</Label>
<TextBox Text="{Binding Papel}" Style="{StaticResource StdTextBox}" Width="100" />
<Label Style="{StaticResource LaterLabel}">Descrição:</Label>
<TextBox Text="{Binding Descricao}" Style="{StaticResource StdTextBox}" Width="400" />
<Button x:Name="DeleteFieldBtn" Style="{StaticResource deleteFieldButtom}" ToolTip="Eliminar este papel"/>
</StackPanel>
</StackPanel>
</ScrollViewer>
In the code-behind, the line:
PapeisIc.ItemsSource = _papeis;
Binds a object that's an ObservableCollection of 3 items and I need it to display the 3 elements in the example.
What I get is:
So that, somehow it knows that there are 3 elements, but it doesn't bind it right...
I already tried to pass to the Page the data as a parameter, but it didn't work either.
How can I bind those values?
Just to make it clear, I'm trying to bind to an ObservableCollection of:
public class Role
{
public int Id { get; set; }
public string Papel { get; set; }
public string Descricao { get; set; }
}
The Frame control does not pass the DataContext down to the Page. The easiest way to solve this issue is to remove the Frame and move its content directly to the DataTemplate.
If you really need the Frame, you have to listen to the LoadCompleted and DataContextChanged events and propagate the DataContext manually to the content of the Frame. I show you how to do it with a TriggerAction using the Microsoft.Xaml.Behaviors.Wpf NuGet package.
public class UpdateContentDataContextAction : TriggerAction<Frame>
{
protected override void Invoke(object parameter)
{
if (AssociatedObject.Content is FrameworkElement frameworkElement)
frameworkElement.DataContext = AssociatedObject.DataContext;
}
}
<DataTemplate>
<Frame x:Name="_papeisAddFrame" Source="PapeisAdd.xaml" Height="50">
<b:Interaction.Triggers>
<b:EventTrigger EventName="LoadCompleted">
<local:UpdateContentDataContextAction/>
</b:EventTrigger>
<b:EventTrigger EventName="DataContextChanged">
<local:UpdateContentDataContextAction/>
</b:EventTrigger>
</b:Interaction.Triggers>
</Frame>
</DataTemplate>
If you want to do it in the code-behind, subscribe the events on the control and use the code of the trigger action.
<Frame x:Name="_papeisAddFrame" Source="PapeisAdd.xaml" Height="50" LoadCompleted="OnLoadCompleted" DataContextChanged="OnDataContextChanged">
private void OnLoadCompleted(object sender, NavigationEventArgs e)
{
PropagateDataContext((Frame)sender);
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
PropagateDataContext((Frame)sender);
}
private void PropagateDataContext(Frame frame)
{
if (frame.Content is FrameworkElement frameworkElement)
frameworkElement.DataContext = frame.DataContext;
}

UWP - MVVM - Remove ListView item using ItemTemplate button

I have a screen displaying a list of items on which the user can click a button to remove the corresponding item from the list.
I am trying to do so using MVVM.
But the item is not aware of the containing list when it gets the action.
I saw some answers here and there, but none of them using out of the box MVVM features I have in my environment
For example that one using PRISM (don't know if I should use that too, is it standard?):
How to properly remove Items from a ListView when the ItemTemplate is a User Control?
Here is the XAML:
<ListView ItemsSource="{Binding MyItemList}" SelectionMode="None" ScrollViewer.VerticalScrollMode="Disabled" ItemContainerTransitions="{x:Null}">
<ListView.ItemTemplate>
<DataTemplate >
<Grid Grid.Row="1" HorizontalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding ItemClass.Property01, Mode=TwoWay}" />
<Button Grid.Column="1" Command="{Binding RemoveItemCommand}" >
<SymbolIcon Symbol="Cancel" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And here is the ModelView list:
private static ObservableCollection<ItemClass> _MyItemList = new ObservableCollection<ItemClass> {
new ItemClass{ Property01 = "Sometext" }
};
public ObservableCollection<ItemClass> MyItemList { get { return _MyItemList; } }
And I want to be able to perform the following (the example of code from the main model view, I could create an item model view if necessary for solving):
public IMvxCommand RemoveItemCommand { get; private set; }
public MyViewModel(IUserDialogs dialogs)
{
RemoveItemCommand = new MvxCommand(RemoveItem);
}
public void RemoveItem(object theItem) { MyItemList.Remove(theItem); }
Add x:Name="listView" attribute to your ListView, then in the template
<Button Grid.Column="1"
Command="{Binding ElementName=listView, Path=DataContext.RemoveItemCommand}"
CommandParameter="{Binding}" >
However, when I face problems like this, I usually just use code behind instead. The reason for that, I can use debugger for C# code in visual studio, but debugging these complex bindings is much harder. Here’s a C# version, the code is IMO cleaner, and easier to debug:
void removeItem_Click( object sender, RoutedEventArgs e )
{
object i = ((FrameworkElement)sender).DataContext;
( this.DataContext as MyViewModel )?.RemoveItem( i );
}
Or maybe that's just my personal preference.
It would be better to have a context menu item on the list view (or a delete button on the page somewhere) to delete the currently selected item(s). You can then get the selection from the list view.
Alternatively you could attach the context menu to the list view item in PrepareContainterForItemOverride (and detach it in the other Override method)
That would be a more standards interaction style.
If you must have the button inside the list view item, then the easiest way to get the list item would probably be to use a visual tree helper to go up from the button to the list view item and then get the actual item from the list view item.
Thanks for all the hints,
Using Soonts answer, I was able to develop a fast solution,
Here is what the final implementation looks like for reference for whoever wants to copy/paste/adapt (note I did not test code as I replaced variables/functions names):
XAML:
<ListView x:Name="ItemClass_ListView" ItemsSource="{Binding MyItemList}" SelectionMode="None" ScrollViewer.VerticalScrollMode="Disabled" ItemContainerTransitions="{x:Null}">
<ListView.ItemTemplate>
<DataTemplate >
<Grid Grid.Row="1" HorizontalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding ItemClass.Property01, Mode=TwoWay}" />
<Button Grid.Column="1" Command="{Binding ElementName=ItemClass_ListView, Path=DataContext.RemoveItemCommand}" CommandParameter="{Binding}" >
<SymbolIcon Symbol="Cancel" />
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ViewModel:
public class MyViewModel : BaseViewModel, INotifyPropertyChanged
{
public IMvxCommand RemoveItemCommand { get; private set; }
public MyViewModel()
{
// Initializing Commands
RemoveItemCommand = new MvxCommand<ItemClass>(OnRemoveItemClick);
}
public void OnRemoveItemClick(ItemClass anItem)
{
// Do stuff...
}
private static ObservableCollection<ItemClass> _MyItemList = new ObservableCollection<ItemClass> {
new ItemClass(),
new ItemClass()
};
public ObservableCollection<ItemClass> MyItemList
{
get { return _MyItemList; }
}
}

Dynamically adding elements to a UI in C#

The Problem
I have a C# window with some text fields and buttons on it. It starts out similar to this:
When the user clicks that "+ Add Machine Function" button, I need to create a new row of controls and move the button below those:
If the user clicks "+Add Scale Unit" the program needs to add some controls to the right:
Attempts at a solution
I have tried using Windows Forms' TableLayoutPanel but it seemed to handle resizing itself to fit additional controls in odd ways, for example it would some one rows of controls much wider than the others, and would make some rows so short it cut off parts of my controls.
I have also tried simply placing the controls by themselves into the form by simply calculating their relative positions. However I feel that this is bad programming practice as it makes the layout of the form relatively hard to change later. In the case of the user deleting the row or scale unit by pressing the 'X' beside it, this method also requires the program to find each element below that one and move it up individually which is terribly inefficient.
My question is: how would I go about creating a dynamically growing/shrinking application, either through Windows Forms layouts or WPF or something else?
In WPF you can do this:
Classes
public class MachineFunction
{
public string Name { get; set; }
public int Machines { get; set; }
public ObservableCollection<ScaleUnit> ScaleUnits { get; set; }
public MachineFunction()
{
ScaleUnits = new ObservableCollection<ScaleUnit>();
}
}
public class ScaleUnit
{
public string Name { get; set; }
public int Index { get; set; }
public ScaleUnit(int index)
{
this.Index = index;
}
}
Window.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ItemsControl Name="lstMachineFunctions">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Machine Function"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="Number of Machines"/>
<Button Grid.Row="1" Grid.Column="0" Click="OnDeleteMachineFunction">X</Button>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Name}"/>
<TextBox Grid.Row="1" Grid.Column="2" Text="{Binding Machines}"/>
</Grid>
<ItemsControl ItemsSource="{Binding ScaleUnits}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="12,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Machine/Scale Unit"/>
<Button Grid.Row="1" Grid.Column="0" Click="OnDeleteScaleUnit">X</Button>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Name}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Index, StringFormat='Scale Unit {0}'}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Button VerticalAlignment="Center" Click="OnAddScaleUnit">Add Scale Unit</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button HorizontalAlignment="Left" Click="OnAddMachineFunction">Add Machine Function</Button>
</StackPanel>
</Window>
Window.cs
public partial class MainWindow : Window
{
public ObservableCollection<MachineFunction> MachineFunctions { get; set; }
public MainWindow()
{
InitializeComponent();
lstMachineFunctions.ItemsSource = MachineFunctions = new ObservableCollection<MachineFunction>();
}
private void OnDeleteMachineFunction(object sender, RoutedEventArgs e)
{
MachineFunctions.Remove((sender as FrameworkElement).DataContext as MachineFunction);
}
private void OnAddMachineFunction(object sender, RoutedEventArgs e)
{
MachineFunctions.Add(new MachineFunction());
}
private void OnAddScaleUnit(object sender, RoutedEventArgs e)
{
var mf = (sender as FrameworkElement).DataContext as MachineFunction;
mf.ScaleUnits.Add(new ScaleUnit(mf.ScaleUnits.Count));
}
private void OnDeleteScaleUnit(object sender, RoutedEventArgs e)
{
var delScaleUnit = (sender as FrameworkElement).DataContext as ScaleUnit;
var mf = MachineFunctions.FirstOrDefault(_ => _.ScaleUnits.Contains(delScaleUnit));
if( mf != null )
{
mf.ScaleUnits.Remove(delScaleUnit);
foreach (var scaleUnit in mf.ScaleUnits)
{
scaleUnit.Index = mf.ScaleUnits.IndexOf(scaleUnit);
}
}
}
}
I did the same thing recently in WinForms and the way I did it was as follows:
Create a UserControl that contains the controls I wanted to repeat
Add a FlowLayoutPanel to the main form to contain all the user controls (and to simplify their positioning)
Add a new instance of your custom UserControl to the FlowLayoutPanel every time you want a new "row" of controls
flowLayoutPanel1.Controls.Add(
new MachineFunctionUC {
Parent = flowLayoutPanel1
});
To remove a row of control call this.Dispose(); from within the user control (that's the instruction executed by the "X" button).
If you want the UserControls to be arranged vertically set the following properties:
flowLayoutPanel1.AutoScroll = true;
flowLayoutPanel1.WrapContents = false;
flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
And to access them use flowLayoutPanel1.Controls[..]
The correct way to achieve your requirements in WPF is for you to define a custom data type class to represent your machine function. Provide it with how ever many properties that you need to represent your machine fields. When you have done this, you then need to move the code that generated your machine function UI into a DataTemplate for the type of your class and data bind all of the relevant properties:
<DataTemplate DataType="{Binding YourPrefix:MachineFunction}">
...
</DataTemplate>
Then, you need to create a collection property to hold your machine function items and data bind that to some kind of collection control. Once you have done this, then to add another row, you just need to add another item to the collection:
<ItemsControl ItemsSource="{Binding MachineFunctions}">
<ItemsControl.Resources>
<DataTemplate DataType="{Binding YourPrefix:MachineFunction}">
...
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
<Button Content="+ Add Machine Function" ... />
...
MachineFunctions.Add(new MachineFunction());
Please see the Data Binding Overview page on MSDN for further help with data binding.
Create a function which will define a row for you. Consider the code and use its where to place another control and do as for buttons also and count it position.
Button button1=new Button();
button1.Text="dynamic button";
button1.Left=10; button1.Top=10; //the button's location
this.Controls.Add(button1); //this is how you can add control

Wrong item selection in ListBox (Windows Phone, Caliburn.Micro, Rx)

I develop an app for Windows Phone 7 with using of Caliburn Micro and Reactive Extensions.
The app has a page with a ListBox control:
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<Views:ItemView Margin="0,12,0,0" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I'm using the next ItemView as a DataTemplate:
<UserControl ...>
<Grid x:Name="LayoutRoot"
cal:Message.Attach="[Event Tap] = [Action SelectItem]">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Style="{StaticResource PhoneTextLargeStyle}"
Text="{Binding Name}"
TextWrapping="Wrap" />
<TextBlock Grid.Column="1"
Foreground="{StaticResource PhoneDisabledBrush}"
Style="{StaticResource PhoneTextLargeStyle}"
Text="{Binding Id}" />
</Grid>
</UserControl>
And the corresponding ItemViewModel looks like this:
public class ItemViewModel
{
private readonly INavigationService _navigationService;
public int Id { get; private set; }
public string Name { get; private set; }
public ItemViewModel(Item item)
{
Id = item.Id;
Name = item.Name;
_navigationService = IoC.Get<INavigationService>();
}
public void SelectItem()
{
_navigationService.UriFor<MainViewModel>()
.WithParam(x => x.Id, Id)
.Navigate();
}
}
}
The ListBox populates with items:
public class ListViewModel : Screen
{
private readonly IItemsManager _itemsManager;
private List<ItemViewModel> _items;
public List<ItemViewModel> Items
{
get { return _items; }
private set
{
_items = value;
NotifyOfPropertyChange(() => Items);
}
}
public ListViewModel(IItemsManager itemsManager)
{
_itemsManager = itemsManager;
}
protected override void OnViewReady(object view)
{
base.OnViewReady(view);
Items = null;
var list = new List<ItemViewModel>();
_itemsManager.GetAll()
.SubscribeOn(ThreadPoolScheduler.Instance)
.ObserveOnDispatcher()
.Subscribe((item) => list.Add(new ItemViewModel(item)),
(ex) => Debug.WriteLine("Error: " + ex.Message),
() =>
{
Items = list;
Debug.WriteLine("Completed"));
}
}
}
And here the problems begin.
_itemsManager returns all items correctly. And all items correctly displayed in the ListBox. There is ~150 items.
When I tap on an item then SelectItem method in the corresponding ItemViewModel must be called. And all works fine for first 10-20 items in ListBox. But for all the next items SelectItem method is called in absolutely incorrect ItemViewModel. For example, I tap on item 34 and SelectItem method is called for item 2, I tap 45 - method is called for item 23, and so on. And there is no no dependence between items.
I already head breaks in search of bugs. In what could be the problem?
The solution was found after reading the discussion forum and the page in documentation of Caliburn.Micro.
All problems were because of Caliburn.Micro's Conventions.
To solve the problem I've added to the DataTempalate the next code: cal:View.Model={Binding}. Now part of the page with the ListBox looks like this:
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<Views:ItemView Margin="0,12,0,0" cal:View.Model={Binding}/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I think it's not a perfect answer. So I'll be glad if someone can provide better answer and explanation.

how do I access a radiobutton inside a ListBoxItem in windows phone 7

Please review the code for the ListBox I am using
<ListBox Name="listBoxDefaultAcc" HorizontalAlignment="Left" VerticalAlignment="Top" Width="450" Height="410">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="60" Width="450">
<RadioButton Content="{Binding}" GroupName="defaultAcc" HorizontalAlignment="Left" VerticalAlignment="Center" Height="80" Width="450" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now I want to access the content property of the RadioButton from codebehind.
The ListBoxItems are getting filled dynamically from the codebehind with the following code:
listBoxDefaultAcc.ItemsSource = from acc in db.Table<Accounts>()
select acc.accName;
Please help me out with this.
You can use the VisualTreeHelper and drill down to the control. This is not recommended though.
Better is to only bind to the properties of the controls in you datatemplate and then retrieve the values by getting the binded values. Technically in this case, if you would want to change the content of the radiobutton then you would need to change the item in the itemssource
Can you explain what you are trying to archieve by getting the content of the radiobutton?
Edit**********
<ListBox Name="listBoxDefaultAcc" HorizontalAlignment="Left" VerticalAlignment="Top" Width="450" Height="410">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="60" Width="450">
<RadioButton Content="{Binding Name}" IsChecked="{Binding Selected, Mode=TwoWay}" GroupName="defaultAcc" HorizontalAlignment="Left" VerticalAlignment="Center" Height="80" Width="450" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
public partial class Home : Page
{
public Home()
{
InitializeComponent();
var items = new List<SomeClass>();
items.Add(new SomeClass() {Name = "a"});
items.Add(new SomeClass() {Name = "b"});
items.Add(new SomeClass() {Name = "c"});
listBoxDefaultAcc.ItemsSource = items;
}
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
private void testButton_Click(object sender, RoutedEventArgs e)
{
var items = (List<SomeClass>)listBoxDefaultAcc.ItemsSource;
var selectedItem = items.Where(x => x.Selected).FirstOrDefault();
}
class SomeClass
{
public string Name { get; set; }
public bool Selected { get; set; }
}
}
You should be using DataBinding. You should bind Content to a property, that represents content, of an object, you are setting as item.
This way, you dont have to care about ListBoxes or Templates or anything. You are simply manipulating objects, and theese changes get reflected in the GUI.

Categories

Resources