I am currently trying to bind a textbox conditionally based on 3 different objects depending on a Level enum value. In the code sample below, what I hoping to achieve is to display values depending on the following condition:
Person Level0, bind/display ViewModel.Person.Level0.Name
Person Level1, bind/display ViewModel.Person.Level1.Name
Person Level2, bind/display ViewModel.Person.Level2.Name
With all that, the problem i have is that not of the objects are displaying as i am hoping. The textbox remains empty, with no values on display. What am i doing wrong?
<TextBox Margin="0,0,0,5">
<interactivity:Interaction.Behaviors>
<core:DataTriggerBehavior Binding="{x:Bind ViewModel.Person.Level, FallbackValue='', Mode=OneWay}" ComparisonCondition="Equal" Value="Level0">
<core:ChangePropertyAction PropertyName="Text" Value="{x:Bind ViewModel.Person.Level0.Name, FallbackValue=''}" />
</core:DataTriggerBehavior>
<core:DataTriggerBehavior Binding="{x:Bind ViewModel.Person.Level, FallbackValue='', Mode=OneWay}" ComparisonCondition="Equal" Value="Level1">
<core:ChangePropertyAction PropertyName="Text" Value="{x:Bind ViewModel.Person.Level1.Name, FallbackValue='', Mode=OneWay}" />
</core:DataTriggerBehavior>
<core:DataTriggerBehavior Binding="{x:Bind ViewModel.Person.Level, FallbackValue='', Mode=OneWay}" ComparisonCondition="Equal" Value="Level2">
<core:ChangePropertyAction PropertyName="Text" Value="{x:Bind ViewModel.Person.Level2.Name, FallbackValue='', Mode=OneWay}" />
</core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBox>
This should work.
Notes:
This code uses a string instead of Level in the Person class because enum binding seems not to work (I'm not sure) with ChangePropertyAction.
The MainPage is named as "ThisPage" so we can bind the ViewModel inside the ChangePropertyAction.
MainPage.xaml
<Page
x:Class="ConditionalBindingTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:local="using:ConditionalBindingTest"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="ThisPage"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid>
<TextBox>
<interactivity:Interaction.Behaviors>
<core:DataTriggerBehavior
Binding="{x:Bind ViewModel.Person.Level, Mode=OneWay}"
ComparisonCondition="Equal"
Value="Level0">
<core:ChangePropertyAction
PropertyName="Text"
Value="{Binding ElementName=ThisPage, Path=ViewModel.Person.Level0.Name, Mode=OneWay}" />
</core:DataTriggerBehavior>
<core:DataTriggerBehavior
Binding="{x:Bind ViewModel.Person.Level, Mode=OneWay}"
ComparisonCondition="Equal"
Value="Level1">
<core:ChangePropertyAction
PropertyName="Text"
Value="{Binding ElementName=ThisPage, Path=ViewModel.Person.Level1.Name, Mode=OneWay}" />
</core:DataTriggerBehavior>
</interactivity:Interaction.Behaviors>
</TextBox>
</Grid>
</Page>
MainPage.xaml.cs
using Microsoft.UI.Xaml.Controls;
namespace ConditionalBindingTest;
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public MainPageViewModel ViewModel { get; } = new();
}
MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
namespace ConditionalBindingTest;
public enum Level
{
Level0,
Level1,
}
public class LevelName
{
public LevelName(Level level)
{
Name = $"{level} Name";
}
public string Name { get; }
}
public class Person
{
public string Level { get; } = ConditionalBindingTest.Level.Level0.ToString();
public LevelName Level0 { get; } = new(ConditionalBindingTest.Level.Level0);
public LevelName Level1 { get; } = new(ConditionalBindingTest.Level.Level1);
}
public partial class MainPageViewModel : ObservableObject
{
[ObservableProperty]
private Person person = new();
}
What am i doing wrong?
You use x:Bind where it's not supported
You implement logic in the XAML markup of the view
x:Bind directly to another read-only property of the view model that is defined something like this:
public string DisplayValue
{
get
{
switch (Person.Level)
{
case "Level0":
return Person.Level0.Name;
case "Level1":
return Person.Level1.Name;
case "Level2":
return Person.Level2.Name;
}
return string.Empty;
}
}
C# is a much more expressive, more concise language than XAML, and while it may be possible to create an entire fairly complex view in markup only, it doesn't mean that it's always a good idea doing so. In this case, you should move the logic to the view model or the Person class itself.
Related
I'm using WinUI in combination with the microsoft MVVM toolkit.
However im experiencing some issues with Binding and can't figure out where the problem lies.
The ViewModel and models used within the ViewModel are of type observableObject. The Command is fired, and the data is fetched. However the binding is not showing a result in the UI, unless i change the xaml and hot reload the change.
My page:
<Page
x:Class="ThrustmasterGuide.Pages.WheelBasePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ThrustmasterGuide.Pages"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:ThrustmasterGuide.DataAccess.Context.Model"
xmlns:wheelbase="using:ThrustmasterGuide.ViewModel.Wheelbase"
xmlns:xaml="using:ABI.Microsoft.UI.Xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:converters="using:ThrustmasterGuide.Converters"
xmlns:wheelBase="using:ThrustmasterGuide.Model.WheelBase"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance wheelbase:WheelBaseViewModel, IsDesignTimeCreatable=True}">
<Page.Resources>
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<converters:InvertBoolToVisibilityConverter x:Key="InvertBoolToVisibilityConverter" />
</Page.Resources>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Loaded">
<core:EventTriggerBehavior.Actions>
<core:InvokeCommandAction Command="{x:Bind ViewModel.LoadWheelBaseCommand}" />
</core:EventTriggerBehavior.Actions>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
<StackPanel Padding="16 16 16 16" Orientation="Vertical">
<StackPanel>
<TextBlock FontSize="18" Text="{x:Bind ViewModel.WheelBase.Name}" />
<TextBlock FontSize="18" Text="Symptomen:" />
<TextBlock Text="Kies hieronder een symptoom uit om te starten." />
<ProgressRing IsActive="true"
Visibility="{x:Bind ViewModel.LoadWheelBaseCommand.IsRunning, Converter={StaticResource BoolToVisibilityConverter}}" />
<TreeView ItemsSource="{x:Bind ViewModel.WheelBase.Symptoms, Mode=OneWay}">
<TreeView.ItemTemplate>
<DataTemplate x:DataType="wheelBase:SymptomModel">
<TreeViewItem ItemsSource="{x:Bind Children}" Content="{x:Bind Description}" />
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</StackPanel>
<Button VerticalAlignment="Bottom" Command="{x:Bind ViewModel.LoadWheelBaseCommand}"
Content="Refresh">
</Button>
</StackPanel>
My ViewModel:
public class WheelBaseViewModel : ObservableRecipient
{
public WheelBaseModel WheelBase { get; set; }
public string WheelBaseName { get; set; }
private readonly WheelBaseService _wheelBaseService;
public IAsyncRelayCommand LoadWheelBaseCommand { get; }
public WheelBaseViewModel(WheelBaseService wheelBaseService)
{
_wheelBaseService = wheelBaseService;
LoadWheelBaseCommand = new AsyncRelayCommand(FetchWheelBase);
}
public async Task FetchWheelBase()
{
WheelBase = await _wheelBaseService.GetWheelBase(WheelBaseName);
}
}
My model:
namespace ThrustmasterGuide.Model.WheelBase
{
public class WheelBaseModel : ObservableObject
{
public string Name { get; set; }
public ObservableCollection<SymptomModel> Symptoms { get; set; }
}
}
My Code behind:
public sealed partial class WheelBasePage : Page
{
public WheelBasePage()
{
this.InitializeComponent();
this.DataContext = App.Current.Services.GetService<WheelBaseViewModel>();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
this.ViewModel.WheelBaseName = e.Parameter as string;
}
public WheelBaseViewModel ViewModel => (WheelBaseViewModel)DataContext;
}
What is it that i missed to make the UI bind to the WheelBaseModel values?
Update I added mode=OneWay, but still not updating.
Should it be noted that im showing pages within a content frame after navigation?
{x:Bind} has a default mode of OneTime, unlike {Binding}, which has a default mode of OneWay.
I believe you need to use SetProperty so it's known when to raise such events?
https://learn.microsoft.com/en-us/windows/communitytoolkit/mvvm/observableobject
namespace ThrustmasterGuide.Model.WheelBase
{
public class WheelBaseModel : ObservableObject
{
public string Name
{
get => name;
set => SetProperty(ref name, value);
}
public ObservableCollection<SymptomModel> Symptoms { get; set; }
}
and also bind mode = OneWay
<TextBlock FontSize="18" Text="{x:Bind ViewModel.WheelBase.Name, Mode=OneWay}" />
No indication that your properties notify of their changes.
https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanged
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>
I am new in MVVVM so please forgive me if it is stupid question. I am using this example http://www.codeproject.com/Articles/36848/WPF-Image-Pixel-Color-Picker-Element and included there library to get color of indicated by user pixel of image. it looks nice and dipsalys in rectangle selected color but i neeed to bind the selecteed value to viewmodel.
here is my xaml code:
<Window x:Class="MovieEditor.View.PixelSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrls="clr-namespace:ColorPickerControls;assembly=ColorPickerControls"
xmlns:local="clr-namespace:MovieEditor.MVVMCommon"
Title="FilterDesigner" Height="550" Width="550"
Icon="..\Resources\Images\icon.ico"
xmlns:VM="clr-namespace:MovieEditor.ViewModel">
<Window.DataContext>
<VM:PixelSelectorVM/>
</Window.DataContext>
<Window.Resources>
<local:ColorToBrushConverter x:Key="ColorToBrushConverter"/>
</Window.Resources>
<Grid Background="#FF191919" >
<DockPanel>
<Grid Margin="10,10,10,1">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto" MinHeight="38"/>
</Grid.RowDefinitions>
<Border BorderBrush="White" BorderThickness="5" Margin="0,39,0,11">
<ctrls:ImageColorPicker Binding.XmlNamespaceManager="{Binding p PixelSelectorVM.MyImageColorPicker, UpdateSourceTrigger=PropertyChanged}"
x:Name="image" Source ="{Binding Frame}" Margin="0,36,0,0"
/>
</Border>
<Border Width="77"
HorizontalAlignment="Center"
BorderBrush="White" BorderThickness="1" Margin="263,2,182,435">
<Rectangle Fill="{Binding ElementName=image, Path=SelectedColor,
Converter={StaticResource ColorToBrushConverter}}" RenderTransformOrigin="0.549,0.429" Margin="1"/>
</Border>
<Button Content="Save" Command="{Binding Save}" Margin="165,0,0,4" Grid.Row="1" HorizontalAlignment="Left" Width="60"/>
<Label Content="Selected pixel color:" HorizontalAlignment="Left" Height="18" Margin="140,11,0,0" VerticalAlignment="Top" Width="110"/>
<Button Content="Cancel" Command="{Binding Cancel}" Margin="0,1,165,4" HorizontalAlignment="Right" Width="60" RenderTransformOrigin="0.5,0.5" Grid.Row="1">
</Button>
</Grid>
</DockPanel>
</Grid>
</Window>
</code>
And here is my view model:
public class PixelSelectorVM : ViewModelBase
{
private BitmapImage frame;
public MainWindowVM parentMainWindowVM;
private ImageColorPicker imageColorPicker;
public ImageColorPicker MyImageColorPicker
{
get
{
return this.imageColorPicker;
}
set
{
this.imageColorPicker = value;
OnPropertyChanged("MyImageColorPicker");
}
}
public BitmapImage Frame
{
get
{
return this.frame;
}
set
{
this.frame = value;
OnPropertyChanged("Frame");
}
}
public PixelSelectorVM(BitmapImage image, MainWindowVM mainWindowVM)
{
this.frame = image;
this.parentMainWindowVM = mainWindowVM;
this.imageColorPicker = new ImageColorPicker();
this.imageColorPicker.Source = image;
}
public PixelSelectorVM() { }
public ICommand Save
{
get
{
return new RelayCommand(SaveExecute);
}
}
public ICommand Cancel
{
get
{
return new RelayCommand(CancelExecute);
}
}
private void SaveExecute()
{
}
private void CancelExecute()
{
}
}
Please suggest me solution how can i pass the selected color to view model
You should be able to bind ImageColorPicker's SelectedColor to ViewModel's Property.
So in XAML add the binding:
SelectedColor="{Binding MySelectedColor, Mode=TwoWay}"
And in VM add the MySelectedColor property:
private Color selectedColor;
public Color MySelectedColor
{
get
{
return this.selectedColor;
}
set
{
this.selectedColor = value;
OnPropertyChanged("MySelectedColor");
}
}
When control's SelectedColor changes, it should automatically update the MySelectedColor in your VM.
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.
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?