LongListMultiSelector: How to use it with MVVM - xaml

I am displaying a list of cities using LongListMultiSelector with Grouping. My ViewModel has DataList propery which is bind to LongListMultiSelector.
On a button click event, i want to remove an item from LongListMultiSelector and also want to update the UI at same time. I don't understand from where should i remove an item so that because of MVVM, UI gets updated automatically.
Below is my CS code.
public class City
{
public string Name { get; set; }
public string Country { get; set; }
public string Language { get; set; }
}
public class Group<T> : List<T>
{
public Group(string name, IEnumerable<T> items)
: base(items)
{
this.Title = name;
}
public string Title
{
get;
set;
}
}
public class myVM : INotifyPropertyChanged
{
static List<City> cityList;
public List<Group<City>> _datalist;
public List<Group<City>> DataList
{
get
{
_datalist = GetCityGroups();
return _datalist;
}
set
{
_datalist = value;
OnPropertyChanged("DataList");
}
}
private static IEnumerable<City> GetCityList()
{
cityList = new List<City>();
cityList.Add(new City() { Name = "Milan", Country = "IT", Language = "Italian" });
cityList.Add(new City() { Name = "Roma", Country = "IT", Language = "Italian" });
cityList.Add(new City() { Name = "Madrid", Country = "ES", Language = "Spanish" });
return cityList;
}
private List<Group<City>> GetCityGroups()
{
IEnumerable<City> cityList = GetCityList();
return GetItemGroups(cityList, c => c.Country);
}
private static List<Group<T>> GetItemGroups<T>(IEnumerable<T> itemList, Func<T, string> getKeyFunc)
{
IEnumerable<Group<T>> groupList = from item in itemList
group item by getKeyFunc(item) into g
orderby g.Key
select new Group<T>(g.Key, g);
return groupList.ToList();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Below is my XAML code
<Button Content="bind" Width="150" Height="150" VerticalAlignment="Bottom" Click="Button_Click"></Button>
<toolkit:LongListMultiSelector x:Name="AddrBook"
ItemsSource="{Binding DataList}"
EnforceIsSelectionEnabled="True"
JumpListStyle="{StaticResource AddrBookJumpListStyle}"
IsSelectionEnabled="True"
Background="Transparent"
GroupHeaderTemplate="{StaticResource AddrBookGroupHeaderTemplate}"
ItemTemplate="{StaticResource AddrBookItemTemplate}"
LayoutMode="List"
IsGroupingEnabled="true"
HideEmptyGroups ="true"/>
In phone:PhoneApplicationPage.Resources i have below xaml
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="AddrBookItemTemplate">
<StackPanel VerticalAlignment="Top">
<TextBlock Text="{Binding Name, Mode=TwoWay}" />
<TextBlock Text="{Binding Language, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="AddrBookGroupHeaderTemplate">
<Border Background="Transparent" Margin="12,8,0,8">
<Border Background="{StaticResource PhoneAccentBrush}"
Padding="8,0,0,0" Width="62" Height="62"
HorizontalAlignment="Left">
<TextBlock Text="{Binding Title, Mode=TwoWay}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6"
FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Border>
</Border>
</DataTemplate>
<phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
<phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
<Style x:Key="AddrBookJumpListStyle" TargetType="phone:LongListSelector">
<Setter Property="GridCellSize" Value="113,113"/>
<Setter Property="LayoutMode" Value="Grid" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Width="Auto" Height="Auto" Margin="6" >
<TextBlock Text="{Binding Title, Mode=TwoWay}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="48" Padding="6"
Margin="8,0,0,0" Foreground="{Binding Converter={StaticResource ForegroundConverter}}" VerticalAlignment="Bottom"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</phone:PhoneApplicationPage.Resources>

You simply remove the item from your DataList inside your VM.
The tricky part is to handle the SelectedItems of the MultiSelector since it isnt bindable.
The simplest solution for me was to hook up a command to the SelectionChanged event and pass the SelectedItems as a parameter with it (I used the Command class from the MvvmLight Toolkit for that). Inside the Command I check for any changes between the updated List and the old List in the VM.
Also you shouldn't use the Click Event on the button, in MVVM the Command Property is used along with the CommandParameter if needed.
For other Controls that dont have a build-in Command Property you can use something like the aforementioned class from the toolkit (or other MVVM frameworks).
Other things to notice:
You need to use something like an ObservableCollection instead of a List if you want the UI to automatically update after changes to the collection.
Also you cant actually remove anything from your DataList since your always re-reading your hardcoded items.

Related

Expander Control - UWP

I have an expander control in my UWP app with the following code:
<Expander
Header="A"
IsExpanded =" True">
<TextBlock
Text="Content in A"/>
</Expander>
<Expander
Header="B">
<TextBlock
Text="Content in B"/>
</Expander>
Currently expander A is expanded by default and B is closed. However, when I expand B, A is also open. I would like the behavior that if I expand one , the other closes and vice versa. Any suggestions as to how I can achieve this in an MVVM way ? Would i need to use converters here? I looked into Collapse all the expanders and expand one of them by default but most of the solutions happen to be in modifying the code behind. How do i achieve the same if i have a XAML code in Main.xaml and i have a corresponding MainPageViewModel.cs?
I would like the behavior that if I expand one , the other closes and vice versa.
For this scenario, you could use OppositConverter to make the other expender close when previous is open.
public class OppositConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return !(bool)value;
}
}
public class MainPageViewModel : INotifyPropertyChanged
{
public MainPageViewModel()
{
}
private bool _isExpend;
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public bool IsExpend
{
get
{
return _isExpend;
}
set
{
_isExpend = value;
OnPropertyChanged();
}
}
}
Usage
<Page.DataContext>
<local:MainPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<Page.Resources>
<local:OppositConverter x:Key="OppositConverter" />
</Page.Resources>
<StackPanel>
<controls:Expander
x:Name="Expander1"
Margin="0,0,0,10"
VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
ExpandDirection="Down"
Header="This is the header - expander 1"
IsExpanded="{Binding IsExpend, Mode=TwoWay}">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="This is the expanded content"
TextWrapping="Wrap" />
</Grid>
</controls:Expander>
<controls:Expander
x:Name="Expander2"
Margin="0,0,0,10"
VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
ExpandDirection="Down"
Header="This is the header - expander 2"
IsExpanded="{Binding IsExpend, Converter={StaticResource OppositConverter}, Mode=TwoWay}">
<Grid>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="This is the expanded content"
TextWrapping="Wrap" />
</Grid>
</controls:Expander>
</StackPanel>

Passing additional arguments to user control inside the data template

This is the xaml code what i am using
<GridView
Grid.Row="0"
x:Name="RootGrid"
SelectionMode="None"
IsItemClickEnabled="True"
ItemsSource="{Binding RootListSource}">
<GridView.ItemTemplate>
<DataTemplate>
<UserControl:TreeInfoControl/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
In this my user control, it contain another GridView that holds a different IEnumerable collection. What i am trying to achieve is i need to pass this collection through code. I tried this by adding a dependency property to the treecontrol but it is not working. So i am looking for a solution that enable passing the collection through xaml (somehow through the user control). I know it is possible to add that collection to my existing collection and bind that one. But for now i can't use that method.
Here's how you do it.
Start with your App.xaml so we can reuse the demo template
<Application.Resources>
<DataTemplate x:Key="MyContentControl">
<Grid Height="100" Width="100" Background="Maroon">
<TextBlock Text="{Binding FallbackValue=0}" Foreground="White" FontSize="40" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</Application.Resources>
Then we can define your user control
<d:UserControl.DataContext>
<local:MyControlViewModel Number="-1" Letter="~K" />
</d:UserControl.DataContext>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
<ContentControl Content="{Binding Number}"
ContentTemplate="{StaticResource MyContentControl}" />
<ListView ItemsSource="{Binding Letters}" IsHitTestVisible="False"
ItemTemplate="{StaticResource MyContentControl}"
SelectedItem="{Binding Letter, Mode=TwoWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListView>
</StackPanel>
And then we can define your MainPage.xaml
<Page.DataContext>
<local:MainPageViewModel Letter="C" />
</Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView x:Name="MyList" ItemsSource="{Binding Letters}"
ItemTemplate="{StaticResource MyContentControl}"
SelectedItem="{Binding Letter, Mode=TwoWay}" />
<ListView Grid.Column="1" ItemsSource="{Binding Numbers}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<local:MyControlViewModel
x:Key="MyDataContext" Number="{Binding}"
Letters="{Binding ItemsSource, ElementName=MyList}"
Letter="{Binding SelectedItem, ElementName=MyList}" />
</StackPanel.Resources>
<local:MyControl DataContext="{StaticResource MyDataContext}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Nothing special yet, right? Well, not so fast. We're creating the viewmodel for the user control , setting the properties of the view model from the surrounding scope, then passing it in to the DataContext of the user control explicitly. Cool, huh? Simple enough, if you think about it. Want to set those properties inside the tag? Sure you do. But you can't. The order of operation would be all wrong. You'll just have to trust me.
Now, there's ZERO code behind for your user control. But the view model looks like this:
public class MyControlViewModel : BindableBase
{
public int Number
{
get { return (int)GetValue(NumberProperty); }
set
{
SetValue(NumberProperty, value);
base.RaisePropertyChanged();
}
}
public static readonly DependencyProperty NumberProperty =
DependencyProperty.Register("Number", typeof(int), typeof(MyControlViewModel),
new PropertyMetadata(0, (s, e) => { }));
public string Letter
{
get { return (string)GetValue(LetterProperty); }
set
{
SetValue(LetterProperty, value);
base.RaisePropertyChanged();
}
}
public static readonly DependencyProperty LetterProperty =
DependencyProperty.Register("Letter", typeof(string), typeof(MyControlViewModel),
new PropertyMetadata("Z", (s, e) => { }));
public ObservableCollection<string> Letters
{
get { return (ObservableCollection<string>)GetValue(LettersProperty); }
set
{
SetValue(LettersProperty, value);
base.RaisePropertyChanged();
}
}
public static readonly DependencyProperty LettersProperty =
DependencyProperty.Register("Letters", typeof(ObservableCollection<string>),
typeof(MyControlViewModel),
new PropertyMetadata(new ObservableCollection<string>(new[] { "~W", "~X", "~Y", "~Z" }), (s, e) => { }));
}
All the properties are dependency properties. I hope you noticed. I didn't just do that because I like to type. Though I do like to type. Fact is, I did that because in order to have internal binding you must use a dependency property - and a dependency property that raises property changed! That last part isn't trivial. But does it have to be in a view model? No. But I like it that way.
You might reference this: http://blog.jerrynixon.com/2013/07/solved-two-way-binding-inside-user.html
There's also no code behind for your MainPage. But the view model looks like this:
public class MainPageViewModel : BindableBase
{
public MainPageViewModel()
{
this._Letters = new ObservableCollection<string>(new[] { "A", "B", "C", "D" });
this._Numbers = new ObservableCollection<int>(new[] { 1, 2, 3, 4 });
}
public string Letter
{
get { return (string)GetValue(LetterProperty); }
set
{
SetValue(LetterProperty, value);
base.RaisePropertyChanged();
}
}
public static readonly DependencyProperty LetterProperty =
DependencyProperty.Register("Letter", typeof(string), typeof(MyControlViewModel),
new PropertyMetadata("Z", (s, e) => { }));
ObservableCollection<string> _Letters = new ObservableCollection<string>();
public ObservableCollection<string> Letters { get { return _Letters; } }
ObservableCollection<int> _Numbers = new ObservableCollection<int>();
public ObservableCollection<int> Numbers { get { return _Numbers; } }
}
The bindable base is standard, here's the code for it:
public abstract class BindableBase : DependencyObject, System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void SetProperty<T>(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
if (!object.Equals(storage, value))
{
storage = value;
if (PropertyChanged != null)
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
When it's all done, you should get exactly what you want. Something like this:
Not to over-simplify things. But, it's that easy.
Look, getting your head wrapped around XAML is not always easy when you start to nest contexts. I don't blame you for not getting it on first run. But I hope this helps you get started. Keep pushing
Best of luck!

XAML ListBox displays class name instead of class property

Here I have a Listbox configured where the TextBlox in the DataTemplate is set to bind the "Name" Property. But instead it shows the full class name "DomainClasses.Entities.Program". Why?
<Grid DataContext="{Binding _CurrentProgram }">
.....
.....
<ListBox x:Name="ProgramsListBox" Width="600" Height="400" Margin="50,0,50,0" ItemsSource="{Binding _Programs}" VerticalAlignment="Top">
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
<DataTemplate>
</ListBox>
----
----
</Grid>
This is the ViewModel class
public class MainPageViewModel : INotifyPropertyChanged
{
public MainPageViewModel()
{
_currentProgram = new Program();
_Programs = new ObservableCollection<Program>();
}
public async void SaveProgram(bool isEditing)
{
_Programs.Add(_currentProgram);
OnPropertyChanged();
}
private Program _currentProgram;
public Program _CurrentProgram
{
get { return _currentProgram; }
set
{
_currentProgram = value;
OnPropertyChanged();
}
}
private ObservableCollection<Program> _programs;
public ObservableCollection<Program> _Programs
{
get
{
return _programs;
}
set
{
this._programs = value;
OnPropertyChanged();
}
}
// Implement INotifyPropertyChanged Interface
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string caller = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
}
This is what you need:
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<Button/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Noticed the ListBox.ItemTemplate around the DataTemplate.
What you have:
<ListBox x:Name="ProgramsListBox" Width="600" Height="400" Margin="50,0,50,0" ItemsSource="{Binding _Programs}" VerticalAlignment="Top">
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
<DataTemplate>
</ListBox>
Creates a ListBox with a DataTemplate as a child (in the same sense that the items in the ItemsSource are children of the ListBox). If I remember correctly, when you set the ItemsSource of a ListBox, all items set in the other fashion are removed. So what you're ending up with is a ListBox with a bunch of Programs in it, which no ItemsTemplate set, so it simply shows the name of the bound class.
You need to add the data template inside listview.itemtemplate and then do the binding. Right now you are adding the data template as a child of the listview.

Dynamically Changing Combobox to TextBox in datagrid inside Cell Editing Template in silverlight 4

I'm making an application in Silverlight 4. I am facing a problem, I need to change a particular combobox into textbox programmatically when a particular column value(using combobox) of the same row is changed.I need to change this on event cellEditEnded.
Please note that I need to change celleditingtemplate combobox to textbox not celltemplate textblock.
This my Column where I need to take the decision of its combo box selected value.
<sdk:DataGridTemplateColumn Header="Instruction Type"
CanUserResize="False" CanUserReorder="False">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding operationType}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="instruction" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
This Column comboBox need to change to textbox here:
<sdk:DataGridTemplateColumn Header="Destination">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding destination}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="destination"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
C# code:
public class Instruction
{
public string operationType { get; set; }
public string destination { get; set; }
}
private void myGrid_CellEditEnded(object sender, DataGridCellEditEndedEventArgs e)
{
DataGrid obj = (DataGrid)sender;
Instruction obj1 = (Instruction)obj.SelectedItem;
if (e.Column.Header.ToString() == "Instruction Type")
{
if (obj1.operationType == "ADD" || obj1.operationType == "SUB")
{
// Here I need Require Code ????/
}
}
}
I m waitng for anyone Genius who help me out ..
Here is a working example http://anzensoft.smtp.ru/FlashKiller2/DataGridTrickTestPage.html
And here is the source code http://cid-a1de71e9f2ae2f82.office.live.com/self.aspx/.Public/DataGridTrick.zip
xaml code
<Grid x:Name="LayoutRoot" Background="White">
<sdk:DataGrid x:Name="dataGrid1" AutoGenerateColumns="False"
PreparingCellForEdit="dataGrid1_PreparingCellForEdit">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Instruction Type">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding operationType}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="instruction"
SelectedValue="{Binding operationType, Mode=TwoWay}">
<s:String>ADD</s:String>
<s:String>MUL</s:String>
</ComboBox>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Destination">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding destination}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<Grid>
<ComboBox x:Name="destinationComboBox"
SelectedValue="{Binding destination, Mode=TwoWay}">
<s:String>sdas</s:String>
<s:String>dasdasdasd</s:String>
</ComboBox>
<TextBox x:Name="destinationTextBox"
Text="{Binding destination, Mode=TwoWay}"
Visibility="Collapsed"/>
</Grid>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
C# code
namespace DataGridTrick
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
dataGrid1.ItemsSource = new List<Instruction>()
{
new Instruction(){operationType = "ADD", destination ="sdas"},
new Instruction(){operationType = "ADD", destination = "dasdasdasd"}
};
}
private void dataGrid1_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
{
if ((string)e.Column.Header == "Destination")
{
var tb = e.EditingElement.FindName("destinationTextBox") as TextBox;
var cb = e.EditingElement.FindName("destinationComboBox") as ComboBox;
var instruction = e.EditingElement.DataContext as Instruction;
if (tb == null || cb == null || instruction == null)
{
throw new
Exception("Something wrong here.. this dosen't have to happen!!");
}
else
{
if (instruction.operationType == "MUL")
{
tb.DataContext = e.EditingElement.DataContext;
cb.DataContext = null;
tb.Visibility = System.Windows.Visibility.Visible;
cb.Visibility = System.Windows.Visibility.Collapsed;
}
else
{
tb.DataContext = null;
cb.DataContext = e.EditingElement.DataContext;
tb.Visibility = System.Windows.Visibility.Collapsed;
cb.Visibility = System.Windows.Visibility.Visible;
}
}
}
}
}
public class Instruction
{
public string operationType { get; set; }
public string destination { get; set; }
}
}

how to make an button not visible when the image is also not visable in datagrid

i have an requirment based on the value 0,1 i am showing the image.
if the value is 0 i am not showing the image.
if the value is 1 i am showing the image.
but here when i am not showing the image for the row. i want even the button to be not shown?
now i need even the button not to be shown when image is not shown. on that row
how can i solve this issue
link to show how the screen shot
this is my xaml code. its works
<Button x:Name="myButton"
Click="myButton_Click">
<StackPanel Orientation="Horizontal">
<Image Margin="2, 2, 2, 2" x:Name="imgMarks" Stretch="Fill" Width="12" Height="12"
Source="Images/detail.JPG"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Visibility="{Binding Level, Converter={StaticResource LevelToVisibility}}"
/>
</StackPanel>
</Button>
this is my xaml code
<UserControl x:Class="SLGridImage.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:local="clr-namespace:SLGridImage"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" >
<UserControl.Resources>
<local:LevelToVisibilityConverter x:Key="LevelToVisibility" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<sdk:DataGrid x:Name="dgMarks" CanUserResizeColumns="False" SelectionMode="Single"
AutoGenerateColumns="False"
VerticalAlignment="Top"
ItemsSource="{Binding MarkCollection}"
IsReadOnly="True"
Margin="13,44,0,0"
RowDetailsVisibilityMode="Collapsed" Height="391"
HorizontalAlignment="Left" Width="965"
VerticalScrollBarVisibility="Visible" >
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="myButton"
Click="myButton_Click">
<StackPanel Orientation="Horizontal">
<Image Margin="2, 2, 2, 2" x:Name="imgMarks" Stretch="Fill" Width="12" Height="12"
Source="Images/detail.JPG"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Visibility="{Binding Level, Converter={StaticResource LevelToVisibility}}"
/>
</StackPanel>
</Button>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Name" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate >
<Border>
<TextBlock Text="{Binding Name}" />
</Border>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Marks" Width="80">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border>
<TextBlock Text="{Binding Marks}" />
</Border>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
</UserControl>
in .cs code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace SLGridImage
{
public partial class MainPage : UserControl
{
private MarksViewModel model = new MarksViewModel();
public MainPage()
{
InitializeComponent();
this.DataContext = model;
}
private void myButton_Click(object sender, RoutedEventArgs e)
{
}
}
public class MarksViewModel : INotifyPropertyChanged
{
public MarksViewModel()
{
markCollection.Add(new Mark() { Name = "ABC", Marks = 23, Level = 0 });
markCollection.Add(new Mark() { Name = "XYZ", Marks = 67, Level = 1 });
markCollection.Add(new Mark() { Name = "YU", Marks = 56, Level = 0 });
markCollection.Add(new Mark() { Name = "AAA", Marks = 89, Level = 1 });
}
private ObservableCollection<Mark> markCollection = new ObservableCollection<Mark>();
public ObservableCollection<Mark> MarkCollection
{
get { return this.markCollection; }
set
{
this.markCollection = value;
OnPropertyChanged("MarkCollection");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public class Mark
{
public string Name { get; set; }
public int Marks { get; set; }
public int Level { get; set; }
}
public class LevelToVisibilityConverter : System.Windows.Data.IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility isVisible = Visibility.Collapsed;
if ((value == null))
return isVisible;
int condition = (int)value;
isVisible = condition == 1 ? Visibility.Visible : Visibility.Collapsed;
return isVisible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
}
looking for an solution .please help me out
thanks
prince
Use element binding to bind to the Visibility property on the image:
<Button x:Name="myButton" Visibility={Binding Visibility, ElementName=imgMarks} Click="myButton_Click" >
Edit: i just reviewed your XAML and realised that the image was the button content - why don't you move this line:
Visibility="{Binding Level, Converter={StaticResource LevelToVisibility}}"
up to the button instead of having it on the image?