Color Binding Not Working for Data Templates in Win8 App - xaml

I'm currently trying to add some sort of a Color Theme feature to a Win8 App I'm working at... I've though of making a binding from a vm, and everything works fine for static UI elements. But, I'm adding some notes (my model) into a DB, and they also appear on the screen into a GridView.
But in the declared DataTemplate for the GridView ItemTemplate, the Color Binding will not work at all...
My template looks like this :
<Grid Grid.Row="3" HorizontalAlignment="Left" Width="200" Height="200">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="60"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="Lavender" Opacity="50"/>
<ScrollViewer Grid.Row="0">
<TextBlock Grid.Row="0" Text="{Binding Content}" Foreground="DodgerBlue" />
</ScrollViewer>
<Border Grid.Row="1" Background="DodgerBlue" Opacity="70"/>
<ScrollViewer Grid.Row="1">
<TextBlock Grid.Row="1" Text="{Binding Subject}" Foreground="LightBlue" />
</ScrollViewer>
<Border Grid.Row="2" Background="DodgerBlue" Opacity="70"/>
<TextBlock Grid.Row="2" Text="{Binding Importance}" Foreground="Black" FontSize="{StaticResource ComboBoxArrowThemeFontSize}" />
</Grid>
What I tried was simply instead of Foreground="DodgerBlue" to Foreground="{Binding ColorTheme}" but it had no effect, the SolidColorBrush was not acquired from vm....
Is there any workaround for this?
Many thanks in advance.

Altough I didn't really find out the actual explanation on why the below works (and I hope someone more experience, maybe could explain me), this post, seemed to have worked for me.
Not very sure, but was a matter of DataContext, so instead of trying a binding like this : Foreground={Binding ColorTheme}, I changed to this : Foreground={Binding DataContext.ColorTheme, ElementName=MyGridViewName}".

Color binding (or better: brush binding) should work just fine - in GridView.ItemTemplate scenario and elsewhere.
You haven't given enough info to pinpoint why it doesn't work in your case, but here is a small sample I've just tried out:
GridView to put in your page:
<GridView Width="600" Height="200" ItemsSource="{Binding GridItems}"
x:Name="GridViewName">
<GridView.ItemTemplate>
<DataTemplate>
<TextBlock Width="50" Height="50"
Foreground="{Binding Color}" Text="{Binding Text}" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
View model class bound as DataContext for your page:
public class ViewModel
{
public ViewModel()
{
GridItems = new List<GridItem>
{
new GridItem {Text = "First", Color = new SolidColorBrush(Colors.White)},
new GridItem {Text = "Second", Color = new SolidColorBrush(Colors.Yellow)},
new GridItem {Text = "Third", Color = new SolidColorBrush(Colors.Green)},
new GridItem {Text = "Fourth", Color = new SolidColorBrush(Colors.Red)},
};
}
}
GridItem class:
public class GridItem
{
public string Text { get; set; }
public Brush Color { get; set; }
}
The result:
EDIT:
I need to point out that inside data template DataContext is set to the current item of the bound collection (GridItems in my case) not to the page DataContext (ViewModel in my case).
This means that by setting {Binding Color} to a control property you're binding to GridItem.Color not to ViewModel.Color. To make the latter work you first need to access the parent DataContext using the ElementName syntax as you already suggested in your own answer: {Binding DataContext.ColorTheme, ElementName=GridViewName} - this binds to a named element on the page and allows you to access its properties, DataContext being ViewModel in this case.

Related

How to make a column with combobox in Avalonia Ui in DataGrid?

Is it possible in Avalonia Ui DataGrid to implement a column with combobox editing cells, that is, to be able to edit a cell simply by opening this very combobox and the user can simply choose from the options provided ?. I tried to implement a DataGrid like this but ran into a problem. I connected the Nuget Avalonia.DataGrid library, connected the styles in App.axaml as it says. As a result, the combobox appears in the DataGrid, but there is no dropdown in it, although the same combobox works fine outside the DataGrid. What is wrong in this code?
//ViewModel
public List<int> Test3 {get;set;}
//View Window
<DataGrid Items="{Binding Tests}" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*" Header="Route" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="combo" Items="{Binding Path=DataContext.Test3, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
You forgot to add the property Tests to your ViewModel.
Also it would probably be good to have a conditional SelectedItem, but that's out of context...
I used this code:
//ViewModel
public List<int> Test3 { get; set; } = new List<int>(new int [] {1, 2, 3});
public List<int> Tests { get; set; } = new List<int>(new int[] { 1, 2 });
//XAML
<DataGrid Items="{Binding Tests}" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*" Header="Route" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="combo" Items="{Binding Path=DataContext.Test3, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Which gives me that result:
In case you did all that and your bindings are working, but you still did not get my result, you would need to provide further context (e.g. which Themes you used, on which operating you run the program, etc.).
Another possible solution is to use the Tag Property according to code example below.
<DataGrid x:Name="myDataGrid"
Items="{CompiledBinding myDataGridItems}"
SelectedItem="{CompiledBinding mySelectedItem}"
Tag="{CompiledBinding myComboBoxItems}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Route">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Items="{Binding Tag, ElementName=myDataGrid}"
ItemTemplate="{StaticResource ComboBoxItemTemplate}" Background="Transparent" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>

Dynamic ListView display based on Itemsource {Binding} to ObservableCollection<"this can change and dictates listview style"?>

Summary of the Question: What is the correct way to manipulate the same, single ObservableCollection in a xaml page's viewmodel (binded to the ListView of the page ), at runtime in order to show different sets of data, each variation of data providing its own ListView-Style via a StyleSelector?
Description:
I have a UWP xaml page with a single ListView, I want this listview to display all different possible data sets the user might want to see. e.g: A dataset could be between one to 15 columns of data, all with headers. The ListView's ItemSource will use binding to an ObservableCollection to populate it. The ObservableCollection can be populated manually or with one of many SQL sourced DataTable's.
<ListView x:Name="UserPageListView"
ItemsSource="{Binding MainListData, Mode=TwoWay}"
Grid.Column="1"
Width="auto"
Background="Gray"
ItemContainerStyleSelector="{StaticResource UserPage_StyleSelector}">
</ListView>
I have tried binding the ItemContainerStyleSelector to provide a xaml ListView Style (which is stored in a ResourceDictionary), based on the data type of the ObservableCollection, or at least that was the idea. I don't know whether the ObservableCollection's data type should be generic or a defined class per data set to view. The latter makes sense, since a StyleSelector would need it for logic to provide the relevant Style. I used StyleSelector instead of DataTemplateSelector since I want the Selector to include HeaderTemplate as well as ItemTemplate(headers of columns change with the different data sets):
public class UserPage_StyleSelector:StyleSelector
{
public Style WatchlistStyle { get; set; }
public Style UserDetailStyle { get; set; }
protected override Style SelectStyleCore(object item, DependencyObject container)
{
if (item is WatchlistData)
return WatchlistStyle;
if (item is UserDetailData)
return UserDetailStyle;
return base.SelectStyleCore(item, container);
}
}
Style example in ResourceDictionary:
<Style TargetType="ListView"
x:Key="UserDetail_ListView"
x:Name="UserDetail_ListView">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Grid Padding="12"
Background="{ThemeResource SystemBaseLowColor}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<TextBlock Text="UserDetails"
Style="{ThemeResource CaptionTextBlockStyle}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding Details}"
FontSize="12"
VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
StyleSelector defined in the xaml page:
<Page.Resources>
<viewModels:UserPage_StyleSelector x:Key="UserPage_StyleSelector"
WatchlistStyle="{StaticResource WatchList_ListView}"
UserDetailStyle="{StaticResource UserDetail_ListView}"/>
</Page.Resources>
The ResourceDictionary is defined in app.xaml.cs. Have I complicated this endeavour far too much by using the wrong approach?
ItemContainerStyle target type is ListViewItem, so you can't make ListView style in ItemContainerStyleSelector.
Derive from your requirement (headers of columns change with the different data sets), you need make GroupStyleSelector and ItemTemplateSelector for different header and columns.
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock
Margin="5"
FontSize="25"
Foreground="Gray"
Text="{Binding Name}"
/>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
For more detail please refer this document.

How to bind to a list of images

I have changed my code to this:
the view:
<phone:Panorama.ItemTemplate>
<DataTemplate>
<ScrollViewer Width="800" HorizontalContentAlignment="Left" Margin="0,50,0,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox x:Name="list_of_images" ItemsSource="{Binding ImagesUrls}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Width="300" Height="300" Source="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
<TextBlock Text="{Binding Title}"
Grid.Row="1"
Loaded="TextBlock_Loaded_1"
Margin="50,0,0,0"
FontSize="23"
TextWrapping="Wrap"
Width="360"
HorizontalAlignment="Left"
Foreground="Black"/>
<TextBox Text="{Binding ContactEmail}"
Grid.Row="2"
BorderBrush="Black"
Width="340"
HorizontalAlignment="Left"
BorderThickness="1"
Margin="40,0,0,0"
Foreground="Black" />
<TextBlock Text="{Binding Body}"
Grid.Row="3"
TextWrapping="Wrap"
Foreground="Black"
Margin="50,5,0,0"
Width="360"
HorizontalAlignment="Left"
FontSize="20" />
</Grid>
and I build a new object with different properties, with one of the properties being a list of strings which represents the imageurls, but I cannot get the images to show?
I have attached screenshots, what in my xaml must I change so that I can display the images, cause at the moment it doesn't show any images but it shows all the other details
code for populating collection:
ObservableCollection<ClassifiedAds> klasifiseerd_source = new ObservableCollection<ClassifiedAds>();
ImagesClassifieds new_Classifieds = new ImagesClassifieds();
ObservableCollection<string> gallery_images = new ObservableCollection<string>();
new_Classifieds.Title = klasifiseerd_source[0].Title;
new_Classifieds.ContactEmail = klasifiseerd_source[0].ContactEmail;
new_Classifieds.Body = klasifiseerd_source[0].Body;
foreach (var item in klasifiseerd_source[0].Gallery.Images)
{
var deserialized = JsonConvert.DeserializeObject<GalleryImages>(item.ToString());
gallery_images.Add(deserialized.ImageUrl);
//new_Classifieds.ImageUrls.Add(deserialized.ImageUrl);
}
new_Classifieds.ImageUrls = gallery_images;
// classifiedPanorama.ItemsSource = new_list;
new_Classifieds_list.Add(new_Classifieds);
classifiedPanorama.ItemsSource = new_Classifieds_list;
public class ImagesClassifieds
{
public string Title { get; set; }
public string ContactEmail { get; set; }
public string Body { get; set; }
public ObservableCollection<string> ImageUrls { get; set; }
}
here is the imageurl format, this works (in another par tof my app I simply bind to 1 image in this format and it works perfectly)
Depending on whether you want to just display a list of images or if you also want to be able to select them, you may either choose an ItemsControl or a ListBox. In both case you have to define a DataTemplate that controls how each item is displayed.
<ItemsControl ItemsSource="{Binding Images}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
or
<ListBox ItemsSource="{Binding Images}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Then you should think about how you define your item class. Just in case you want to be able to dynamically add or remove images from the list and let the UI be automatically updated, you should use an ObservableCollection as container type. As there is a built-in type conversion from string to ImageSource (the type of the Image control's Source property), you may simply use an ObservableCollection<string>.
public class Gal
{
public ObservableCollection<string> Images { get; set; }
}
You may create an instance of that class like so:
var gallery = new Gal();
gallery.Images = new ObservableCollection<string>(
Directory.EnumerateFiles(#"C:\Users\Public\Pictures\Sample Pictures", "*.jpg"));
Now you may directly bind to that instance by simply setting the DataContext of your Window (or wherever the image list should be shown) to this instance:
DataContext = gallery;
Note the binding declaration in the ItemsControl or ListBox above was {Binding Images}. If you really have to have a property Gallery (which I assume is in MainWindow) and bind like {Binding Gallery.Images} you may set the DataContext like this:
DataContext = this;
so I basically created a loaded event on the listbox and added this code
private void list_of_images_Loaded_1(object sender, RoutedEventArgs e)
{
ListBox lst = (ListBox)sender;
lst.ItemsSource = new_Classifieds_list[0].ImageUrls;
}
which binds the itemssource of the listbox to the list of imageurls. since I cannot access the listbox from codebehind due to it being inside the panorama's itemstemplate

Windows StoreApp XAML: Changing ItemTemplate in GridView based on Data type

I am working on developing Windows Store App using C#/XAML. I have experience primarily in iOS and to some extent Android app development, but not yet comfortable with C#/XAML world.
Here is my issue in GridView based page (Based on the nice template VS2012 generates).
I have a gridview and its collection is bound to a data retrieved from network and it works fine.
But I want to change the grid item depending on the data.
For example: I have files and folders that I would like to show using different grid view items.
My Question: How would I use a different DataTemplate for the ItemTemplate depending on the data? For example, for "Folders", I will have only one textblock which is vertically centered and for File, I will have the 2 textblocks and visually different.
Am I going the right path or should I be doing completely different?
The XAML Portion is
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Grid.RowSpan="3"
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource FileEntriesTemplate}"
ItemClick="ItemView_ItemClick"
IsItemClickEnabled="True"
SelectionMode="None"
IsSwipeEnabled="false">
The Template is
<DataTemplate x:Key="FileEntriesTemplate">
<Grid HorizontalAlignment="Left" Width="400" Height="80" Background="Beige">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding Image}" Stretch="Uniform" Grid.Column="0" Margin="10,0,0,0" AutomationProperties.Name="{Binding Title}"/>
<StackPanel Orientation="Vertical" Grid.Column="1" Background="Transparent">
<TextBlock Text="{Binding Title}" Foreground="Black" Style="{StaticResource LargeTitleTextStyle}" Margin="20,20,10,0"/>
<TextBlock Text="{Binding Subtitle}" Foreground="gray" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="20,10,0,30"/>
</StackPanel>
</Grid>
GridView exposes this through the ItemTemplateSelector property which is a class you can create that inherits from DataTemplateSelector. An example would be that I have a GridView that has Issues and Repositories bound to it and want to use different data templates for each.
My data template selector looks like:
public class IssueSummaryTemplateSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return item is IssueGroupViewModel ? IssueTemplate : RepositoryTemplate;
}
public DataTemplate RepositoryTemplate
{
get;
set;
}
public DataTemplate IssueTemplate
{
get;
set;
}
}
I then declare the selector as a Resource in xaml assigning the two templates I want to use for Repository and Issues.
<selectors:IssueSummaryTemplateSelector x:Key="IssueSummarySelector"
IssueTemplate="{StaticResource IssueGridZoomedOutTemplate}"
RepositoryTemplate="{StaticResource IssueGridRepositoryZoomedOutTemplate}"/>
You can then use it on your GridView.
<GridView ItemTemplateSelector="{StaticResource IssueSummarySelector}" />

binding files to longlistselector

Trying to learn Win Phone 8, following along an online tutorial. In the tutorial, the guy uses the ListBox to show files, which is working fine for me.
However, I thought we're supposed to use LongListSelector, so I added that; but nothing shows up.
If I put the LongListSelector first in the markup, neither displays when I run the app in the emulator, so I think I'm getting an exception from binding the LongListSelector. I don't understand why though.
It's pretty simple, click a button and read files in a directory, displaying them back.
<StackPanel x:Name="ContentPanel" Margin="12,0,12,0" Grid.Row="1" >
<Button Content="Show files" Click="Button_Click_1"/>
<ListBox x:Name="lb">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" />
<Image x:Name="img" Source="{Binding Path}" Width="100" Height="100"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<phone:LongListSelector HorizontalAlignment="Left"
x:Name="llsFiles"
ItemTemplate="{StaticResource FilesDataTemplate}"
/>
</StackPanel>
and the LLS template:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="FilesDataTemplate">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
then the code-behind:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
GetPackageFiles();
}
private async Task GetPackageFiles()
{
//Get the folder where the app is installed on the phone.
var installFolder = Package.Current.InstalledLocation;
var imagesFolder = await installFolder.GetFolderAsync("Images");
var fileList = await imagesFolder.GetFilesAsync();
lb.ItemsSource = fileList;
llsFiles.ItemsSource = fileList.ToList();
}
Try this
//add this declaration
List<FirstList> source = new List<FirstList>();
public class FirstList
{
[DataMember]
public string cItem { get; set; }
public FirstList(string item)
{
this.cItem = item;
}
}
Then to add anything you would just do this.
source.Add(new FirstList(fileList.ToString());
make you sure you have the binding for it