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));
}
}
}
Related
There is a WPF form containing 8 textboxes.
<StackPanel Grid.Column="2">
<TextBox Margin="5" Width="100" Text="{Binding SelectedOrder.OrderCode}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.ClientID}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.RouteCode}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.DriverID}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.TCCode}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.Date}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.StartDate}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<TextBox Margin="10" Width="100" Text="{Binding SelectedOrder.EndDate}" FontSize="16" FontWeight="Normal" FontStyle="Normal"/>
<Button Margin="50" Width="100" Content="Create"
Command="{Binding AddCommand}"
/>
</StackPanel>
There is a ViewModel class that implements the transfer of data from the view to the model
public class OrderViewModel : INotifyPropertyChanged
{
private ObservableCollection<Order> orderList; //list of records in the Order table
private Order selectedOrder; // specific entry in Order
private TransportCompanyEntities transportCompanyEntities; // context?
public Order SelectedOrder
{
get { return selectedOrder; }
set
{
selectedOrder = value;
OnPropertyChanged(nameof(SelectedOrder));
}
}
public ObservableCollection<Order> OrderList
{
get { return orderList; }
set
{
orderList = value;
OnPropertyChanged(nameof(OrderList));
}
}
public OrderViewModel()
{
transportCompanyEntities = new TransportCompanyEntities();
Load Orders();
}
private void LoadOrders()
{
OrderList = new ObservableCollection<Order>(transportCompanyEntities.Order);
}
private RelayCommand addCommand;
public RelayCommand AddCommand
{
get
{
return addCommand ??
(addCommand = new RelayCommand(obj =>
{
transportCompanyEntities.Order.Add(SelectedOrder);
transportCompanyEntities.SaveChanges();
}));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class RelayCommand{}
When the button is clicked, an entry should be created, but an error occurs
How can i fix it?
System.ArgumentNullException: "Value cannot be null. Parameter name: entity"
I understand that I am trying to add an empty entry, but it is not clear to me why it is not created when the button is clicked.
I'm actually developping an UWP app who's reading Excel data, and display it on a form. Every Excel sheet are represented with RadioButton, and when the user click on a RadioButton, I update a ListView with the corresponding data.
Every item of the ListView have different data, and 2 checkboxes. This checkboxes can have the state "true" or "false", and if the user need to change the state, I want to modify his value
But the problem is, there is no event triggered with all the checkboxes when I check them. I tried to search and try to make my own template, but without success.
All the data are stored in a class :
public class REFERENCES
{
public int AI_ID { get; set; }
public int ID_poste { get; set; }
public string reference { get; set; }
public string designation { get; set; }
public bool avance { get; set; }
public bool jour { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public REFERENCES(int ai_id, int id_poste, string ref_, string des_, string avance_, string jour_)
{
AI_ID = ai_id;
ID_poste = id_poste;
reference = ref_;
designation = des_;
if(jour_ != null)
{
jour = true;
}
else
{
jour = false;
}
if (avance_ != null)
{
avance = true;
}
else
{
avance = false;
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And this is my ListView :
<ListView x:Name="ListViewData" SelectionMode="None" HorizontalAlignment="Center" Height="412" VerticalAlignment="Top" Width="650" Margin="0,218,0,0" >
<ListView.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Height="35" Margin="0,0,0,0" VerticalAlignment="Center" >
<TextBlock Text="AI_ID" Width="0" Visibility="Collapsed" />
<TextBlock Text="Désignations" FontSize="20" Width="300" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="Références" FontSize="20" Width="150" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="Avance" FontSize="20" Width="100" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="Jour" FontSize="20" Width="100" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate x:DataType="ExcelLinkData:REFERENCES">
<StackPanel Orientation="Horizontal" >
<TextBlock Name="ItemAI_ID" Text="{x:Bind AI_ID}" Width="0" />
<TextBlock Name="ItemDesignation" Text="{x:Bind designation}" Width="300" FontSize="16" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center"/>
<TextBlock Name="ItemReference" Text="{x:Bind reference}" Width="150" FontSize="16" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" />
<Grid Width="100" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center">
<CheckBox Name="ItemAvance" IsChecked="{x:Bind avance}" Tag="{x:Bind AI_ID}" Checked="CHANGE_STATUS_REFERENCE"/>
</Grid>
<Grid Width="100" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center">
<CheckBox Name="ItemJour" IsChecked="{x:Bind jour}" Tag="{x:Bind AI_ID}" Checked="CHANGE_STATUS_REFERENCE"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The method "CHANGE_STATUS_REFERENCE" is the method where I want to change the state in my class.
I tried different solutions, but I'm not an expert in UWP, so if anyone got an advice, I'll take it !
Thanks in advance for your time !
Guillaume
In UWP, default mode for Binding is OneTime. And when you change property from viewmodel then no event is triggered. By changing Binding to OneWay / TwoWay (depending on your usage), viewmodel will trigger the event.
Change
IsChecked="{x:Bind jour}"
To
IsChecked="{x:Bind jour Mode=TwoWay}"
Change
<CheckBox Name="ItemAvance" IsChecked="{x:Bind avance}" Tag="{x:Bind AI_ID}" Checked="CHANGE_STATUS_REFERENCE"/>
to
<CheckBox Name="ItemAvance" IsChecked="{x:Bind avance}" Tag="{x:Bind AI_ID}" Command="{Binding CHANGE_STATUS_REFERENCE}"/>
Add a "Flip Function" to your class:
private void Flip()
{
this.avance = !this.avance;
}
Set up a RelayCommand:
RelayCommand _flipCommand = new RelayCommand(this.Flip);
and Implement CHANGE_STATUS_REFERENCE as an ICommand like so:
public ICommand CHANGE_STATUS_REFERENCE
{
get
{
return _flipCommand;
}
}
Hi I have my list view as follows:
![][1]
<RelativePanel >
<ListView x:Name="StudentListView"
IsItemClickEnabled="True"
Width="1000"
ItemClick="Student_ItemClick" >
<ListView.ItemTemplate>
<DataTemplate x:Name="ABC">
<StackPanel
x:Name="ListItemPanel"
Orientation="Horizontal"
MaxWidth="500">
<TextBlock x:Name ="uName" Text="{Binding Username}"
Margin="20,0,20,8"
FontSize="24"
FontStyle="Italic"
FontWeight="SemiBold"
Foreground="DarkBlue"
/>
<CheckBox Name="AttendCheckBox"
HorizontalAlignment="Left"
Checked="AttendCheckBox_Checked"
IsChecked="False"></CheckBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock Name="queryName" FontSize="20"></TextBlock>
<Button Name="finishBtn" Content="Finish" RelativePanel.Below="StudentListView" ></Button>
</RelativePanel>
I am trying to access each data item and check if checkbox is checked or not when user clicks on finish button that is on same page as listview. And I am having tough time trying to figure it out. Any hint on it would be great. Thank you
I checked your code. You did not need to use Checked event of CheckBox. Instead, you could declare a bool type property in your custom class and bind IsChecked to it and set Mode=TwoWay, then, once your checkbox's IsChecked value is changed, the source also will be updated. After that, you could filter the source to get the 'IsChecked=True' items.
According to your code snippet, I made a code sample for you reference:
<RelativePanel>
<ListView x:Name="StudentListView"
IsItemClickEnabled="True"
Width="1000" Height="500">
<ListView.ItemTemplate>
<DataTemplate x:Name="ABC">
<StackPanel
x:Name="ListItemPanel"
Orientation="Horizontal"
MaxWidth="500">
<TextBlock x:Name ="uName" Text="{Binding Username}"
Margin="20,0,20,8"
FontSize="24"
FontStyle="Italic"
FontWeight="SemiBold"
Foreground="DarkBlue"/>
<CheckBox Name="AttendCheckBox" HorizontalAlignment="Left" IsChecked="{Binding IsSelected,Mode=TwoWay}"></CheckBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock Name="queryName" FontSize="20"></TextBlock>
<Button Name="finishBtn" Content="Finish" RelativePanel.Below="StudentListView" Click="{x:Bind finishBtn_Click}"></Button>
</RelativePanel>
public sealed partial class MainPage : Page
{
public ObservableCollection<Test> tests { get; set; }
public MainPage()
{
this.InitializeComponent();
tests = new ObservableCollection<Test>();
for (int i=0;i<100;i++)
{
tests.Add(new Test() {Username="name "+i });
}
StudentListView.ItemsSource = tests;
}
private void finishBtn_Click(object sender, RoutedEventArgs e)
{
var selectedStudents = tests.Where(x => x.IsSelected == true).ToList();
}
}
public class Test : INotifyPropertyChanged
{
private string _Username;
public string Username
{
get { return _Username; }
set
{
if (_Username != value)
{
_Username = value;
RaisePropertyChanged("Username");
}
}
}
private bool _IsSelected;
public bool IsSelected
{
get { return _IsSelected; }
set
{
if (_IsSelected != value)
{
_IsSelected = value;
RaisePropertyChanged("IsSelected");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(PropertyName));
}
}
}
I have a gridview in UWP app and I have put a button in each gridview item in datatemplate so that it can be used to delete/remove that specific item from the gridview ( removing it from observableCollection behind). I am not using MVVM approach, because I am not much familiar with it, I am using a normal Observable Collection for binding of data and data template.
if you can suggest me a better way to do it, myabe using MVVM please suggest me how to do it. Thanks in advance
Code :
XAML GRID VIEW (button with the red back ground is the button I wanna use to delete item)
<controls:AdaptiveGridView Name="HistoryGridView" StretchContentForSingleRow="False"
Style="{StaticResource MainGridView}"
ItemClick ="HistoryGridView_SelectionChanged"
ItemsSource="{x:Bind HistoryVideos, Mode=OneWay}">
<controls:AdaptiveGridView.ItemTemplate>
<DataTemplate x:DataType="data:Video">
<StackPanel Margin="4" >
<Grid>
<Button Background="Red"
HorizontalAlignment="Right" VerticalAlignment="Top"
Height="36" Canvas.ZIndex="1"
Style="{StaticResource TransparentButton}" Width="36">
<fa:FontAwesome Icon="Close" FontSize="20" HorizontalAlignment="Center" Foreground="White"
/>
</Button>
<Image Canvas.ZIndex="0" Source="{x:Bind Thumbnail}" Style="{StaticResource GridViewImage}"/>
<Border Style="{StaticResource TimeBorder}" Height="Auto" VerticalAlignment="Bottom"
Canvas.ZIndex="1"
HorizontalAlignment="Left">
<TextBlock Text="{x:Bind Duration}" Foreground="White" Height="Auto"/>
</Border>
</Grid>
<TextBlock Text="{x:Bind Name}" Style="{StaticResource GridViewVideoName}"/>
<TextBlock Text="{x:Bind ParentName}" Style="{StaticResource GridViewParentName}"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{x:Bind Views}" Style="{StaticResource GridViewViews}"/>
<TextBlock Text="Views" HorizontalAlignment="Right"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>
</controls:AdaptiveGridView>
Code Behind
public History()
{
this.InitializeComponent();
HistoryVideos = new ObservableCollection<Video>();
}
public ObservableCollection<Video> HistoryVideos { get; private set; }
I am using onnavigated to method for filling the collection and it works fine and also I guess that is not relevent here.
We can add the Command to the Button to invoke when this button is pressed and we can use parameter to pass to the Command property.
To use the Command, we should be able to define a DelegateCommand class that inherits from the ICommand.
For example:
internal class DelegateCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public DelegateCommand(Action<object> execute)
{
this.execute = execute;
this.canExecute = (x) => { return true; };
}
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute(parameter);
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
public void Execute(object parameter)
{
execute(parameter);
}
}
We can add the Id property in the Video, then we can pass the Id property to the CommandParameter. When we click the Button, the ExecuteDeleteCommand method will be fired. We can use the Id to find the Video in the HistoryVideos and use the Remove method to remove it.
The ViewModel code:
internal class ViewModel
{
private ObservableCollection<Viedo> _videos;
public ObservableCollection<Viedo> Videos
{
get
{
return _videos;
}
set
{
if (_videos != value)
{
_videos = value;
}
}
}
public ICommand DeleteCommand { set; get; }
private void ExecuteDeleteCommand(object param)
{
int id = (Int32)param;
Viedo cus = GetCustomerById(id);
if (cus != null)
{
Videos.Remove(cus);
}
}
private Viedo GetCustomerById(int id)
{
try
{
return Videos.First(x => x.Id == id);
}
catch
{
return null;
}
}
public ViewModel()
{
Videos = new ObservableCollection<Viedo>();
for (int i = 0; i < 5; i++)
{
Videos.Add(new Viedo());
Videos[i].Name = "Name";
Videos[i].Id = i;
}
this.DeleteCommand = new DelegateCommand(ExecuteDeleteCommand);
}
}
The XAML code:
<GridView Name="MyGridView" ItemsSource="{Binding Videos}">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"></TextBlock>
<Button Background="Red"
HorizontalAlignment="Right" VerticalAlignment="Top"
Height="36" Canvas.ZIndex="1"
Width="36" Command="{Binding DataContext.DeleteCommand, ElementName=MyGridView}" CommandParameter="{Binding Id}">
</Button>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The code behind:
private ViewModel myViewModel;
public MainPage()
{
this.InitializeComponent();
myViewModel = new ViewModel();
MyGridView.DataContext = myViewModel;
}
Update:
<GridView Name="MyGridView" ItemsSource="{x:Bind myViewModel.Videos}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:Viedo">
<StackPanel>
<TextBlock Text="{x:Bind Name}"></TextBlock>
<Button Background="Red"
HorizontalAlignment="Right" VerticalAlignment="Top"
Height="36" Canvas.ZIndex="1"
Width="36" Command="{Binding DataContext.DeleteCommand, ElementName=MyGridView}" CommandParameter="{Binding Id}">
</Button>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
i am trying to bind the background color with the item template containing a grid in it. I want that depending upon the status the background color of each item in a list should be highlighted automatically. So i am doing it but no color is shown on the respective item.so how to bind the grid background such that color is changed. Xaml code :
<phone:LongListSelector x:Name="ResultListBox"
Margin="35,10,35,-25"
ItemsSource="{Binding Country}"
ItemTemplate="{StaticResource CustomList}"
Height="436" SelectionChanged="ResultListBox_SelectionChanged" Loaded="Listbox_loaded">
<UserControl.Resources>
<DataTemplate x:Key="CustomList">
<Grid Margin="5,0,10,5" Tag="{Binding Name}" x:Name="CountryGrid" Tap="BorderColor" >
<Grid.Background>
<SolidColorBrush Color="{Binding HighlightBackgroundColor}" />
</Grid.Background>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="450"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="45"></RowDefinition>
</Grid.RowDefinitions>
<Border VerticalAlignment="Center" x:Name="HighlightBG" HorizontalAlignment="Left" Grid.Column="0" Margin="0,5,0,0" Height="70" CornerRadius="0,10,10,0" Grid.Row="0" >
<StackPanel Orientation="Vertical" Margin="0,5,0,0" HorizontalAlignment="Center" >
<TextBlock Text="{Binding Name}" x:Name="nametextblock" VerticalAlignment="Top" TextWrapping="Wrap" Foreground="White" FontSize="30" HorizontalAlignment="Center" ></TextBlock>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
</UserControl.Resources>
c# code snippet:
public partial class ListPopup : UserControl,INotifyPropertyChanged
{
public ListPopup()
{
InitializeComponent();
this.Loaded += ListPopup_Loaded;
this.IsSelected = false;
//, INotifyPropertyChanged
this.NonHighlightColor = new SolidColorBrush(Colors.Transparent);
this.HighLightColor = new SolidColorBrush(Colors.Red);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
////////////
private bool _is_selected;
public bool IsSelected
{
get { return _is_selected; }
set
{
_is_selected = value;
OnPropertyChanged("HighlightBackgroundColor");
}
}
public SolidColorBrush HighlightBackgroundColor
{
get { if (IsSelected) return HighLightColor; else return NonHighlightColor; }
}
private SolidColorBrush HighLightColor { get; set; }
private SolidColorBrush NonHighlightColor { get; set; }
}
You're exposing a Brush but binding it as a Color. Just change your XAML:
<Grid Margin="5,0,10,5" Background="{Binding HighlightBackgroundColor}" Tag="{Binding Name}" x:Name="CountryGrid" Tap="BorderColor" >