So im creating an app which allows users to make habit list. It works fine when I try to make new habits. but Im stuck at how to delete them.
this is the XAML for the binding
<PivotItem
Header="HABIT LIST"
Margin="10,10,0,0">
<ScrollViewer>
<!--Habit item template-->
<Grid Margin="0,0,10,0">
<Grid.Resources>
<DataTemplate x:Name="dataTemplate">
<Grid Margin="0,0,0,0"
Holding="ListViewItem_Holding">
<!--ContextMenu-->
<FlyoutBase.AttachedFlyout>
<MenuFlyout>
<MenuFlyoutItem
x:Name="deletehabit"
Text="Delete"
Click="deletehabit_Click"
RequestedTheme="Dark"
/>
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="105" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--ProgressBar-->
<StackPanel
Grid.Column="0"
CommonNavigationTransitionInfo.IsStaggerElement="True">
<ProgressBar
x:Name="habitbar"
Grid.Column="0"
Margin="0,105,-10,-105"
Value="{Binding Dates, Converter={StaticResource CompletedDatesToIntegerConverter}}"
Maximum="21"
Minimum="0"
Foreground="#FF32CE79"
Width="100"
Height="50"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
RenderTransformOrigin="0,0"
Pivot.SlideInAnimationGroup="GroupOne"
FontFamily="Global User Interface"
>
<ProgressBar.RenderTransform>
<CompositeTransform Rotation="270"/>
</ProgressBar.RenderTransform>
</ProgressBar>
</StackPanel>
<!--Details-->
<StackPanel
x:Name="habitdetail"
Grid.Column="1"
Margin="-30,0,0,0" >
<TextBlock
Text="{Binding Name}"
FontSize="24"
Foreground= "#FF3274CE"
FontWeight="Thin"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontFamily="Global User Interface"
Pivot.SlideInAnimationGroup="GroupTwo"/>
<TextBlock
Text="{Binding Description}"
FontSize="18"
FontWeight="Thin"
HorizontalAlignment="Left"
VerticalAlignment="Top"
FontFamily="Global User Interface"
LineHeight="10"
Pivot.SlideInAnimationGroup="GroupTwo"/>
<!--Button-->
<Button
x:Name="CompletedButton"
Content="!"
Command="{Binding CompletedCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding Dates, Converter={StaticResource IsCompleteToBooleanConverter}}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Margin="0,5,0,0"
Background="#FFCE3232"
Foreground="White"
Height="21"
BorderBrush="#FFCE3232"
FontFamily="Global User Interface"
ClickMode="Release"
Pivot.SlideInAnimationGroup="GroupThree"
Width="280"/>
</StackPanel>
</Grid>
</DataTemplate>
</Grid.Resources>
<ListView
x:Name="habitlist"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource dataTemplate}"
Background="{x:Null}"
/>
</Grid>
</ScrollViewer>
</PivotItem>
this is the code behind for deleting the habit which I don't know what to type
private void ListViewItem_Holding(object sender, HoldingRoutedEventArgs e)
{
FrameworkElement senderElement = sender as FrameworkElement;
FlyoutBase flyoutBase = FlyoutBase.GetAttachedFlyout(senderElement);
flyoutBase.ShowAt(senderElement);
}
private void deletehabit_Click(object sender, RoutedEventArgs e)
{
//TODO
}
and heres the datamodel
public class Habit : INotifyPropertyChanged
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ObservableCollection<DateTime> Dates { get; set; }
[IgnoreDataMember]
public ICommand CompletedCommand { get; set; }
public Habit()
{
CompletedCommand = new CompletedButtonClick();
Dates = new ObservableCollection<DateTime>();
}
public void AddDate()
{
Dates.Add(DateTime.Today);
NotifyPropertyChanged("Dates");
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class DataSource
{
private ObservableCollection<Habit> _habits;
const string fileName = "habits.json";
public DataSource()
{
_habits = new ObservableCollection<Habit>();
}
public async Task<ObservableCollection<Habit>> GetHabits()
{
await ensureDataLoaded();
return _habits;
}
private async Task ensureDataLoaded()
{
if (_habits.Count == 0)
await getHabitDataAsync();
return;
}
private async Task getHabitDataAsync()
{
if (_habits.Count != 0)
return;
var jsonSerializer = new DataContractJsonSerializer(typeof(ObservableCollection<Habit>));
try
{
// Add a using System.IO;
using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(fileName))
{
_habits = (ObservableCollection<Habit>)jsonSerializer.ReadObject(stream);
}
}
catch
{
_habits = new ObservableCollection<Habit>();
}
}
public async void AddHabit(string name, string description)
{
var habit = new Habit();
habit.Name = name;
habit.Description = description;
habit.Dates = new ObservableCollection<DateTime>();
_habits.Add(habit);
await saveHabitDataAsync();
}
private async Task saveHabitDataAsync()
{
var jsonSerializer = new DataContractJsonSerializer(typeof(ObservableCollection<Habit>));
using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync(fileName,
CreationCollisionOption.ReplaceExisting))
{
jsonSerializer.WriteObject(stream, _habits);
}
}
public async void CompleteHabitToday(Habit habit)
{
int index = _habits.IndexOf(habit);
_habits[index].AddDate();
await saveHabitDataAsync();
}
}
im very new to programming
thanks
If I understand the question correctly, just call the
NameOfCollectionGoesHere.Remove()
Method.
You can also clear the entire collection with
.Clear()
Is that what you are asking for?
Related
I have a user list in MainWindow. After pressing the preview button, a non-modal window for data editing opens. Updated data are changed in real time in the main window. The question is how to bind the windows so that because the user changes from the list in the main window, he changes in real time in an already open non-modal window.
WPF does not recommend coding business logic directly in xaml.cs
files.
It is recommended that you write code using the MVVM pattern
ViewModel
public class podgladUzytkownika : INotifyPropertyChanged
{
private string imie;
private string nazwisko;
private string mail;
public string Mail
{
get => mail;
set => this.SetValue(ref mail, value);
}
public string Nazwisko
{
get => nazwisko;
set => this.SetValue(ref nazwisko, value);
}
public string Imie
{
get => imie;
set => this.SetValue(ref imie, value);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void SetValue<T>(ref T oldValue, T newValue, [CallerMemberName] string propertyName = null)
{
oldValue = newValue;
OnPropertyChanged(propertyName);
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MainWindowViewModel
{
private int refreshCount;
public ICommand RefreshCommand { get; }
public ICommand PodgladUzytkownikaShow { get; }
public podgladUzytkownika data { get; }
public MainWindowViewModel()
{
data = new podgladUzytkownika();
PodgladUzytkownikaShow = new Command(PodgladUzytkownikaShowExecute);
RefreshCommand = new Command(RefreshCommandExecute);
}
private void PodgladUzytkownikaShowExecute(object obj)
{
var window = new Window();
window.DataContext = data;
window.Show();
}
private void RefreshCommandExecute(object obj)
{
// Data updates are passed to the view
refreshCount++;
data.Imie = nameof(data.Imie) + refreshCount;
data.Nazwisko = nameof(data.Nazwisko) + refreshCount;
data.Mail = nameof(data.Mail) + refreshCount;
}
}
View
// MainWindow.xaml
<StackPanel x:Name="StackPanel1">
<Button Content="PodgladUzytkownika" Command="{Binding Path=PodgladUzytkownikaShow}"/>
<Button Content="Refresh" Command="{Binding Path=RefreshCommand}"/>
</StackPanel>
// window.xaml
<StackPanel >
<TextBlock Text="{Binding Path=Imie }"/>
<TextBlock Text="{Binding Path=Nazwisko }"/>
<TextBlock Text="{Binding Path=Mail }"/>
</StackPanel>
Demo
this.MainWindow.DataContext =new MainWindowViewModel();
After chasing one problem after another with your comments, the problem is your code is not well-designed. Using data bindings (one of the prime benefits of WPF), you can stop chasing your tail with trying to figure out how to update one UI when data changes. Here is a simplified version of your code that will always ensure the UI matches the data you wish to manipulate.
MainWindow.xaml
<Grid Margin="3">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Label Margin="3" Grid.ColumnSpan="3">Lista użytkowników</Label>
<Button Margin="3" Padding="3" Grid.Row="2" Grid.ColumnSpan="3" Click="Zamknij_Click">Zamknij</Button>
<StackPanel Margin="3" Grid.Column="2" Grid.Row="1">
<!--<Button Name="Dodaj" Click="Dodaj_Click" Margin="3" Padding="10,3" >Dodaj...</Button>-->
<!--<Button Name="Usun" IsEnabled="False" Click="Usun_Click" Margin="3" Padding="10,3" >Usuń</Button>-->
<!--<Button Name="Edytuj" IsEnabled="False" Click="Edytuj_Click" Margin="3" Padding="10,3" >Edytuj...</Button>-->
<Button Name="Podglad" IsEnabled="False" Click="Podglad_Click" Margin="3" Padding="10,3" >Podgląd...</Button>
</StackPanel>
<ListView SelectionMode="Single" SelectionChanged="Selection_Changed" Name="lv_uzytkownicy" Margin="3" Grid.Row="1">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Imię"
DisplayMemberBinding="{Binding Imie}"/>
<GridViewColumn Header="Nazwisko"
DisplayMemberBinding="{Binding Nazwisko}" />
<GridViewColumn Header="Mail"
DisplayMemberBinding="{Binding Mail}"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<GridSplitter Grid.Column="1" Grid.Row="1" Width="5" ResizeDirection="Columns" HorizontalAlignment="Center"/>
</Grid>
MainWindow.xaml.cs
using System.Collections.ObjectModel;
public partial class MainWindow : Window
{
public ObservableCollection<Uzytkownik> listaUzytkownikow = new ObservableCollection<Uzytkownik>();
Podglad_Uzytkownika podgladUzytkownika;
public MainWindow()
{
InitializeComponent();
lv_uzytkownicy.ItemsSource = listaUzytkownikow;
listaUzytkownikow.Add(new Uzytkownik("Mietek", "Żul", "sikalafa#wp.pl"));
listaUzytkownikow.Add(new Uzytkownik("Franek", "Alpinista", "halo#gmail.pl"));
listaUzytkownikow.Add(new Uzytkownik("Stefan", "Ulążka", "mam.to#o2.pl"));
this.DataContext = this;
}
private void Podglad_Click(object sender, RoutedEventArgs e)
{
podgladUzytkownika = new Podglad_Uzytkownika();
podgladUzytkownika.DataContext = lv_uzytkownicy.SelectedItem;
podgladUzytkownika.Show();
}
private void Zamknij_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void Selection_Changed(object sender, SelectionChangedEventArgs e)
{
if (lv_uzytkownicy.SelectedItems.Count > 0) Podglad.IsEnabled = true;
else Podglad.IsEnabled = false;
if (podgladUzytkownika != null && podgladUzytkownika.IsVisible)
{
podgladUzytkownika.DataContext = lv_uzytkownicy.SelectedItem;
}
}
}
Podglad_Uzytkownika.xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Margin="3">Imię</Label>
<Label Margin="3" Grid.Row="1">Nazwisko</Label>
<Label Margin="3" Grid.Row="2">Email</Label>
<TextBox Name="imieTextBox" Text="{Binding Imie, UpdateSourceTrigger=PropertyChanged}" Margin="3" Grid.Column="1"/>
<TextBox Name="nazwiskoTextBox" Text="{Binding Nazwisko, UpdateSourceTrigger=PropertyChanged}" Margin="3" Grid.Column="1" Grid.Row="1"/>
<TextBox Name="mailTextBox" Text="{Binding Mail, UpdateSourceTrigger=PropertyChanged}" Margin="3" Grid.Column="1" Grid.Row="2"/>
<Grid HorizontalAlignment="Center" Grid.ColumnSpan="2" Grid.Row="3" Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="pierwsza" />
</Grid.ColumnDefinitions>
<Button Margin="3" Padding="20, 5" Name="Podglad" Click="Podglad_Click" IsDefault="True">Zamknij</Button>
</Grid>
</Grid>
Podglad_Uzytkownika.xaml.cs
public partial class Podglad_Uzytkownika : Window
{
public Podglad_Uzytkownika()
{
InitializeComponent();
}
private void Podglad_Click(object sender, RoutedEventArgs e)
{
Close();
}
}
Uzytkownik.cs
public class Uzytkownik : INotifyPropertyChanged
{
private string imie;
private string nazwisko;
private string mail;
public Uzytkownik(string imie, string nazwisko, string mail)
{
this.Imie = imie;
this.Nazwisko = nazwisko;
this.Mail = mail;
}
public string Imie { get => this.imie; set { this.imie = value; OnPropertyChanged(); } }
public string Nazwisko { get => this.nazwisko; set { this.nazwisko = value; OnPropertyChanged(); } }
public string Mail { get => this.mail; set { this.mail = value; OnPropertyChanged(); } }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
After adding a text view to my MasterDetailsView I noticed an anomaly of this item which can cause an inconvenience for users. In the interest of user experience (UX) and to prevent confusion to the user, is there a way to disable the back button on the Command Bar when the MasterDetailsView is showing the Detail pane only (and NOT showing the Master pane)? This would normally be when the window is snapped or less than a certain width + if both pane are showing, I then want the command bar back button to reappear
Master pane (snapped/short window mode)
Details pane (snapped/short window mode)
XAML (MasterDetailsView page - loaded inside Frame within main page)
<Grid x:Name="RootGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Margin="0,0,0,20" Grid.Row="0">
<TextBlock x:Name="txtMDPageTitle" Text="Mail" x:FieldModifier="public" Style="{StaticResource HeaderTextBlockStyle}" />
<TextBlock x:Name="txtMDPageSubtitle" Text="name.surname#domain.com" x:FieldModifier="public" Style="{StaticResource SubheaderTextBlockStyle}"/>
</StackPanel>
<controls:MasterDetailsView
x:Name="MyMasterDetailsView"
Grid.Row="1"
BackButtonBehavior="Automatic"
CompactModeThresholdWidth="720"
ItemsSource="{x:Bind Emails}"
NoSelectionContent="Select an item to view"
SelectionChanged="MyMasterDetailsView_SelectionChanged">
<controls:MasterDetailsView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="0,8">
<TextBlock
Style="{ThemeResource SubtitleTextBlockStyle}"
Text="{Binding Name}" />
<TextBlock
Opacity=".6"
Style="{ThemeResource BodyTextBlockStyle}"
Text="{Binding Zone}" />
</StackPanel>
<Button
x:Name="MoreBtn"
Grid.Column="1"
Margin="10"
Padding="10"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
Click="MoreBtn_Click"
Command="{Binding ElementName=RootGrid, Path=DataContext.OpenDialog}"
CommandParameter="{Binding}"
Content=""
FontFamily="Segoe MDL2 Assets"
Visibility="{Binding ShowButton, Converter={StaticResource MyConveter}}" />
</Grid>
</DataTemplate>
</controls:MasterDetailsView.ItemTemplate>
<controls:MasterDetailsView.DetailsTemplate>
<DataTemplate>
<StackPanel>
<TextBlock
Margin="12,-6,0,0"
Style="{ThemeResource SubtitleTextBlockStyle}"
Text="{Binding From}"
/>
<TextBlock
x:Name="Body"
Margin="0,12,0,0"
Style="{ThemeResource BodyTextBlockStyle}"
Text="{Binding Body}"
TextWrapping="Wrap"
/>
</StackPanel>
</DataTemplate>
</controls:MasterDetailsView.DetailsTemplate>
<controls:MasterDetailsView.NoSelectionContentTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock
Margin="0,12"
FontSize="24"
Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</controls:MasterDetailsView.NoSelectionContentTemplate>
<controls:MasterDetailsView.MasterCommandBar>
<CommandBar>
<AppBarButton Icon="Back" Label="Back" />
<AppBarButton Icon="Forward" Label="Forward" />
<CommandBar.Content>
<TextBlock Margin="12,14">
<Run Text="{Binding Emails.Count}" />
<Run Text="Items" />
</TextBlock>
</CommandBar.Content>
</CommandBar>
</controls:MasterDetailsView.MasterCommandBar>
<controls:MasterDetailsView.DetailsCommandBar>
<CommandBar>
<AppBarButton Icon="MailReply" Label="Reply" />
<AppBarButton Icon="MailReplyAll" Label="Reply All" />
<AppBarButton Icon="MailForward" Label="Forward" />
</CommandBar>
</controls:MasterDetailsView.DetailsCommandBar>
</controls:MasterDetailsView>
</Grid>
C# (MasterDetailsView page)
public sealed partial class MasterDetailPage : Page
{
public List<Email> Emails { get; set; }
public MasterDetailPage()
{
this.InitializeComponent();
this.DataContext = this;
Emails = MyEmailManager.GetEmails();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
MainPage.Current.BackButton.Visibility = Visibility.Visible;
MainPage.Current.BackButton.IsEnabled = true;
}
private void MyMasterDetailsView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
}
public class Email
{
public string From { get; set; }
public string Body { get; set; }
public bool ShowButton { get; set; }
}
public class MyEmailManager
{
public static List<Email> GetEmails()
{
var MyEmails = new List<Email>
{
new Email
{
From = "Steve Johnson",
Body = "Are you available for lunch tomorrow? A client would like to discuss a project with you.",
ShowButton = true
},
new Email
{
From = "Pete Davidson",
Body = "Don't forget the kids have their soccer game this Friday. We have to supply end of game snacks.",
ShowButton = false
},
new Email
{
From = "OneDrive",
Body = "Your new album.\r\nYou uploaded some photos to your OneDrive and automatically created an album for you.",
ShowButton = false
},
new Email
{
From = "Twitter",
Body = "Here are some people we think you might like to follow:\r\n.#randomPerson\r\nAPersonYouMightKnow",
ShowButton = true
}
};
return MyEmails;
}
}
public class CommadEventHandler<T> : ICommand
{
public event EventHandler CanExecuteChanged;
public Action<T> action;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
this.action((T)parameter);
}
public CommadEventHandler(Action<T> action)
{
this.action = action;
}
}
}
XAML (Main Page)
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<CommandBar Grid.Row="0" DefaultLabelPosition="Right">
<CommandBar.Content>
<Button
x:FieldModifier="public"
Style="{StaticResource NavigationBackButtonNormalStyle}"
Name="BackButton"
VerticalAlignment="Top"
Click="Back_Click"/>
</CommandBar.Content>
</CommandBar>
<Frame Name="MainFrame" Grid.Row="1" Padding="0"/>
</Grid>
C# (MainPage)
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Current = this;
Frame_Main.Navigate(typeof(MsterDetailPage));
}
private void Back_Click(object sender, RoutedEventArgs e)
{
On_BackRequested();
}
private bool On_BackRequested()
{
if (Frame_Main.CanGoBack)
{
Frame_Main.GoBack();
return true;
}
return false;
}
private void BackInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
On_BackRequested();
args.Handled = true;
}
}
MasterDetailView provides ViewStateChanged event, which will be triggered when the display state of MasterDetailView changes. We can adjust the CommandBar in MainPage based on this event.
private void MyMasterDetailsView_ViewStateChanged(object sender, MasterDetailsViewState e)
{
if (e == MasterDetailsViewState.Details)
{
MainPage.Current.BackButton.Visibility = Visibility.Collapsed;
MainPage.Current.BackButton.IsEnabled = false;
}
else
{
MainPage.Current.BackButton.Visibility = Visibility.Visible;
MainPage.Current.BackButton.IsEnabled = true;
}
}
Below is my item template in a grid view.
</Grid.ColumnDefinitions>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SerialNumber}" VerticalAlignment="Center" HorizontalAlignment="Left" FontWeight="Bold" Margin="10" FontSize="25"/>
<TextBlock Text="." VerticalAlignment="Center" HorizontalAlignment="Left" FontWeight="Bold" FontSize="25" />
</StackPanel>
<Image Grid.Column="0" Margin="20" Height="100" Width="150" HorizontalAlignment="Center" Source="{Binding ImageUri,Mode=TwoWay}" VerticalAlignment="Center"/>
</StackPanel>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
what i am trying to achieve is to display the item position in the collection in the TextBlock Text="{Binding SerialNumber} (if this were to be a list view, it would be row number), please how do i achieve this.
You just need to define a class with the specific properties and bind it on xaml.
I made a simple code sample for your reference:
<GridView ItemsSource="{Binding oc}">
<GridView.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding SerialNumber}" VerticalAlignment="Center" HorizontalAlignment="Left" FontWeight="Bold" Margin="10" FontSize="25"/>
<TextBlock Text="." VerticalAlignment="Center" HorizontalAlignment="Left" FontWeight="Bold" FontSize="25" />
</StackPanel>
<Image Grid.Column="0" Margin="20" Height="100" Width="150" HorizontalAlignment="Center" Source="{Binding source,Mode=TwoWay}" VerticalAlignment="Center"/>
</StackPanel>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
public sealed partial class MainPage : Page
{
public ObservableCollection<Test> oc { get; set;}
public MainPage()
{
this.InitializeComponent();
oc = new ObservableCollection<Test>();
oc.CollectionChanged += Oc_CollectionChanged;
for (int i=0;i<10;i++)
{
oc.Add(new Test() {SerialNumber=i,source=new BitmapImage(new Uri("ms-appx:///Assets/test.png")) });
}
this.DataContext = this;
}
private void Oc_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
for (int i =e.OldStartingIndex; i<oc.Count;i++)
{
oc[i].SerialNumber = i;
}
}
}
}
public class Test:INotifyPropertyChanged
{
private int _SerialNumber;
public int SerialNumber
{
get { return _SerialNumber; }
set
{
_SerialNumber = value;
RaisePropertyChanged("SerialNumber");
}
}
private BitmapImage _source;
public BitmapImage source
{
get { return _source; }
set
{
_source = value;
RaisePropertyChanged("source");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(PropertyName));
}
}
}
I have a ListView with textBox in one of the columns. User input on the textbox supposed to update the underlying data, that's what my requirement is, but it's not happening. I tried a work around as shown all the way below, it seems to work but I am guessing that the binding itself should take care of it without the work around.
XAML:
<ListView x:Name="listView" Grid.Row="1" ItemsSource="{Binding}" SelectionMode="Multiple">
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="{Binding BackGround}">
<Grid x:Name="row">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tblDescription"
Grid.Row="0"
Grid.Column="0"
Margin="1"
TextWrapping="Wrap"
Text="{Binding Description}"
FontSize="{StaticResource TextStyleMediumFontSize}"
Foreground="Black"/>
<TextBlock x:Name="tblItemNumber"
Grid.Row="0"
Grid.Column="1"
Margin="1"
Text="{Binding ItemNumber}"
FontSize="{StaticResource TextStyleMediumFontSize}"
FontStyle="Italic"
Foreground="Gray"/>
<TextBox x:Name="tbQuantity"
Grid.Row="1"
Grid.Column="1"
Margin="1"
Text="{Binding Quantity}"
IsEnabled="{Binding IsEnabled}"
FontSize="{StaticResource TextStyleLargeFontSize}"
BorderBrush="DarkGray"
Foreground="Black"
InputScope="Number"
Tag="{Binding RowNumber}"
TextChanged="tbQuantity_TextChanged"
>
<TextBox.Header>Quantity</TextBox.Header>
</TextBox>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
DataRow class:
public class DataRowBase : INotifyPropertyChanged
{
#region Events
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Properties
public int RowNumber { get; set; }
public string ItemNumber { get; set; }
public string Description { get; set; }
private string _Quantity;
public string Quantity
{
get { return _Quantity; }
set {
_Quantity = value;
RaisePropertyChanged("Quantity");
}
}
#endregion
}
Work Around:
private void tbQuantity_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox tb = (TextBox)sender;
int rownumber = tb.Tag.ToString().ToInt();
UpdateQuantity(rownumber, value: tb.Text);
}
private void UpdateQuantity(int rownumber, string value)
{
try
{
DataRow datarow = OriginalSource.Where(o => o.RowNumber == rownumber).FirstOrDefault();
if (datarow != null)
{
datarow.Quantity = value;
}
}
catch (Exception ex)
{
}
}
The default Binding is OneWay, for a TwoWay you will have to declare it, for example:
Text="{Binding ItemNumber, Mode=TwoWay}"
I want to Display a list of pictures in a LongListSelector on Windows Phone 8.
That´s my Model:
public class LocationMediaModel : INotifyPropertyChanged
{
private string _id;
public string ID
{
get
{
return _id;
}
set
{
if (value != _id)
{
_id = value;
NotifyPropertyChanged("ID");
}
}
}
private string _mediatype;
public string MediaType
{
get
{
return _mediatype;
}
set
{
if (value != _mediatype)
{
_mediatype = value;
NotifyPropertyChanged("MediaType");
}
}
}
private string _url;
public string URL
{
get
{
return _url;
}
set
{
if (value != _url)
{
_url = value;
NotifyPropertyChanged("URL");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Here´s my ViewModel:
public class LocationMediaViewModel : INotifyPropertyChanged
{
public LocationMediaViewModel()
{
this.MediaItems = new ObservableCollection<LocationMediaModel>();
}
public ObservableCollection<LocationMediaModel> MediaItems { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
// Properties vom Model <-> ViewModel:
private string _id;
public string ID
{
get
{
return _id;
}
set
{
if (value != _id)
{
_id = value;
NotifyPropertyChanged("ID");
}
}
}
private string _mediatype;
public string MediaType
{
get
{
return _mediatype;
}
set
{
if (value != _mediatype)
{
_mediatype = value;
NotifyPropertyChanged("MediaType");
}
}
}
private string _url;
public string URL
{
get
{
return _url;
}
set
{
if (value != _url)
{
_url = value;
NotifyPropertyChanged("URL");
}
}
}
public bool IsDataLoaded
{
get;
private set;
}
public void LoadData()
{
// Sample data; replace with real data
this.MediaItems.Add(new LocationMediaModel() { ID = "3e3b1e48-8463-424b-8256-15c569358dfb", MediaType = "jpg", URL = "http://media.contoso.com/thumbs/f3be161f-cffc-485e-8f1d-52cfcebc1c79.jpg" });
this.MediaItems.Add(new LocationMediaModel() { ID = "e5e7cb87-04bb-498a-ab57-83bd5c3425c4", MediaType = "jpg", URL = "http://media.contoso.com/thumbs/99FBBBB0-9C16-4E0A-B6E7-A1A709638D06.jpg" });
this.MediaItems.Add(new LocationMediaModel() { ID = "b45931bf-0778-45cc-9efa-fc1aa397ccd9", MediaType = "jpg", URL = "http://media.contoso.com/thumbs/dff96a4f-f22f-4c6d-af24-504a1c80b7c4.jpg" });
this.MediaItems.Add(new LocationMediaModel() { ID = "a23e31b1-9232-086c23fe2279ab1bb22dd0", MediaType = "jpg", URL = "http://media.contoso.com/thumbs/1d1315c7-3292-4e67-8189-5db5393ec801.jpg" });
this.MediaItems.Add(new LocationMediaModel() { ID = "22991670-32b2-45f6-be69-3892b9587865", MediaType = "jpg", URL = "http://media.contoso.com/thumbs/433EA3D7-B9BF-4F3E-96C8-EEC1B9B04896.jpg" });
this.IsDataLoaded = true;
}
}
And finaly my XAML view:
<phone:PhoneApplicationPage
x:Class="WhaGoO.LocationPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DataContext="{d:DesignData DesignData/LocationDetailsSampleData.xaml}"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<Grid x:Name="LayoutRoot" Background="Transparent">
<phone:Pivot x:Name="pvtMainPivot" SelectionChanged="evt_PivotControl_SelectionChanged">
<!-- ++++++++++++++++++ Header -->
<phone:Pivot.Title>
<StackPanel HorizontalAlignment="Center">
<Image Stretch="None" HorizontalAlignment="Left" Margin="-5,0,0,0" MinWidth="50" MaxHeight="50" Source="/mAppData/logo.png"/>
</StackPanel>
</phone:Pivot.Title>
<!-- ++++++++++++++++++ EREIGNISSE -->
<phone:PivotItem x:Name="pivotitemFavoriten" Header="Ereignisse">
<StackPanel Margin="0,0,0,15" >
<Grid VerticalAlignment="Top" Margin="0,0,5,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="120" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" TextTrimming="WordEllipsis" Text="LocationName" TextWrapping="NoWrap" Style="{StaticResource PhoneTextLargeStyle}" VerticalAlignment="Top" Margin="0,0,0,22" />
<Image Grid.Column="0" Width="138" Height="25" Source="/mAppData/stars-3.png" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0"/>
<TextBlock Grid.Column="1" Text="distance" TextWrapping="NoWrap" Style="{StaticResource PhoneTextSubtleStyle}" HorizontalAlignment="Right" Margin="0,0,-3,40" VerticalAlignment="Bottom"/>
<TextBlock Grid.Column="1" Text="lastupload" TextWrapping="NoWrap" Style="{StaticResource PhoneTextSubtleStyle}" HorizontalAlignment="Right" Margin="0,0,-3,20" VerticalAlignment="Bottom"/>
<TextBlock Grid.Column="1" Text="ratingscnt" TextWrapping="NoWrap" Style="{StaticResource PhoneTextSubtleStyle}" HorizontalAlignment="Right" Margin="0" VerticalAlignment="Bottom"/>
</Grid>
<TextBlock Grid.Column="1" Text="Marlene-Dietrich-Platz 1" TextWrapping="NoWrap" Style="{StaticResource PhoneTextSubtleStyle}" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Bottom"/>
<TextBlock Grid.Column="1" Text="Berlin" TextWrapping="NoWrap" Style="{StaticResource PhoneTextSubtleStyle}" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Bottom"/>
<phone:LongListSelector Name="lls_PhotoHub" Margin="0" IsGroupingEnabled="False" LayoutMode="Grid" DataContext="LocationMediaViewModel" ItemsSource="{Binding MediaItems}" GridCellSize="108,108" >
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Image Width="100" Height="100" Source="{Binding URL}" />
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</StackPanel>
</phone:PivotItem>
<!-- ++++++++++++++++++ 2.PivotItem-->
<phone:PivotItem x:Name="pivotitemUmgebung" Header="Karte">
</phone:PivotItem>
</phone:Pivot>
</Grid>
</phone:PhoneApplicationPage>
But the binding seems not working -> no Images are displayed.
Can anyone help?
As Florent Gz pointed out, I don't see any DataContext initialization either.
In your PhoneApplicationPage code behind, in the constructor, add this:
this.DataContext = new LocationMediaViewModel();