Binding listbox to object without window datacontext - c#

I would like to bind my listbox to an object without the wpf window binding to a datacontext:
<ListBox Height="Auto" HorizontalAlignment="Left" Margin="0,0,0,0" Name="lstb_logFiles" VerticalAlignment="Stretch" Width="100" SelectionChanged="lstb_threadList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding dateName,StringFormat=\{0\}}" Foreground="Orange" Margin="10,3,0,3" Width="80" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And here is where I setup the binding
public ObservableCollection<FileLog> _logFiles = new ObservableCollection<FileLog>();
lstb_logFiles.DataContext = _logFiles;
This doesn't work, my _logFiles definitely have object in it, but lstb_logFiles does not show any items. What am I doing wrong?

For ListBox to populate its item, you should set ItemsSource and not DataContext.
It should be:
lstb_logFiles.ItemsSource = _logFiles;
and not
lstb_logFiles.DataContext = _logFiles;

you have to set the itemssource to "self"
<ListBox ItemsSource="{Binding}"/>
or instead of setting the datacontext you can set the itemssource directly
public ObservableCollection<FileLog> _logFiles = new ObservableCollection<FileLog>();
lstb_logFiles.ItemsSource= _logFiles;

Related

How do I prompt a new Window showing the model data from the selected item?

My goal here is to show a new Window when right-clicking an item in the ItemsControl and selecting Edit in the ContextMenu
This is what I have so far.
I have my MainWindow.xaml which would be the MainView of the application
and on that View I have a ItemsControl with the DataTemplate of UserCard which is a custom UserControl.
The ItemsControl has a ItemSource set to my ObservableCollection in my ViewModel
I set the DataContext in the code-behind like so.
public MainWindow()
{
InitializeComponent();
this.DataContext = new BaseViewModel();
}
And here is the XAML
<StackPanel>
<Grid>
<ItemsControl ItemsSource="{Binding CardViewModel.Users}"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultEffectDataTemplate="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:UserCard>
<controls:UserCard.ContextMenu>
<!-- Bind the DataContext of the CM to the DataContext that's bound to the RootObject-->
<ContextMenu DataContext="{Binding DataContext, Source={local:RootObject}}">
<MenuItem Header="Edit"
Command="{Binding CardViewModel.EditUser}"
CommandParameter="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</ContextMenu>
</controls:UserCard.ContextMenu>
</controls:UserCard>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</StackPanel>
Now it does display two UserCard controls because in the ViewModel I've added two objects to the collection of which it's ItemSource derrives from.
However when I click the MenuItem in the ContextMenu I want to open a new Window that displays TextBlock controls and they should be bound to differet properties from my Model.
I have no idea how to pass that model on to the new Window
Here is the UserControl
<TextBlock Text="{Binding Description}"
TextWrapping="Wrap"
Width="180"
VerticalAlignment="Top"
Margin="10"
FontFamily="Consolas"/>
<TextBlock Width="100"
Height="20"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Margin="5"
Text="{Binding Name}"
FontFamily="Consolas" />
<TextBlock Width="100"
Height="20"
VerticalAlignment="Bottom"
HorizontalAlignment="Left"
Text="{Binding Id}"
FontFamily="Consolas"/>
</Grid>
The binding there works just fine! I can see the Name and everything in my ItemsControl MainWindow but when I right click the UserControl and it displays the new Window I don't know how to pass it on.
NewWindow.xaml
<Grid>
<TextBlock Height="25" Text="{Binding SelectedItemViewModel.Name}"/>
</Grid>
ViewModel
class BaseViewModel : ObservableObject
{
public CardViewModel CardViewModel { get; set; } = new CardViewModel();
}
You're binding to SelectedItemViewModel.Name, but I don't see this property in the view model...

Updating Listview after adding/removing item

How can I refresh ListView after adding item to collection in Windows Store app? Adding items to list works fine, but Listview doesn't refresh. I was trying to implement INotifyCollectionChanged, but what exactly should I do to make it work?
edit: XAML file
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView HorizontalAlignment="Left" Height="437" Margin="10,120,0,0" VerticalAlignment="Top" Width="593" ItemsSource="{Binding Persons, Mode=TwoWay}" Background="#FF5D5D5D">
<ListView.DataContext>
<Model:School/>
</ListView.DataContext>
</ListView>
<Button Content="Button" HorizontalAlignment="Left" Margin="7,64,0,0" VerticalAlignment="Top" Command="{Binding AddCommand, Mode=OneWay}">
<Button.DataContext>
<Model:School/>
</Button.DataContext>
</Button>
</Grid>
C# code:
class School
{
private ObservableCollection<string> _persons = new ObservableCollection<string>()
{
"Name1", "Name2", "Name3"
};
public ObservableCollection<string> Persons
{
get { return _persons; }
}
private ICommand _addCommand;
public ICommand AddCommand
{
get
{
return this._addCommand ??
(this._addCommand = new RelayCommand(Add));
}
}
private void Add()
{
this._persons.Add("Name");
}
}
You don't need to add INotifyCollectionChanged when you are using ObservableCollection - it already implements needed interfaces.
Your code should work, though there may be some other problems:
check if the DataContext of your ListView (its parent in this case) is properly set - it should be set, so that 'ListView would find' Persons property,
also check if the ItemTemplate is properly set - example:
<ListView Name="myList" ItemsSource="{Binding Persons}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Surname}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
in your case there is no need that your ListView's ItemsSource uses TwoWay binding - you are not defining a setter ofr the property Persons.
EDIT:
After your edit, I can see where is the problem - you are setting separate DataContext for your ListView and Button - the button is adding to its own collection - different than ListView is bound to. Take a short test - set the DataContext of both to same staticresource:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<Model:School x:Key="mySchool"/>
</Grid.Resources>
<ListView HorizontalAlignment="Left" VerticalAlignment="Stretch" Margin="10,120,0,0" ItemsSource="{Binding Persons}" Background="#FF5D5D5D"
DataContext="{StaticResource mySchool}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="7,64,0,0" VerticalAlignment="Top" Command="{Binding AddCommand, Mode=OneWay}"
DataContext="{StaticResource mySchool}">
</Button>
</Grid>

How to (is it possible to) set property of user control from outside?

This is my XAML:
<UserControl x:Class="SearchResultsBox">
<ListBox ItemsSource="{Binding SearchResults}" SelectedItem="{Binding Selected}"
Style="{StaticResource ListBoxStyle1}"
ItemContainerStyle="{StaticResource SearchItemContainerStyle}"
Background="{StaticResource DefaultBackground}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Transparent">
<local:Forecast_SearchResults_ListView_Data/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl x:Class="SearchResultsBox">
I want to be able to reuse this listbox and just slap on a new datatemplate from the external context:
<local:SearchResultsBox>
<DataTemplate = {ForecastDataTemplate}/>
</local>
And it will put this DataTemplate into the ListBox.ItemTemplate property. Is this even possible? If so, how? If not, is there another way to achieve a similar effect?
you may use as follows
<local:SearchResultsBox ItemTemplate="{StaticResource ForecastDataTemplate}" />
and you can wire up the property to the underlying ListBox
eg
add a name to listbox
<ListBox x:Name="list" ... />
add a property wiring
public DataTemplate ItemTemplate
{
get { return list.ItemTemplate;}
set { list.ItemTemplate = value;}
}

Bind outside ItemsSource of DataTemplate, Windows phone

In my Windows Phone 8 I have LongListSelector and ItemTemplate specified for that. In code behind I set the ItemsSource for this LongListSelector. In item template I want to bind value to outside ItemsSource. How to do that?
<DataTemplate x:Key="template">
<TextBlock Text="{Binding name}"/>
<TextBlock Text="{Binding country}"/>
</DataTemplate>
...
<phone:LongListSelector x:Name="list" ItemTemplate="{StaticResource template}">
</phone:LongListSelector>
C#
string country = "Japan";
this.list.ItemsSource = items;
So how to bind country to outside ItemsSource? The country is accessor in my "code behind" phoneApplicationPage.
It would be best that you make your models so that inside template you have to bind only to that item model.
Anyway it is possible to bind also outside of itemSource:
xaml:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="ItemTemplate">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<!-- this binds to the layoutRoot's dataContext, which can be setted to be "code behind" -->
<TextBlock Text="{Binding DataContext.Outside, ElementName=LayoutRoot}"/>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot">
<phone:LongListSelector ItemsSource="{Binding Items}"
IsGroupingEnabled="False"
ItemTemplate="{StaticResource ItemTemplate}">
</phone:LongListSelector>
</Grid>
In cs you have of course properties:
public ObservableCollection<Model> Items{get; set;}
public string Outside { get; set; }
Also layoutRoot's datacontext should be setted somewhere in cs:
LayoutRoot.DataContext = this;

ListBox ItemsSource Binding doesn't work

I'm developing a Windows Phome application. I have the following ListBox on a page:
<ListBox Margin="10,10,8,8" x:Name="WallList">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="ListBoxItemLayout" Background="Transparent" Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.33*"/>
<ColumnDefinition Width="0.77*"/>
</Grid.ColumnDefinitions>
<Image HorizontalAlignment="Left" Margin="0" Source="{Binding ImagePath}" Height="200"/>
<StackPanel Margin="5,0,0,0" Grid.Column="1">
<TextBlock x:Name="Name" TextWrapping="Wrap" Text="{Binding Name}" Style="{StaticResource PhoneTextTitle2Style}"/>
<TextBlock x:Name="Comment" Margin="0,5,0,0" TextWrapping="Wrap" Text="{Binding Comment}" Style="{StaticResource PhoneTextNormalStyle}" Height="130"/>
<TextBlock x:Name="When" TextWrapping="Wrap" Text="{Binding When}" Style="{StaticResource PhoneTextTitle3Style}" VerticalAlignment="Bottom"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm using this to fill the ListBox on Loaded event:
this.WallList.ItemsSource = StartingWall.GetWallPosts();
And now I want to add more items programmatically when the user write down some text on a TextBox and click on a button. I want to place this text on Comment field.
I'm gooing to fill the rest fields with default data.
My question is:
How can I add more items to WallList ListBox?
Someone has suggested to do the following:
public ObservableCollection<WallPostEntry> MyWallPosts {get;set;}
// Initialize MyWallPosts to whatever
MyWallPosts.Add(new WallPostEntry("new entry"));
<ListBox Margin="10,10,8,8" x:Name="WallList" ItemsSource="{Binding MyWallPosts}">
But Binding ListBox ItemsSource doesn't work for me. I'm initializing MyWallPosts on constructor, just before InitializeComponent();, like this:
public Wall()
{
MyWallPosts = StartingWall.GetWallPosts();
InitializeComponent();
}
Any advice?
Thanks.
I see a couple wierd things:
first, you're using the itemssource binding in one place, but explicitly setting it in another? setting something in code will override/undo any bindings, so that could cause a problem (but it looks like you're setting it to the same thing so that shouldn't make a difference, but i'd remove the this.WallList.ItemsSource = StartingWall.GetWallPosts(); call entirely, and leave the ItemsSource="{Binding MyWallPosts}" in the xaml. the point of using bindings is to get rid of this kind of code)
second, you're setting mywallposts and using a binding, but not setting the datacontext on your object itself? simplest in your example would be to just add one line to your constructor:
public Wall()
{
DataContext = this;
MyWallPosts = StartingWall.GetWallPosts();
InitializeComponent();
}
My next suggestion would be to simplify until it works. leave the listbox but comment out all of the item/data templating to make sure that you don't have a bug in your template
Could he just add
a DataContext property to this:
<ListBox Margin="10,10,8,8" x:Name="WallList" ItemsSource="{Binding MyWallPosts}">
so:
<ListBox Margin="10,10,8,8" x:Name="WallList" ItemsSource="{Binding MyWallPosts}" DataContext="{Binding MyWallPosts}">
Would there be any way of setting the dataContext declarativelly?
tks,
Oscar

Categories

Resources