Expander Control - UWP - xaml

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>

Related

ListPicker selected item not changing when selected in Full Mode

I have List of Categories that I want to display in a ListPicker. The Class is:
public class Category : INotifyPropertyChanged, INotifyPropertyChanging
{
private int _id;
public int Id
{
get { return _id; }
set
{
if (_id == value) return;
NotifyPropertyChanging();
_id = value;
NotifyPropertyChanged();
}
}
private string _description;
public string Description
{
get { return _description; }
set
{
if (_description == value) return;
NotifyPropertyChanging();
_description = value;
NotifyPropertyChanged();
}
}
#region INotifyPropertyChanging and INotifyPropertyChanged Members
public event PropertyChangingEventHandler PropertyChanging;
/// <summary>
/// Used to notify the data context that a property is about to change...
/// </summary>
private void NotifyPropertyChanging([CallerMemberName] string propertyName = null)
{
if (PropertyChanging != null) PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Used to notify the data context that a property has changed...
/// </summary>
private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
I have a ListPicker Full Mode Item Template defined as a XAML Resource:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="FullModeItemTemplate">
<TextBlock d:DataContext="{Binding}"
Text="{Binding Description}"
/>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
and a Listpicker for it defined in XAML on the Page:
<phone:PhoneApplicationPage
x:Class="QuestionPage"
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"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeMedium}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed.-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Border Style="{StaticResource ButtonBorderStyle}"
Background="Blue"
BorderBrush="White"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the app and page title.-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="0,10,0,0">
<TextBlock x:Name="ApplicationTitle"
Text="pagetitle"
Style="{StaticResource PhoneTextLargeStyle}"/>
<TextBlock x:Name="PageTitle"
Text="subtitle"
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
</StackPanel>
<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="0,0,0,15">
<TextBlock Text="question" Margin="20,5,0,0"/>
<TextBox x:Name="ItemDescription"/>
<TextBlock Text="category" Margin="20,0,0,-10"/>
<toolkit:ListPicker x:Name="CategoriesListPicker"
DataContext="{Binding}" ItemsSource="{Binding Categories}"
DisplayMemberPath="Description"
FullModeHeader="Categories:"
FullModeItemTemplate="{StaticResource FullModeItemTemplate}"
CacheMode="BitmapCache"
>
</toolkit:ListPicker>
</StackPanel>
</Grid>
</Border>
</Grid>
</phone:PhoneApplicationPage>
The ItemDescription and Category are to be saved to a Question Class Item in another list... but this is not relevant to the problem...
If the Category List has five or less items in it, the selection list is displayed in short mode and items from the list can be selected and this selection is reflected in the control field. This is fine.
If I increase the Categories List to over five items, the ListPicker switches to full mode, and although the display of these is fine, when an item from the list is selected, the item shown in the control field remains unchanged.
Is this a bug in the Full Mode selection list or am I missing something?
Any help you can give will be appreciated...
In my original question I stated:
"The ItemDescription and Category are to be saved to a Question Class Item in another list... but this is not relevant to the problem..."
Although this is correct, it made me realise I'd not taken into consideration how the data items for the page containing the ListPicker are populated before it is displayed. This data population also includes setting the SelectedItem parameter for the ListPicker to the Category for the Question.
I set this data population to happen during the OnNavigatedTo protected override for the page. I'd not realised that the OnNavigatedTo method also gets triggered on return from the Full Mode Listpicker which of course then reset the SelectedItem to the original value for the Question. To avoid this problem, I put in a check for null on the QuestionId so OnNavigatedTo only populates the data items on initial entry to the page... problem solved!

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!

LongListMultiSelector: How to use it with MVVM

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.

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.

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?