UWP change style of ListView DataTemplate in a MasterView - c#

This is the structure of the XAML:
<controls:MasterDetailsView
ItemsSource="{x:Bind Artists}">
<controls:MasterDetailsView.MasterHeader>
// Some Code
</controls:MasterDetailsView.MasterHeader>
<controls:MasterDetailsView.ItemTemplate>
// Some Code
</controls:MasterDetailsView.ItemTemplate>
<controls:MasterDetailsView.DetailsTemplate>
<DataTemplate x:DataType="data:ArtistView">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<RelativePanel HorizontalAlignment="Stretch">
// Some Code
</RelativePanel>
<ListView
x:Name="AlbumsListView"
Grid.Row="1"
HorizontalAlignment="Stretch"
ItemsSource="{x:Bind Albums}"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:AlbumView">
<Grid Margin="10,0,0,30">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<RelativePanel>
// Some Code
</RelativePanel>
<ListView
x:Name="SongsListView"
Grid.Row="1"
HorizontalAlignment="Stretch"
ContainerContentChanging="SongsListView_ContainerContentChanging"
IsItemClickEnabled="True"
ItemClick="SongsListView_ItemClick"
ItemsSource="{x:Bind Songs}"
SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Music">
// Some Code
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</controls:MasterDetailsView.DetailsTemplate>
</controls:MasterDetailsView>
I am trying to highlight an item of SongsListView (it's inside another listview) whose music is playing by changing the foreground. I implemented it in the ContainerContentChanging but the foreground will only be changed after reload the page. I want it to be updated in real time. How can I do that?
I registered a MusicSwitching event which will take place when the current playing music is changed, so that I can set the foreground of the item that has been played to black, and the foreground of the item to be played to a highlight color.
public async void MusicSwitching(Music current, Music next)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
{
var item = ArtistMasterDetailsView.Items.First((a) => (a as ArtistView).Name == next.Artist);
var container = ArtistMasterDetailsView.ContainerFromItem(item);
});
}
I can first find the item correctly, but the container is null. Why? I thought it is the DataTemplate that contains the item.

If you want to highlight an item of SongsListView,the simple way is to set a property(I saw you have set a IsPlaying method,I changed it to a property) in Music class to bind to the control in item you want to hightlight.About Binding,you can refer to this document.
First, you should let the Music class inherits from INotifyPropertyChanged to listen property change notifications.
public class Music : IComparable<Music>, INotifyPropertyChanged
{
......
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public bool IsPlaying {
set {
IsMusicPlaying = value;
OnPropertyChanged();
}
get {
return IsMusicPlaying;
}
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
Then,bind the property to the control in item you want to highlight.
<Page.Resources>
<local:ColorConvert x:Name="MyConvert"></local:ColorConvert>
</Page.Resources>
<FontIcon
x:Name="PlayingIcon"
Margin="0,0,16,0"
FontFamily="Segoe MDL2 Assets"
Foreground="{StaticResource SystemColorHighlightColor}"
Glyph=""
RelativePanel.AlignLeftWithPanel="True"
Visibility="{Binding Name, Converter={StaticResource MusicVisibilityConverter}}" />
<TextBlock
x:Name="MusicNameTextBlcok"
Grid.Column="1"
Width="720"
Text="{x:Bind Name}"
Foreground="{x:Bind IsPlaying,Converter={StaticResource MyConvert},Mode=OneWay}"/>
.cs
public class ColorConvert : IValueConverter
{
// this does not include sublevel menus right now
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value.ToString() == "False")
{
return Helper.BlackBrush;
}
else
{
return Helper.GetHighlightBrush();
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Finally,when the MusicSwitching is triggered,you can reset IsPlaying property.In this case,the foreground will also change together.

Related

How to have a custom display in ListBox with DataTemplate?

I need to display cards in a ListBox in a specific layout:
https://imgur.com/a/0U8eqTc
I've tried to find a way to use 2 types of DataTemplate but I have no idea how to do it. I decided to make a template which contains 6 card Template (like this):
https://imgur.com/VrOlYcR
Here's what my current Template looks like:
<ControlTemplate x:Key = "CardTemplate" TargetType = "Button">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding Path=Image}"/>
<TextBlock Grid.Row="1" Text="{Binding Path=Titre}"/>
</Grid>
</ControlTemplate>
<DataTemplate x:Key="DataTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Grid.Row="0" Template="{StaticResource CardTemplate}"/>
<Grid Grid.Column="1" Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Template="{StaticResource CardTemplate}"/>
<Button Grid.Row="1" Template="{StaticResource CardTemplate}"/>
</Grid>
<Grid Grid.Column="0" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Template="{StaticResource CardTemplate}"/>
<Button Grid.Row="1" Template="{StaticResource CardTemplate}"/>
</Grid>
<Button Grid.Column="1" Grid.Row="1" Template="{StaticResource CardTemplate}"/>
</Grid>
</DataTemplate>
Which I intend to display in a ListBox:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Name="ListBox" ItemTemplate="{DynamicResource DataTemplate}"
ScrollBar.Scroll="ScrollOnBottom">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
Here's how my cod behind basically works:
class Cards
{
public List<Card> cards; // list of 6 Card objects
}
class Card
{
string title;
BitmapImage image;
public string Title { get => title; set => title = value; }
public BitmapImage Image { get => image; set => image = value; }
}
ObservableCollection<Cards> cc = new ObservableCollection<Cards>();
/*
Cards are already filled with 6 Card
cc filled with Cards
*/
formationListBox.ItemsSource = cc;
Here's the problem, it displays the right amount of Cards but the buttons are empty. I don't know how to bind a specific object to each button.
To Give an example of what Sinatr commented. You should approach this from an Mvvm perspective. first you should add a View Model for the View that this Window is in. This will contain a list of objects that are DisplayCards each object will store the string and image.
public class DisplayCard : INotifyPropertyChanged
{
private string _title;
public string Title
{
get { return _title; }
set
{
if (value != _title) { _title = value; RaisePropertyChanged(); }
}
}
private string _cardImage;
public string CardImage
{
get { return _cardImage; }
set
{
if (value != _cardImage) { _cardImage = value; RaisePropertyChanged(); }
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class YourViewVM : INotifyPropertyChanged
{
private ObservableCollection<DisplayCard> _cardCollection;
public ObservableCollection<DisplayCard> CardCollection
{
get { return _cardCollection; }
set
{
if (value != _cardCollection) { _cardCollection = value; RaisePropertyChanged(); }
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then you need to make the list CardCollection set to the ListBox's ItemSource. Then use a datatemplate to bind the DisplayCards properties to the containing object.
<ListBox Name="lbTodoList" HorizontalContentAlignment="Stretch" ItemSource="{Binding CardCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding Image}"/>
<TextBlock Grid.Row="1" Text="{Binding Title}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You need to make sure you set the YourViewVM As the DataContext of the View. A simple search should solve how to do that.
The above should be enough to allow you to refactor your code such that it works.

Problems with Visibility Binding in DataTemplate

I don't know why but my Visibility Binding isn't working ONLY in the DataTemplate. Did I forget something?
Edit: All Bindings (except for this one work perfectly)
Thats the structure.
<Window>
<Grid>
<Grid>
<Grid Grid.Row="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl x:Name="Targets" Margin="0,4,0,4">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,5,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox TextWrapping="Wrap" Foreground="{Binding Foreground, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" Text="{Binding Address, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" Tag="{Binding}" PreviewKeyDown="ChangeLocationAddress" PreviewGotKeyboardFocus="TxtGotKeyboardFocusHandler" LostKeyboardFocus="ChangeLocationAddress" />
<Button Margin="2,0,0,0" Grid.Column="1" Content=" ↑ " Click="MoveLocationUp" Visibility="Visible" />
<Button Margin="2,0,0,0" Grid.Column="2" Content=" ↓ " Click="MoveLocationDown" Visibility="{Binding Path = UpDownButtonVisibility, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button x:Name="btnNewAddress" Grid.Row="1" Content="Neues Ziel hinzufügen" Margin="0,4,0,4" Visibility="{Binding Path=TargetButtonVisibility}"/>
</Grid>
</Grid></Grid></Grid></Window>
Codebehind:
public MapView(){
this.DataContext = this.ViewModel = new MapVM();
this.InitializeComponent();
this.Targest.Itemssource = this.ViewModel.ToLocations;
}
ViewModel:
public MapVM()
{ this.UpDownButtonVisibility = Visibility.Collapsed;
this.TargetButtonVisibility = Visibility.Collapsed;
}
private Visibility _UpDownButtonVisibility;
/// <summary>
/// Property Visibility für "↓" und "↑"
/// </summary>
public Visibility UpDownButtonVisibility
{
get { return _UpDownButtonVisibility; }
set
{
this._UpDownButtonVisibility = value;
NotifyPropertyChanged("UpDownButtonVisibility");
}
}
public Visibility TargetButtonVisibility { get; set; }
EDIT:
Program Output:
BindingExpression path error: 'UpDownButtonVisibility' property not found on 'object' ''Location' (HashCode=-794088449)'. BindingExpression:Path=UpDownButtonVisibility; DataItem='Location' (HashCode=-794088449); target element is 'Button' (Name=''); target property is 'Visibility' (type 'Visibility') 1.10s
Any suggestions?
I cannot find a PropertyChanged event handler and a call to it in your code. Add the INotifyPropertyChanged to your DataContext object and it should work
Personally I would model the visibility as a bool and use the BooleasnToVisibility Converter that comes with WPF.
Change string to Visibility
public Visibility UpDownButtonVisibility { get; set; }
this.UpDownButtonVisibility = Visibility.Collapsed;
Add INPC and binding to a View model.
Here is working sample:
XAML
<Window x:Class="ItemsControlDataTemplate.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ItemsControlDataTemplate"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<ItemsControl x:Name="Targets" Margin="0,4,0,4" ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,5,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox TextWrapping="Wrap" Foreground="{Binding Foreground, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" Text="{Binding Address, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" Tag="{Binding}" />
<Button Margin="2,0,0,0" Grid.Column="1" Content=" ↑ " Visibility="Visible" />
<Button Margin="2,0,0,0" Grid.Column="2" Content=" ↓ " Visibility="{Binding Path=UpDownButtonVisibility}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
C#
class MainWindowViewModel : INotifyPropertyChanged
{
ObservableCollection<MapVM> _items = new ObservableCollection<MapVM>();
public ObservableCollection<MapVM> Items { get { return _items; } }
public MainWindowViewModel()
{
Items.Add(new MapVM() { UpDownButtonVisibility = Visibility.Visible, Address = "1111111" });
Items.Add(new MapVM() { UpDownButtonVisibility = Visibility.Collapsed, Address = "222222" });
Items.Add(new MapVM() { UpDownButtonVisibility = Visibility.Visible, Address = "33333333" });
}
public event PropertyChangedEventHandler PropertyChanged;
}
class MapVM : INotifyPropertyChanged
{
public MapVM()
{
this.UpDownButtonVisibility = Visibility.Collapsed;
this.TargetButtonVisibility = Visibility.Collapsed;
}
private Visibility _upDownButtonVisibility;
public Visibility UpDownButtonVisibility
{
get { return _upDownButtonVisibility; }
set
{
_upDownButtonVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(UpDownButtonVisibility)));
}
}
private Visibility _targetButtonVisibility;
public Visibility TargetButtonVisibility
{
get { return _targetButtonVisibility; }
set
{
_targetButtonVisibility = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TargetButtonVisibility)));
}
}
private string _address;
public string Address
{
get { return _address; }
set
{
_address = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Address)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
The DataContext of your TargetButtonVisibility binding is your main MapVM. This works ok.
The DataContext within your DataTemplate is not MapVM, is it the item being displayed by the template.
Since you have not supplied any ItemsSource binding on your ItemsControl we have no way of knowing what this actually is.
Also, as unkreativ points out, do not use Visibility in your VM, since this is a view related type. Use bool instead and call the property IsUpDownButtonVisible or similar.
EDIT: Assuming you do actually want to bind to your single MapVM, you could use a RelativeSource to find the parent ItemsControl:
<Button Margin="2,0,0,0"
Grid.Column="2"
Content=" ↓ "
Click="MoveLocationDown"
Visibility="{Binding DataContext.UpDownButtonVisibility,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}"/>
However, since you've already named your ItemsControl (Targets), you can simply refer to it by name:
<Button Margin="2,0,0,0"
Grid.Column="2"
Content=" ↓ "
Click="MoveLocationDown"
Visibility="{Binding DataContext.UpDownButtonVisibility,
ElementName=Targets}"/>

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. ;-)

DataBinding To Two Sources

I have a need to use two listboxes, each bound to a different collection.
i originally had this working with one listbox and binding before the need to bind two came up.
Here is how I was doing that.
<Window x:Class="TeamManager.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc ="clr-namespace:TeamManager"
Title="Game Manager" Height="800" Width="800">
<Window.Resources>
<DataTemplate DataType="{x:Type loc:Game}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Name="dateBlock" Grid.Column="0" Grid.Row="1" Text="{Binding Date, StringFormat=d}"></TextBlock>
<TextBlock Name="TimeBlock" Grid.Column="1" Grid.Row="1" Text="{Binding Time}"></TextBlock>
<Button Grid.Row="1" Grid.Column="2" CommandParameter="{Binding Id}" Click="Manage_Click" >Manage</Button>
<Button Grid.Row="1" Grid.Column="3" CommandParameter="{Binding Id}" Click="Delete_Click" Height="16" Width="16">
<Image Source="/Images/DeleteRed.png"></Image>
</Button>
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<StackPanel>
<TextBlock>Upcomming Games</TextBlock>
<ListBox ItemsSource="{Binding}" Name="GameList"></ListBox>
</StackPanel>
<StackPanel Orientation="Vertical" HorizontalAlignment="Left">
<Button Height="30" Width="100" Margin="10,10,10,10" Click="AddGame_Click">Add New Game</Button>
</StackPanel>
</StackPanel>
</StackPanel>
And my code simply set the DataContext of the window to a ObservableCollection
with the need to use TWO collections I created a wrapper class like this
public class AppModel
{
public ObservableCollection<Game> gameCollection { get; set; }
public ObservableCollection<Player> playerCollection { get; set; }
}
And my CS is now setting the DataContext to an object of AppModel
GameDBEntities _entity = new GameDBEntities();
AppModel _model;
public MainWindow()
{
InitializeComponent();
DataContext = model;
}
AppModel model
{
get
{
if (_model == null)
{
_model = new AppModel();
}
if (_model.gameCollection == null)
{
_model.gameCollection = new ObservableCollection<Game>(_entity.Games);
}
if (_model.playerCollection == null)
{
_model.playerCollection = new ObservableCollection<Player>(_entity.Players);
}
return _model;
}
set { }
}
In my Xaml, how can I set the datacontext of the existing listBox to be bound to the Collection Of Games in The AppModel?
Once I get that working I will work on the second listbox on my own.
Thanks!
You need to add a Path to the Binding. The DatacContext will be the model, the path should point to either collection:
<ListBox ItemsSource="{Binding gameCollection}" ...
Would changing the Binding to <ListBox ItemsSource="{Binding Path=gameCollection}" Name="GameList"></ListBox> solve your problem?
As per your question you state that you used to set the DataContext to the gameCollection, but now that you have changed this to use the AppModel, you will need to also change your binding as appropriate.
This will essentially change the Binding from being just bound to gameCollection, it will now be set to use AppData.gameCollection.

Binding depending of type in WPF

I have a ParentViewModel which has ObservableCollection named Notices.
public class Notice
{
public string Content { get; set; }
public NoticeType Type { get; set; }
}
I have static controls at user control where I want to bind this observablecollection to this static controls.
And I don't know how binding this Notices depending of its Types.
I want bind notice with Type FirstType to "first row" and notice with Type SecondType to "second row"
Also If user check checkbox Notice should be removed from collection.
There are my codes
<UserControl x:Class="Repo.UserControlNotices"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="Auto" Width="Auto">
<Grid DataContext="{Binding}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox Text="FirtNotice" >
</TextBox>
<StackPanel Grid.Row="0" Grid.Column="1">
<TextBox Text="{Binding Path =Content}" >
</TextBox>
<CheckBox >
</CheckBox>
</StackPanel>
<TextBox Grid.Row="1" Text="SecondNotice">
</TextBox>
<StackPanel Grid.Row="1" Grid.Column="1">
<TextBox Text="{Binding Path =Content}" >
</TextBox>
<CheckBox >
</CheckBox>
</StackPanel>
</Grid>
</UserControl>
class ParentViewModel
{
public ObservableCollection<Notice> Notices { get; set; }
public ParentViewModel()
{
ObservableCollection<Notice> loadedNotices = new ObservableCollection<Notice>();
loadedNotices.Add(new Notice() { Content = "Something", Type = NoticeType.FirstType });
loadedNotices.Add(new Notice() { Content = "Something", Type = NoticeType.SecondType });
Notices = loadedNotices;
}
}
<Window x:Class="Repo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Repo="clr-namespace:Repo" Title="Window1" Height="300" Width="300">
<Window.Resources>
<Repo:ParentViewModel x:Key="parentVM"/>
</Window.Resources>
<Window.DataContext>
<StaticResourceExtension ResourceKey="parentVM"/>
</Window.DataContext>
<Grid>
<Repo:UserControlNotices DataContext="{Binding Path=Notices}">
</Repo:UserControlNotices>
</Grid>
</Window>
This is example in winforms:
I'm not exactly sure what your asking but I think you most likely need to use the IValueConverter interface. You declare a new class implementing the IValueConverter interface and implement the Convert and ConvertBack methods like so
public Converter implements IValueConverter{
Object Convert(value, targetType, parameter, culture){
// 'value' has the bound value from the xaml
// do some converting and return the result
}
Object Convert(value, targetType, parameter, culture){
// you can figure this one out, usually used for a two-way relationship
}
}
In the xaml, you need a ResourceDictionary in your xaml with something like
xmlns:y="clr-namespace:NamespaceWithClass">
<y:Converter x:Key="someName" />
And reference this converter in your controls
<TextBox Text="{Binding Content, Converter={StaticResource someName}}" >
</TextBox>
Not sure if this is exactly what your looking for but I hope it helps.
Is it not easier to just have two properties on ParentViewModel, e.g.,...
public static IEnumerable<Notice> FirstTypeNotices
{
get
{
return Notices.Where(n => n.Type == NoticeType.FirstType);
}
}
...and bind to those?
You'll probably have to hook up to the Notices.CollectionChanged event and raise PropertyChanged events for each of the two properties.

Categories

Resources