I have done something very bad, because I cannot get it to work at all the way I think I should do it.
I am writing a small test harness which is to be used to help my testing team test the use of another service I have written, but in order to test the service I need a client.
Basically I have a list of tweets that I am displaying to the user, and I want them to be able to click on the tweet to find out the original raw payload that was sent via twitter.
my XAML is as follows:
<ItemsControl x:Name="ActivitiesList" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Black" Margin="2">
<Grid Height="100">
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="50"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="300"/>
</Grid.ColumnDefinitions>
<Image Width="Auto" Height="Auto" Source="{Binding Avatar}" Grid.ColumnSpan="1" Grid.RowSpan="2" Grid.Column="0" Grid.Row="0" Margin="2,2,2,2" />
<TextBlock Text="{Binding Author}" Grid.ColumnSpan="3" Grid.RowSpan="1" Grid.Column="1" Grid.Row="0" />
<TextBlock Text="{Binding Id}" Grid.ColumnSpan="1" Grid.RowSpan="1" Grid.Column="3" Grid.Row="0" Margin="0,0,0,0" />
<Border BorderThickness="0" x:Name="border" Grid.ColumnSpan="3" Grid.RowSpan="1" Grid.Column="1" Grid.Row="1" Margin="0.5" />
<TextBlock Text="{Binding Body}" TextAlignment="Left" TextWrapping="Wrap" Grid.ColumnSpan="3" Grid.RowSpan="1" Grid.Column="1" Grid.Row="1" Width="{Binding ActualWidth, ElementName=border}" Height="{Binding ActualHeight, ElementName=border}" />
<TextBlock Text="Tags:" Grid.ColumnSpan="1" Grid.RowSpan="1" Grid.Column="0" Grid.Row="2" />
<ItemsControl ItemsSource="{Binding Tags}" Grid.ColumnSpan="2" Grid.Row="2" Grid.Column="1" Margin="0,0,0,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1,1,1,1" BorderBrush="Black" CornerRadius="5" Margin="1,1,1,1" >
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFFFEEEE" Offset="0"/>
<GradientStop Color="#FFFFEBEB" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<TextBlock Text="{Binding}" Margin="3,0,3,0" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="View Raw Data" Grid.Column="3" Grid.Row="2" HorizontalAlignment="Right" Width="105" Tag="{Binding}" Click="ButtonBase_OnClick" />
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<!--<local1:Tweet Id="tag:search.twitter.com,2005:823502379551248384 ( 1000 )" Author="jim parslow" Body="This is the content and is going to be very long so that it takes over the page more and more and more" Avatar="https://pbs.twimg.com/profile_images/539113272553648128/sWcgnCan_normal.jpeg" >
<local1:Tweet.Tags>
<System:String>Tag 1</System:String>
<System:String>Tag 2</System:String>
<System:String>Tag 3</System:String>
</local1:Tweet.Tags>
</local1:Tweet>
<local1:Tweet Id="tag:search.twitter.com,2005:823502379551248384 ( 1001 )" Author="jim parslow" Body="This is the content balh" Avatar="https://pbs.twimg.com/profile_images/539113272553648128/sWcgnCan_normal.jpeg" />
<local1:Tweet Id="tag:search.twitter.com,2005:823502379551248384 ( 1002 )" Author="jim parslow" Body="This is the content blah 2" Avatar="https://pbs.twimg.com/profile_images/539113272553648128/sWcgnCan_normal.jpeg" />-->
</ItemsControl>
I have added a button in and attached the entire datacontext item into the tag property of the button.
<Button Content="View Raw Data" Grid.Column="3" Grid.Row="2" HorizontalAlignment="Right" Width="105" Tag="{Binding}" Click="ButtonBase_OnClick" />
Then in the code I grab this out on button click:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var buttonClicked = (Button) sender;
var tag = buttonClicked.Tag;
Console.WriteLine("");
}
I have tried using a button with command, but can't get to work.
I have tried to use events from other controls and add mouse clicks on the grid, but again I cannot make this work.
Everything is currently in one xaml file and code file (I know!!)
The tweet class is below:
public class Tweet : INotifyPropertyChanged
{
public string Id { get; set; }
public string Author { get; set; }
public string Body { get; set; }
public string Avatar { get; set; }
public List<string> Tags { get; set; }
public Activity OriginalActivity { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
And everytime I get a new tweet I add it to the list and set the list:
ActivitiesList.ItemsSource = Tweets;
Where Tweets is an observable collection
private ObservableCollection<Tweet> _tweets = new ObservableCollection<Tweet>();
public ObservableCollection<Tweet> Tweets
{
get { return _tweets; }
}
if anyone could tell me the correct way to do this I would be eternally grateful.
EDIT* As asking for an example of how to do this properly wanted to know what I tried:
<Border.InputBindings>
<MouseBinding MouseAction="LeftClick" Command="{Binding DataContext.ShowData, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"/>
</Border.InputBindings>
I also tried this:
<Button Command="{Binding
RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}},
Path=DataContext.ShowData}" CommandParamater="{Binding}" />
But could never get anything to call the property on the tweet
public ICommand ShowData
{
get;
private set;
}
**
Another Edit: Why this no worky?
**
I have this button in the ItemsControl
<Button Content="View Raw Data" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.ShowDataCommand}" CommandParameter="{Binding}" />
And in the code I have the following:
public class Tweet : INotifyPropertyChanged
{
public string Id { get; set; }
public string Author { get; set; }
public string Body { get; set; }
public string Avatar { get; set; }
public List<string> Tags { get; set; }
public Activity OriginalActivity { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
RelayCommand _showData;
public ICommand ShowDataCommand
{
get
{
if (_showData == null)
{
_showData = new RelayCommand(param => this.ShowData((Tweet)param));
}
return _showData;
}
}
public void ShowData(Tweet tweet)
{
Debug.WriteLine("I AM HERE");
}
}
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute) : this(execute, null) { }
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute; _canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter) { _execute(parameter); }
#endregion // ICommand Members
}
Why does this not work?
I get no errors or messages that are saying I have anything wrong.
Can anyone help?
Related
I have an annoying bug that I can't seem to figure out and it is driving me crazy. I have a window with a listbox in it and when an item is selected an new window is opened using mvvm light which displays different details, the problem is when I click on the item in my listbox (BrowseGamesView) the new window that opens (GameDetailsView) does not show the background image unless I click back to the BrowseGamesView. I'm calling to an api and using a converter to build the url for the image. I need the image to show when the new window opens.
GameDetailsView
Where I need the background image to show when the window opens.
<Window.Resources>
<vm:GameDetailsViewModel x:Key="vm"/>
<converters:StringToBackgroundImageConverter x:Key="stringToBackgroundImageConverter"/>
<converters:StringToImageConverter x:Key="stringToImageConverter"/>
</Window.Resources>
<Grid DataContext="{StaticResource vm}">
<Grid.Background>
<ImageBrush ImageSource="{Binding Game.ScreenshotBackground, Converter={StaticResource stringToBackgroundImageConverter}}"/>
</Grid.Background>
</Grid>
BrowseGamesView
Where the listbox is held.
<ListBox ItemsSource="{Binding Games}"
ItemContainerStyle="{DynamicResource ListBoxItemStyle1}"
SelectedItem="{Binding SelectedGame}"
Width="480"
Height="500"
Grid.Row="4">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding cover.image_id, Converter={StaticResource stringToImage}}"
Stretch="Fill"
Width="100"
Height="130"/>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="310"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding name}"
Foreground="White"
FontWeight="Bold"
FontSize="16"
Margin="15 2 0 0"
TextWrapping="Wrap"/>
<TextBlock Text="{Binding aggregated_rating, StringFormat={}{0:F0}, Converter={StaticResource nullRatingConverter}}"
Grid.Column="1"
Foreground="{Binding AggregatedRatingColor}"
FontWeight="Bold"
FontSize="16"
HorizontalAlignment="Center"/>
</Grid>
<ItemsControl Grid.Row="1"
ItemsSource="{Binding DeveloperCompanies}"
Margin="15 2 0 0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="commaTextBlock"
Text=", "
Foreground="White"/>
<TextBlock Text="{Binding company.name}"
Foreground="White"
TextWrapping="Wrap"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="Visibility" TargetName="commaTextBlock" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid Grid.Row="2"
VerticalAlignment="Bottom"
Margin="0 0 0 4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Release Date:"
Foreground="White"
Margin="15 20 0 0"/>
<TextBlock Text="{Binding first_release_date, Converter={StaticResource unixTimestampToDateTimeConverter}}"
Foreground="White"
Margin="10 20 0 0"
Grid.Column="1"/>
</Grid>
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
GameDetailsViewModel
public class GameDetailsViewModel : INotifyPropertyChanged
{
private Game game;
public Game Game
{
get { return game; }
set
{
game = value;
OnPropertyChanged("Game");
}
}
public GameDetailsViewModel()
{
Messenger.Default.Register<Game>(this, NotifyMe);
}
public void NotifyMe(Game sentGame)
{
Game = sentGame;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
BrowseGamesViewModel
public class BrowseGamesViewModel : ViewModelBase, INotifyPropertyChanged
{
private string query;
private Game selectedGame;
private int gamesCount;
private Game game;
public RelayCommand ShowGameDetailsViewCommand { private set; get; }
public string Query
{
get { return query; }
set
{
query = value;
OnPropertyChanged("Query");
}
}
public Game Game
{
get { return game; }
set
{
game = value;
OnPropertyChanged("Game");
}
}
public Game SelectedGame
{
get { return selectedGame; }
set
{
selectedGame = value;
OnPropertyChanged("SelectedGame");
GetGameDetails();
ShowGameDetailsViewCommandExecute();
}
}
public ObservableCollection<Game> Games { get; set; }
public int GamesCount
{
get { return gamesCount; }
set
{
gamesCount = value;
OnPropertyChanged("GamesCount");
}
}
public SearchGamesCommand SearchGamesCommand { get; set; }
public BrowseGamesViewModel()
{
Games = new ObservableCollection<Game>();
SearchGamesCommand = new SearchGamesCommand(this);
ShowGameDetailsViewCommand = new RelayCommand(ShowGameDetailsViewCommandExecute);
}
public void ShowGameDetailsViewCommandExecute()
{
Messenger.Default.Send(new NotificationMessage("ShowGameDetailsView"));
}
private async void GetGameDetails()
{
Game = await IGDBHelper.GetGameInformation(SelectedGame.id);
Messenger.Default.Send(Game);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
BrowseGamesView Code Behind
public partial class BrowseGamesView : Window
{
public BrowseGamesView()
{
InitializeComponent();
Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}
private void NotificationMessageReceived(NotificationMessage msg)
{
if (msg.Notification == "ShowGameDetailsView")
{
var view = new GameDetailsView();
view.Show();
}
}
}
For my current projet i want to make an UI where information are displayed on "tile" which i designed as a Grid with other Label and progress bar into. But i can't figure out how to make those tiles displayed on my main grid.
I already tried Gridview that didn't work with the exemples on the web and making someway without grid isn't really easy.
This is the grid to insert as many times as needed
<Grid Margin="10" Background="AntiqueWhite" Grid.Row="0" Grid.Column="0">
<Label Content="{Binding fieldname}" FontFamily="Arial Black" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,20,0,0"/>
<Label Content="{Binding datebegin}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="85,85,0,0" FontFamily="Arial Black" FontSize="18" />
<Label Content="{Binding dateend}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="285,85,0,0" FontFamily="Arial Black" FontSize="18" />
<ProgressBar Margin="0,150,0,0" Value="{Binding progression}" Background="White" BorderBrush="Black" VerticalAlignment="Top" Height="50" />
</Grid>
I need a way to add the exact tile produced into a grid (or anything else that can get onto a scrollviewer with 3 column and unlimited lines obviously).
Below is the xmal. I have used ItemsControl and the WrapPanel as ItemsPanelTemplate to wrap the ItemsControl's items
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Content="Add" Height="26" Width="75" Command="{Binding Add}" Grid.Row="0"/>
<ScrollViewer Height="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Row="1">
<ItemsControl ItemsSource="{Binding Items}" HorizontalAlignment="Left">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Margin="10,10,0,0" BorderBrush="Black" BorderThickness="1">
<StackPanel Width="200" Height="Auto">
<Label Content="{Binding fieldname}" FontFamily="Arial Black" FontSize="20" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,10,0,0"/>
<Label Content="{Binding datebegin}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,10,0,0" FontFamily="Arial Black" FontSize="18" />
<Label Content="{Binding dateend}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,10,0,0" FontFamily="Arial Black" FontSize="18" />
<ProgressBar Value="{Binding progression}" Margin="5,10,5,10" Background="White" BorderBrush="Black" VerticalAlignment="Top" Height="20" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
And the viewmodel is
public class Item
{
public string fieldname
{
get;
set;
}
public string datebegin
{
get;
set;
}
public string dateend
{
get;
set;
}
public string progression
{
get;
set;
}
public Item(int number)
{
fieldname = "Filed name " + number;
datebegin = "12-12-12";
dateend = "14-12-12";
progression = (5 * number).ToString();
}
}
public class ViewModel
{
public ICollection<Item> Items
{
get;
private set;
}
public ViewModel()
{
Items = new ObservableCollection<Item>();
}
public ICommand Add
{
get
{
return new RelayCommand((a) =>
{
Items.Add(new Item(Items.Count));
});
}
}
}
Relaycommand
public class RelayCommand : ICommand
{
private Action<object> execute;
private Predicate<object> canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute == null || canExecute(parameter);
}
public void Execute(object parameter)
{
execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
I created datatemplate for my listview with 2 button that must user click on if i use my datatemplate in Window everything's is OK and work fine but if I use my datatemplate in Usercontrol click event for my buttons not work so what is the problem? this is my codes:
<ListView Name="lvDataBinding" HorizontalContentAlignment="Stretch" BorderThickness="0" Margin="10" Grid.Row="3" Background="{x:Null}" SelectionChanged="lvDataBinding_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="#f0f4f7">
<StackPanel Background="#f5f6fa" Margin="1,1,1,1" VerticalAlignment="Top">
<Border Background="#edf0f5" BorderThickness="5">
<Grid Background="#ffffff" Height="30">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Background="#ffffff" Margin="5" Orientation="Horizontal">
<Button Height="20" Width="20" BorderBrush="Transparent" BorderThickness="0" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.cmddelete}">
<Button.Background>
<ImageBrush ImageSource="E:\Aks\ICON\colorful-stickers-icons-set\png\32x32\accept.png"/>
</Button.Background>
</Button>
<Button Height="20" Width="20" BorderBrush="Transparent" BorderThickness="0" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.cmdShow}">
<Button.Background>
<ImageBrush ImageSource="E:\Aks\ICON\colorful-stickers-icons-set\png\32x32\accept.png"/>
</Button.Background>
</Button>
</StackPanel>
<TextBlock Name="txtPhon" Foreground="#7c7f84" HorizontalAlignment="Right" Grid.Column="1" Text="{Binding Path=HomePhoneNumber}"
Margin="0,5,5,5"/>
</Grid>
</Border>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And this is my code behind that I created iCommand and bind it to buttons :
public ICommand cmdShow { get; set; }
public ICommand cmddelete { get; set; }
private FrameworkElement Window { get; set; }
int index = 0;
public UserControl1()
{
InitializeComponent();
InitalizeData();
this.DataContext = this;
Window = this;
cmdShow = new RoutedCommand();
cmddelete = new RoutedCommand();
CommandManager.RegisterClassCommandBinding(Window.GetType(), new CommandBinding(cmdShow, cmdShow_Click));
CommandManager.RegisterClassCommandBinding(Window.GetType(), new CommandBinding(cmddelete, cmddelete_Click));
}
protected void cmdShow_Click(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show(lvDataBinding.SelectedIndex + "");
}
protected void cmddelete_Click(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("delete");
}
private void InitalizeData()
{
ObservableCollection<Patient> data = new ObservableCollection<Patient>();
for (int i = 0; i < 3; i++)
{
data.Add(new Patient
{
HomePhoneNumber = "0512-62810609"
});
}
this.lvDataBinding.ItemsSource = data;
}
public class Patient
{
public string HomePhoneNumber { get; set; }
}
Depending where you set the DataContext the Problem is probably caused by
AncestorType={x:Type **Window**}}
I am trying to build a diary app that uses hub as user interface and update the UI after saving the diary. I already implemented the INotifyPropertyChanged but it didn't work. I want the item that is added after saving to appear on the hub immediately.
public class SampleDataGroup : INotifyPropertyChanged
{
public SampleDataGroup()
{
UniqueId = string.Empty;
Title = string.Empty;
Subtitle = string.Empty;
Description = string.Empty;
ImagePath = string.Empty;
Items = new ObservableCollection<DiaryData>();
}
public string UniqueId { get; private set; }
public string Title { get; private set; }
public string Subtitle { get; private set; }
public string Description { get; private set; }
public string ImagePath { get; private set; }
private ObservableCollection<DiaryData> _items;
public ObservableCollection<DiaryData> Items { get{return _items;} private set
{
OnPropertyChanged("Items");
_items = value;
} }
public override string ToString()
{
if (this.Title != null)
{
return this.Title;
}
else
{
System.Diagnostics.Debug.WriteLine("this is null at tostring");
return null;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public sealed class SampleDataSource : INotifyPropertyChanged
{
private static SampleDataSource _sampleDataSource = new SampleDataSource();
private ObservableCollection<SampleDataGroup> _groups = new ObservableCollection<SampleDataGroup>();
public ObservableCollection<SampleDataGroup> Groups
{
get { return this._groups; }
set { }
}
public static async Task<IEnumerable<SampleDataGroup>> GetGroupsAsync()
{
await _sampleDataSource.GetSampleDataAsync();
return _sampleDataSource.Groups;
}
public static async Task<SampleDataGroup> GetGroupAsync(string uniqueId)
{
System.Diagnostics.Debug.WriteLine("GetGroupAsync is entered phase 1");
await _sampleDataSource.GetSampleDataAsync();
// Simple linear search is acceptable for small data sets
System.Diagnostics.Debug.WriteLine("GetGroupAsync is entered phase 2");
var matches = _sampleDataSource.Groups.Where((group) => group.UniqueId.Equals(uniqueId));
if (matches.Count() == 1) return matches.First();
return null;
}
public static async Task<DiaryData> GetItemAsync(string uniqueId)
{
await _sampleDataSource.GetSampleDataAsync();
System.Diagnostics.Debug.WriteLine("GetItemAsync is entered");
// Simple linear search is acceptable for small data sets
var matches = _sampleDataSource.Groups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
if (matches.Count() == 1) return matches.First();
else return null;
}
private async Task GetSampleDataAsync()
{
System.Diagnostics.Debug.WriteLine("GetSampleDataAsync is entered");
//if (this._groups.Count != 0)return;
Uri dataUri = new Uri("ms-appdata:///local/data.json");
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(dataUri);
string jsonText = await FileIO.ReadTextAsync(file);
JsonArray jsonArray = JsonArray.Parse(jsonText);
SampleDataGroup group = new SampleDataGroup();
foreach (JsonValue itemValue in jsonArray)
{
JsonObject itemObject = itemValue.GetObject();
group.Items.Add(new DiaryData(itemObject["Title"].GetString(),
itemObject["Content"].GetString(),
itemObject["Coordinate"].GetString(),
itemObject["UniqueId"].GetString(),
itemObject["ImagePath"].GetString(),
itemObject["VideoPath"].GetString()));
System.Diagnostics.Debug.WriteLine(itemObject["Title"].GetString());
}
this.Groups.Add(group);
System.Diagnostics.Debug.WriteLine("GetSampleDataAsync is finished");
}
//}
public event PropertyChangedEventHandler PropertyChanged;
}
here's my XAML File
<Page
x:Class="DiaryAppHub.HubPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DiaryAppHub"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:DiaryAppHub.Data"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
d:DataContext="{Binding Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:data.json}}"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="HubSectionHeaderTemplate">
<TextBlock Margin="0,0,0,-9.5" Text="{Binding}"/>
</DataTemplate>
<!-- Grid-appropriate item template as seen in section 2 -->
<DataTemplate x:Key="Standard200x180TileItemTemplate">
<Grid Margin="0,0,9.5,9.5" Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="138.5" Width="138.5"/>
<TextBlock Text="{Binding Title}" VerticalAlignment="Bottom" Margin="9.5,0,0,6.5" Style="{ThemeResource BaseTextBlockStyle}"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="StandardTripleLineItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,9.5,0,0" Grid.Column="0" HorizontalAlignment="Left">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="79" Width="79"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}"/>
<TextBlock Text="{Binding Description}" Style="{ThemeResource ListViewItemContentTextBlockStyle}" Foreground="{ThemeResource PhoneMidBrush}" />
<TextBlock Text="{Binding Subtitle}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />
</StackPanel>
</Grid>
</DataTemplate>
<DataTemplate x:Key="StandardDoubleLineItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,9.5,0,0" Grid.Column="0" HorizontalAlignment="Left">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="79" Width="79"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}" Foreground="Black"/>
<TextBlock Text="{Binding Subtitle}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" Foreground="DimGray"/>
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Page.BottomAppBar>
<CommandBar Background="Transparent">
<AppBarButton Icon="Add" Label="Add" Click="add_onclick"/>
<AppBarButton Icon="Add" Label="Shake it!" />
</CommandBar>
</Page.BottomAppBar>
<Grid x:Name="LayoutRoot">
<Hub x:Name="Hub" x:Uid="Hub" Header="diary app hub" Margin="0,0,0,-59" Foreground="DimGray">
<Hub.Background>
<ImageBrush ImageSource="ms-appx:/Assets/desk_paper.png" Stretch="None"/>
</Hub.Background>
<!--<HubSection x:Uid="HubSection1" Header="SECTION 1" DataContext="{Binding Groups}" HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}">
<DataTemplate>
<ListView
ItemsSource="{Binding}"
IsItemClickEnabled="True"
ItemClick="GroupSection_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,27.5">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</HubSection>-->
<HubSection x:Uid="HubSection5" Header="Recent"
DataContext="{Binding Groups[0]}" HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}">
<DataTemplate>
<ListView
AutomationProperties.AutomationId="ItemListViewSection5"
AutomationProperties.Name="Items In Group"
SelectionMode="None"
IsItemClickEnabled="True"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource StandardDoubleLineItemTemplate}"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
</ListView>
</DataTemplate>
</HubSection>
<HubSection x:Uid="HubSection2" Header="All notes" Width ="Auto"
DataContext="{Binding Groups[0]}" HeaderTemplate="{ThemeResource HubSectionHeaderTemplate}" Height="659" >
<DataTemplate>
<GridView
Margin="0,9.5,0,0"
ItemsSource="{Binding Items}"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Items In Group"
ItemTemplate="{StaticResource Standard200x180TileItemTemplate}"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</DataTemplate>
</HubSection>
</Hub>
</Grid>
You need to raise the PropertyChanged event for the model's properties. The UI doesn't get notified as properties like Title,Subtitle don't raise the PropertyChanged event when they are modified. It should be like this:
private string _title;
public string Title
{
get
{
return _title;
}
set
{
if(_title!=value)
{
_title=value;
OnPropertyChanged("Title");
}
}
}
Do this similarly for other properties. Also, you don't need to raise the PropertyChanged event for an ObservableCollection as an ObservableCollection implements INotifyPropertyChanged by default.
First time using a ListBox and after following this , I'm having issues having data actually display. The ListBox is just empty and white with no text in it.
I made a separate textbox to test an individual "Tweet" object out and it is indeed outputting what I want it to. I think my issue either lies in XAML or Tweets. But nothing looks out of place.
Tracing reveals that Tweets successfully adds a proper Tweet object with what I need. But my ListBox Count is always 0.
<Grid Opacity="0.8">
<Grid.Resources>
<local:Tweets x:Key="tweets"/>
</Grid.Resources>
<Rectangle Fill="Gray" Margin="1523,0,0,729" Height="321" Width="389">
<Rectangle.Effect>
<DropShadowEffect/>
</Rectangle.Effect></Rectangle>
<ListBox ItemsSource="{StaticResource tweets}" Height="321" Margin="340,40,1096,0" x:Name="twitterBox" VerticalAlignment="Top" Width="476">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="132">
<!--<Image Source="{Binding imgSrc}" Height="73" Width="73" VerticalAlignment="Top" Margin="0,10,8,0"/>-->
<StackPanel Width="370">
<TextBlock Text="{Binding user}" FontSize="28" />
<TextBlock Text="{Binding tweet}" TextWrapping="Wrap" FontSize="24" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
In my cs:
public class Tweet
{
public String imgSrc { get; set; }
public String user { get; set; }
public String tweet { get; set; }
public Tweet(String user, String tweet, String img)
{
this.imgSrc = img;
this.user = user;
this.tweet = tweet;
}
}
public class Tweets : ObservableCollection<Tweet>
{
public Tweets()
{
}
public void addTweet(Tweet tweet)
{
Add(tweet);
}
}
public void SomeFunction()
{
Tweets myTwitter = new Tweets();
myTwitter.addTweet(new Tweet(tweet.User.ScreenName, tweet.Text, tweet.User.ProfileImageUrl));
}
ItemTemplate code is ok but you should remove this Margin="1523,0,0,729".
ListBox is empty because items source is empty. You should add some items.
To add items in XAML you should add default constructor to Tweet class.
public class Tweet
{
public String imgSrc { get; set; }
public String user { get; set; }
public String tweet { get; set; }
public Tweet(){}
public Tweet(String user, String tweet, String img)
{
this.imgSrc = img;
this.user = user;
this.tweet = tweet;
}
}
And now you can write something like this:
...
<Grid.Resources>
<local:Tweets x:Key="tweets">
<local:Tweet imgSrc="imgSrc1" user="user1" tweet="tweet1" />
<local:Tweet imgSrc="imgSrc2" user="user2" tweet="tweet2" />
</local:Tweets>
</Grid.Resources>
...
Result:
Add items in code-behind.
To do that you should use function: FindResource (msdn).
XAML:
<Grid Name="mainGrid" Opacity="0.8">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.Resources>
<local:Tweets x:Key="tweets">
<local:Tweet imgSrc="imgSrc1" user="user1" tweet="tweet1" />
<local:Tweet imgSrc="imgSrc2" user="user2" tweet="tweet2" />
</local:Tweets>
</Grid.Resources>
<Button Content="Add new item" Click="Button_Click" />
<ListBox x:Name="twitterBox" ItemsSource="{StaticResource tweets}"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="132">
<!--<Image Source="{Binding imgSrc}" Height="73" Width="73" VerticalAlignment="Top" Margin="0,10,8,0"/>-->
<StackPanel Width="370">
<TextBlock Text="{Binding user}" FontSize="28" />
<TextBlock Text="{Binding tweet}" TextWrapping="Wrap" FontSize="24" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Code-behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
var coll = mainGrid.FindResource("tweets") as Tweets;
if (coll != null)
{
coll.Add(new Tweet("user", "name", "url"));
}
}
Second solution:
The better solution will be if you will create an instance of class Tweets in code behind.
XAML:
<Grid Name="mainGrid" Opacity="0.8">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Content="Add new item" Click="Button_Click" />
<ListBox x:Name="twitterBox" ItemsSource="{Binding tweets}"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="132">
<!--<Image Source="{Binding imgSrc}" Height="73" Width="73" VerticalAlignment="Top" Margin="0,10,8,0"/>-->
<StackPanel Width="370">
<TextBlock Text="{Binding user}" FontSize="28" />
<TextBlock Text="{Binding tweet}" TextWrapping="Wrap" FontSize="24" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
tweets = new Tweets();
tweets.Add(new Tweet("user1", "name1", "url1"));
tweets.Add(new Tweet("user2", "name2", "url2"));
tweets.Add(new Tweet("user3", "name3", "url3"));
this.DataContext = this;
}
public Tweets tweets { get; set; }
private void Button_Click(object sender, RoutedEventArgs e)
{
tweets.Add(new Tweet("user4", "name4", "url4"));
}
}
You add tweets to a different collection than the one displayed by the listbox.