Bindig List to ListView in XAML not working? - c#

I have read all the similar posts but did not found a solution for my problem.
I have the following List:
private List<Character> _Characters;
public List<Character> Characters
{
get { return _Characters; }
set { Set(ref _Characters, value);}
}
As I debugged the code, all the items (around 500) are added to the list properly.
My XAML looks like this:
<StackPanel Orientation="Horizontal">
<TextBlock Text="Characters: " FontWeight="Bold" VerticalAlignment="Top" />
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ItemsControl ItemsSource="{Binding Characters}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=name}" IsTextSelectionEnabled="True" Margin="12" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</StackPanel>
However, when I run the program, the names are not displayed at all.
EDIT: Datacontext is set in the XAML:
<Page.DataContext>
<vm:MyViewModel />
</Page.DataContext>

Try to use ObservableCollection instead of List
private ObservableCollection<Character> _Characters;
public ObservableCollection<Character> Characters
{
get { return _Characters; }
set { Set(ref _Characters, value);}
}
also give a look at https://github.com/Fody/PropertyChanged

Related

Binding a property with a different ItemSource WPF C#

I have a list bound as ItemSource that contains two strings: Option 1 and option 2, I have 2 text boxes where I bind and display these two options. I also have two radio buttons next to the two textboxes. I want to bind these radiobuttons but every time I click on them nothing happens. I found out the reason for this, because now he is always trying to find the bool in my list whether the button is checked or not. Is there a way to set in the xaml code that I can access the bool property which is in my ViewModel?
ViewModel:
public class WortAuswahlViewModel : AntwortMoeglichkeitViewModel, IWortAuswahlViewModel
{
public ObservableCollection<AuswahlOptionen> m_auswahlOptionen;
public WortAuswahlViewModel(WortAuswahl wortAuswahl)
{
if (wortAuswahl?.Optionen == null)
{
return;
}
m_auswahlOptionen = new ObservableCollection<AuswahlOptionen>(wortAuswahl.Optionen);
}
public ObservableCollection<AuswahlOptionen> WortAuswahlOptionen
{
get
{
return m_auswahlOptionen;
}
set
{
if (m_auswahlOptionen != value)
{
m_auswahlOptionen = value;
OnPropertyChanged();
}
}
}
private bool m_isRadioButtonCheckedFirst;
public bool CheckButtonEins
{
get
{
return m_isRadioButtonCheckedFirst;
}
set
{
if (m_isRadioButtonCheckedFirst != value)
{
m_isRadioButtonCheckedFirst = value;
OnPropertyChanged();
}
}
}
private bool m_isRadioButtonCheckedSecond;
public bool CheckButtonZwei
{
get
{
return m_isRadioButtonCheckedSecond;
}
set
{
if (m_isRadioButtonCheckedSecond != value)
{
m_isRadioButtonCheckedSecond = value;
OnPropertyChanged();
}
}
}
}
}
XAML:
<Grid>
<StackPanel Grid.Row="1" Grid.Column="1" Margin="20">
<ItemsControl ItemsSource="{Binding WortAuswahlOptionen}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Viewbox Height="80" HorizontalAlignment="Left" VerticalAlignment="Top">
<StackPanel>
<RadioButton HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" IsChecked="{Binding CheckButtonEins}"/>
<DockPanel LastChildFill="True">
<TextBox Grid.Column="1" Margin="20, 0, 0, 0" x:Name="TXT_optionEinsLoesung" Text="{Binding OptionEins}" IsReadOnly="True"/>
</DockPanel>
<RadioButton HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" IsChecked ="{Binding CheckeButtonZwei}"/>
<DockPanel LastChildFill="True">
<TextBox Grid.Column="1" Margin="20, 0, 0, 0" x:Name="TXT_optionZweiLoesung" Text="{Binding OptionZwei}" IsReadOnly="True"/>
</DockPanel>
</StackPanel>
</Viewbox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
DataContext of each ItemTemplate and ItemContainerStyle inside ItemsControl is automatically set to the corresponding element of the ItemsSource.
One way to redirect the DataContext to somewhere outside of the elements is to start the binding path from the DataContext of the root object of your Window.
So if your WortAuswahlViewModel is set to the DataContext of a Window, first you need to set the binding source to the Window using RelativeSource={RelativeSource AncestorType=Window} and then set path to Path=DataContext.CheckButtonEins
IsChecked="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.CheckButtonEins}"
If your WortAuswahlViewModel is set to the DataContext of another UI element, replace Window with the type of that element.

Initial Focus on selected ListViewItem

I have a simple dialog with MVVM, just a ListView and two Buttons (Ok, Cancel) and a ViewModel responsible for binding the ItemsSource and SelectedItem of the ListView.
View:
...
<StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ListView ItemsSource="{Binding Projects}" SelectedItem="{Binding Project}" SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
<StackPanel Orientation="Horizontal" FlowDirection="RightToLeft">
<Button Content="Cancel" IsCancel="True"/>
<Button Content="Ok" Command="{Binding OkCommand}" CommandParameter="{Binding ElementName=Dlg}"/>
</StackPanel>
</StackPanel>
...
Viewmodel:
public class SelectProjectViewModel : ViewModelBase, IModalDialogViewModel
{
private readonly ProjectList _projectList;
public ProjectList Projects => _projectList;
public Project Project
{
get { return GetValue(() => Project); }
set { SetValue(() => Project, value);}
}
private RelayCommand _okCommand;
public RelayCommand OkCommand => _okCommand ?? (_okCommand = new RelayCommand(OkCommandCall));
public SelectProjectViewModel(ProjectList projectList, Project currentProject)
{
_projectList = projectList;
this.Project = currentProject;
}
private void OkCommandCall(object window)
{
DialogResult = true;
WindowCloseBehaviour.SetClose(window as DependencyObject, true);
}
public bool? DialogResult
{
get { return GetValue(() => DialogResult); }
private set { SetValue(() => DialogResult, value); }
}
}
I tried to achieve focusing the first Element like described here, with the accepted solution and the equivalent behaviour class. But this always sets the focus on the Cancel-Button, while I want my ListView to be focused when opening the dialog, so that the selected element is really highlighted, not just in the "inactive highlight" color. And no, I don't want to workaround with changing the colors.
Using simple FocusedElement on a parent with SelectedIndex on ListView itself works for me:
<StackPanel FocusManager.FocusedElement="{Binding ElementName=myListView}">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ListView Name="myListView" ItemsSource="{Binding Projects}" SelectedItem="{Binding Project}" SelectionMode="Single"
SelectedIndex="0">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
...
</StackPanel>
</StackPanel>

Binding issue in UserControl contained in a ListView

My app structure is as follows:
MainPage.xaml has a ListView that has it's ItemSource set to a CollectionViewSource which is populated in code-behind:
MainPage.xaml
<Page.Resources>
...
<CollectionViewSource x:Key="src" IsSourceGrouped="True" />
...
</Page.Resources>
<Grid>
...
<ListView
ItemsSource="{Binding Source={StaticResource src}}"
SelectionMode="None"
ItemTemplate="{StaticResource processTemplate}"
ItemContainerStyle="{StaticResource ListViewItemStyle}">
<ListView.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource groupTemplate}"/>
</ListView.GroupStyle>
</ListView>
...
</Grid>
MainPage.xaml.cs
var cvs = (CollectionViewSource)Resources["src"];
cvs.Source = groups.ToList();
Where groups is a Linq query which is grouping objects by an object property
This is all working fine to display my groups objects in a ListView successfully. Where I have an issue is inside the layout of the individual list items. The template looks like this and includes a Usercontrol defined in another file.
MainPage.xaml
<DataTemplate x:Name="processTemplate">
<Grid>
...
<TextBlock Text="{Binding Path=Process}" ... />
<TextBlock Text="{Binding Path=Description}" ... />
<TextBlock Text="{Binding Path=LastSuccess}" ... />
<Button Grid.Column="1" Grid.RowSpan="3"
Background="{Binding Path=Status,
Converter={StaticResource stbConverter}}" ... />
<local:MinutesOverlay ... Visibility="{Binding Path=Status,
Converter={StaticResource stoConverter}}"
Overdue="{Binding Path=MinutesWarning}"
Alert="{Binding Path=MinutesAlert}"/>
</Grid>
</DataTemplate>
MinutesOverlay.xaml
<Grid>
...
<TextBlock Text="{Binding Path=Overdue}" />
<TextBlock Text="{Binding Path=Alert}" />
...
</Grid>
MinutesOverlay.xaml.cs
public sealed partial class MinutesOverlay : UserControl
{
public MinutesOverlay()
{
this.InitializeComponent();
}
public static readonly DependencyProperty OverdueProperty = DependencyProperty.Register(
"Overdue", typeof(int), typeof(MinutesOverlay), new PropertyMetadata(0));
public static readonly DependencyProperty AlertProperty = DependencyProperty.Register(
"Alert", typeof(int), typeof(MinutesOverlay), new PropertyMetadata(0));
public int Overdue
{
get { return (int)GetValue(OverdueProperty); }
set { SetValue(OverdueProperty, value); }
}
public int Alert
{
get { return (int)GetValue(AlertProperty); }
set { SetValue(AlertProperty, value); }
}
}
My bindings do not work and I cannot figure out how to get them to work. At present, the visibility of the MinutesOverlay control is governed by a binding which works as long as I do not set the Datacontext of the MinutesOverlay. If I do set it by doing this.Datacontext = this then the binding has no effect and the overlay is always visible(it should be collapsed most of the time).
If I set the values of Overdue and Alert without bindings in the MainPage.xaml it works fine.
Have you tried setting a name (x:Name="userControl") on your usercontrol and changed the binding to Text="{Binding Path=Alert, ElementName=userControl}"?

Send a FlipViewItem as a RelayCommandParameter in a Windows Store App

I am trying to send to a view model the current item of a FlipView control, using MVVM Light.
The XAML code representing the FlipView control is the following:
<FlipView x:Name="mainFlipView" Margin="0,10,0,10" ItemsSource="{Binding AlbumItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Caption}"
FontSize="23"
HorizontalAlignment="Center"
TextAlignment="Center"
TextWrapping="Wrap"
Margin="10"/>
<ScrollViewer Grid.Row="1" ZoomMode="Enabled">
<uc:ImageViewer FilePath="{Binding ImagePath}" />
</ScrollViewer>
<TextBlock Text="{Binding NrOfVotes}" FontSize="20"
Grid.Row="2" HorizontalAlignment="Center"
Margin="10" />
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
...
The XAML code of the item containing the relay command is:
<Page.BottomAppBar>
<CommandBar>
<AppBarButton x:Name="appBarButtonDelete" Label="Delete" Icon="Delete"
Command="{Binding DeleteItemCommand}"
CommandParameter="{Binding ElementName=mainFlipView, Path=SelectedItem}"/>
</CommandBar>
</Page.BottomAppBar>
In the ViewModel, the RelayCommand is declared and used as follows:
public class ResultsPageViewModel : ViewModelBase
{
public RelayCommand<MyModel> DeleteItemCommand { get; private set; }
public ResultsPageViewModel()
{
this.DeleteItemCommand = new RelayCommand<MyModel>(post => DeleteItem(post));
}
public void DeleteItem(MyModel p)
{
//P is always null here...
}
}
The problem is that in the DeleteItem function I always get the parameter as null. I have tried declaring the RelayCommand as RelayCommand<object> but the problem persists.
I also tried the "workaround" method of declaring a MyModel bindable property and binding it to the FlipView. It works, but I would like to know what am I doing wrong in this situation.
Thank you in advance!
Try a different strategy: take the parameter directly from ViewModel, after a proper binding.
XAML
<FlipView x:Name="mainFlipView"
Margin="0,10,0,10"
ItemsSource="{Binding AlbumItems, Mode=TwoWay }"
SelectedItem="{Binding AlbumSelectedItem, Mode=TwoWay}">
ViewModel
private MyModel albumSelectedItem;
public MyModel AlbumSelectedItem
{
get
{
return albumSelectedItem;
}
set
{
if (value != null && albumSelectedItem != value)
{
albumSelectedItem = value;
RaisePropertyChanged(() => AlbumSelectedItem);
}
}
}
public void DeleteItem(MyModel p)
{
//P is always null here...
var pp = AlbumSelectedItem;
}
Obviously, CommandParameter is useless. ;-)

Binding controls inside ListBox to a source other than the source of ListBox

I have a ListBox bound to a source which provides data to the text property of the controls inside. Now I'd like to bind Foreground property of my textboxes to a different source other than the one the main ListBox is bound to!
My listbox is bound to a ObservableCollection and I want my textblock Foreground property bound to textColor which is located in ViewModel
public SolidColorBrush textColor
{
get { return new SolidColorBrush(Colors.Red); }
}
both are in ViewModel class.
I tried using Foreground="{Binding textColor}" but it seems XAML doesn't see it at all, should I do anything in the page so that it can see it, or is it because the parent (ListBox) is using a different source?
Edit :
More details:
I have a DataContext.cs class which I have defined my tables in it.
I have a ViewModel.cs class which I have these in it
public class CViewModel : INotifyPropertyChanged
{
private CDataContext myDB;
public CViewModel(string DBConnectionString)
{
myDB = new CDataContext(DBConnectionString);
}
private ObservableCollection<Groups> _allGroups;
public ObservableCollection<Groups> AllGroups
{
get { return _allGroups; }
set
{
_allGroups = value;
NotifyPropertyChanged("AllGroups");
}
}
public string textColor
{
get { return "Tomato"; }
}
}
Then I have my XAML file MainPage.xaml:
....
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Margin="0,8,0,0" toolkit:TiltEffect.IsTiltEnabled="True" x:Name="list" ItemsSource="{Binding AllGroups}" HorizontalAlignment="Center" BorderThickness="4">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Orange" Width="125" Height="125" Margin="6" Tap="Counterlist_OnTap">
<TextBlock Name="gname" Foreground="White" Text="{Binding Name}" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"/>
<TextBlock Name="ccl" Margin="0,0,0,-5" Foreground="{Binding textColor}" Text="{Binding Count}" FontSize="26" VerticalAlignment="Bottom" HorizontalAlignment="Left" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
....
I also set DataContext of my MainPage to ViewModel in code behind:
this.DataContext = App.ViewModel;
The textColor property is part of the CViewModel, not the Groups object that is the datacontext within the ItemTemplate.
Within the ItemTemplate you can reach out to the parent ViewModel with the following Element binding:
<TextBlock Name="ccl" Margin="0,0,0,-5"
Foreground="{Binding ElementName=ContentPanel, Path=DataContext.textColor}"
Text="{Binding Count}" FontSize="26"
VerticalAlignment="Bottom" HorizontalAlignment="Left" />
All you have to do is declare a static class (e.g. a singleton with per-instance access) and explicitly set the property binding to look in that class instead of the parent-bound model.
Bottom line: Just set the Source explicitly through a StaticResource.

Categories

Resources