how can we access the controls in the Itemtemplate Silverlight - silverlight

i have a list box. i have an item template with a stack panel in it.
it has a text box and a check box in the item template.
is there a way i can access the check box and enable/disable it on selected index changed?
<UserControl.Resources>
<DataTemplate x:Key="UserApplicationsTemplate">
<StackPanel Orientation="Horizontal"
Margin="2"
ToolTipService.Placement="Mouse"
ToolTipService.ToolTip="{Binding Description, Mode=OneWay}">
<TextBlock Text="{Binding Mode=OneWay}"
TextWrapping="Wrap"
Width="100"
DataContext="{Binding ApplicationName, Mode=OneWay}" />
<CheckBox x:Name="{Binding ApplicationName, Mode=OneWay}"
Margin="5,0,0,0"
Click="IsActive_Clicked"
IsChecked="{Binding IsActive, Mode=OneWay}"
Content="IsActive"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<ListBox x:Name="lstbxUserApplications"
Height="357"
ItemsSource="{Binding Mode=OneWay}"
SelectionMode="Single"
ItemTemplate="{StaticResource UserApplicationsTemplate}" />

Assming you have your ItemsSource binded:
<ListBox x:Name="myList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Check, Mode=TwoWay}" />
<TextBlock Text="{Binding Name, Mode=TwoWay}"
Width="100" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="button1"
Content="Uncheck 2"
Click="button1_Click" />
You don't actually need to change the CheckBox.IsChecked property, but the value on your ItemsSource:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
myList.ItemsSource = ListInfo.getInfo();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
ListInfo item = myList.Items[1] as ListInfo;
item.Check = !item.Check;
}
}
public class ListInfo : INotifyPropertyChanged
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
NotifyPropertyChange("Name");
}
}
private bool check;
public bool Check
{
get
{
return check;
}
set
{
check = value;
NotifyPropertyChange("Check");
}
}
public static ObservableCollection<ListInfo> getInfo()
{
ObservableCollection<ListInfo> data = new ObservableCollection<ListInfo>();
data.Add(new ListInfo { Name = "Some text 1", Check = true });
data.Add(new ListInfo { Name = "Some text 2", Check = false });
data.Add(new ListInfo { Name = "Some text 3", Check = true });
return data;
}
public void NotifyPropertyChange(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
If you take a look at the event handler for the Click event on the button, you can see that all I did was get the item and changed the value. This immediately reflects on the UI.
UPDATE: I see that this was not what you asked for. Here are a couple of ideas:
You can have an event handler for your check box:
<ListBox x:Name="myList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Check, Mode=TwoWay}"
IsEnabled="True"
Content="{Binding Name, Mode=TwoWay}"
Click="CheckBox_Click" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And get the reference on the code behind:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox chk = sender as CheckBox;
chk.IsEnabled = false;
}
Of course the problem here is that if you disable the checkbox you lose access to the Click envent.
Another choice is to use the VisualTreeHelper to get reference to your CheckBox when the selection change on the ListBox:
private void myList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox list = sender as ListBox;
ListInfo current = list.SelectedItem as ListInfo;
List<CheckBox> checkBoxes = new List<CheckBox>();
getCheckBoxes(list, ref checkBoxes);
foreach (CheckBox checkBox in checkBoxes)
{
if (checkBox.Content.ToString() == current.Name)
{
checkBox.Foreground = new SolidColorBrush(Colors.Red);
}
}
}
public void getCheckBoxes(UIElement parent, ref List<CheckBox> items)
{
int count = VisualTreeHelper.GetChildrenCount(parent);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = VisualTreeHelper.GetChild(parent, i) as UIElement;
if (child.GetType() == typeof(CheckBox))
{
items.Add(child as CheckBox);
}
getCheckBoxes(child, ref items);
}
}
}
This of course is not the best option for performance but you get more flexibility.

Here is a solution using RadioButtons:
http://leeontech.wordpress.com/2009/03/18/creating-radiobuttonlist/
It should be easy enough to change it to checkboxes.

Related

C# WPF Binding: Textbox and Listbox inside DockPanel, using ObservableCollection

This example is from a textbook, which I believe there are some mistakes in it.
In this example, a class Nickname with two properties, Name and Nick, is created, and a ObservableCollection Nicknames is created to collect Nickname. In the View, there are two textboxes for users to fill in name and nickname, and a button to add these two values to Nicknames and show item on Listbox; mutually the two textboxes should show the name and nickname if certain item is selected in Listbox.
However, the two values are always Jack and Joe in the listbox and I believe the problem is more than likely on:
public Nickname() : this("Jack", "Joe") { }
How do I fix this problem? Or, is there any suggestion other than dock panel to fulfill the requirement?
Window1.xaml :
<DockPanel x:Name="dockPanel">
<TextBlock DockPanel.Dock="Top">
<TextBlock VerticalAlignment="Center">Name: </TextBlock>
<TextBox Text="{Binding Path=Name}" Width="50"/>
<TextBlock VerticalAlignment="Center">Nick: </TextBlock>
<TextBox Text="{Binding Path=Nick}" Width="50"/>
</TextBlock>
<Button DockPanel.Dock="Bottom" x:Name="addButton">Add</Button>
<ListBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock Text="{Binding Path=Name}" />:
<TextBlock Text="{Binding Path=Nick}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
Window1.xaml.cs :
public Window1()
{
InitializeComponent();
this.addButton.Click += addButton_Click;
// create a nickname collection
this.names = new Nicknames();
// make data available for binding
dockPanel.DataContext = this.names;
}
void addButton_Click(object sender, RoutedEventArgs e)
{
this.names.Add(new Nickname());
}
Nickname.cs :
public event PropertyChangedEventHandler PropertyChanged;
void Notify(string propName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propName));
}
}
string name;
public string Name {...}
string nick;
public string Nick {...}
public Nickname() : this("Jack", "Joe") { }
public Nickname(string name, string nick)
{
this.Name = name;
this.Nick = nick;
}
Nicknames.cs :
public class Nicknames : ObservableCollection<Nickname> { }

Checkbox is not checked in DevExpress GridControl using wpf

I am trying to work on DevExpress GridControl Checkbox column but problem is that when I binding the checkbox value in XAML code dynamically its not work perfectlly
below I provide you my demo project code :-
XAML Code:-
<dxg:GridControl AutoPopulateColumns="True" HorizontalAlignment="Left" Margin="0,40,0,0" Name="gridControl1" VerticalAlignment="Top" Height="318" Width="503">
<dxg:GridControl.View>
<dxg:TableView Name="tableView1" ShowTotalSummary="True" />
</dxg:GridControl.View>
<dxg:GridControl.Columns>
<dxg:GridColumn DisplayMemberBinding="{Binding Path=EvenOdd}" Header="Even/Odd" />
<dxg:GridColumn Name="PickColumn" Header="Pick" Width="30"
AllowColumnFiltering="False" AllowSorting="False">
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsValid}"
HorizontalAlignment="Center" VerticalAlignment="Center" >
</CheckBox>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
</dxg:GridColumn>
</dxg:GridControl.Columns>
</dxg:GridControl>
my cs file code:-
public class ss
{
public bool IsValid { get; set; }
public string EvenOdd { get; set; }
}
Code Behind:
public List<ss> sList = new List<ss>();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
if (i % 2 == 0)
{
sList.Add(new ss { IsValid = true, EvenOdd = "Even" });
}
else
{
sList.Add(new ss { IsValid = false, EvenOdd = "Odd" });
}
}
gridControl1.ItemsSource = sList;
}
Adding on to HighCore's answer. If you would like to edit the data in your grid.
See ColumnBase.CellTemplate Property:
To enable data editing, use an editor shipped with the DevExpress Data Editors Library for WPF. The editor's Name must be set to
'PART_Editor'.
Standard controls can be used in CellTemplate only for display purposes. Data editing is not allowed.
Then,
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
<dxg:GridColumn Name="PickColumn"
Header="Pick"
Width="30"
AllowColumnFiltering="False"
AllowSorting="False">
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<dxe:CheckEdit x:Name="PART_Editor"
EditValue="{Binding Path=Data.IsValid, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
</dxg:GridColumn>
You still need to use HighCore's implementation of INotifyPropertyChanged.
First of all you need to correct the binding inside the CellTemplate:
<CheckBox IsChecked="{Binding Path=RowData.Row.IsValid}"/>
Second, your data items should implement INotifyPropertyChanged:
public class ss:INotifyPropertyChanged
{
private bool _isValid;
private string _evenOdd;
public bool IsValid
{
get { return _isValid; }
set
{
_isValid = value;
OnPropertyChanged("IsValid");
}
}
public string EvenOdd
{
get { return _evenOdd; }
set
{
_evenOdd = value;
OnPropertyChanged("EvenOdd");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
xmlns:dxgcore="http://schemas.devexpress.com/winfx/2008/xaml/grid"
<dxgcore:GridColumn Width="20"
AllowEditing="True"
Binding="{Binding Path=IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Header="R"
Visible="{Binding CheckboxSelection}"
VisibleIndex="6">
<dxgcore:GridColumn.CellTemplate>
<DataTemplate>
<dxe:CheckEdit HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding
Path=View.DataContext.IsCheckedCommand}"
CommandParameter="{Binding RowData.Row}"
IsChecked="{Binding RowData.Row.IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Path=View.DataContext.IsCheckBoxEnabled, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</dxgcore:GridColumn.CellTemplate>
</dxgcore:GridColumn>
And Notifychanged property
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
RaisePropertyChanged("IsChecked");
}
}

How to make added buttons visible for the selected row in Wpf Datagrid

I have a Wpf Datagrid with edit,update and cancel buttons. Initially edit button is made visible, On click of edit button update and cancel button is made visible.
The issue here is when I click on edit button , update and cancel button are made visible for all the rows in the grid. I want it to be visible only for the selected row in the grid.
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Name="Stkbuttons">
<Button Name="BtnEdit" Content="Edit" Width="Auto" Click="BtnEdit_Click" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=BtnEditVisibility}"></Button>
<Button Name="BtnUpdate" Content="Update" Width="Auto" Click="BtnUpdate_Click" Visibility="{Binding RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=BtnUpdateVisibility}"></Button>
<Button Name="BtnCancel" Content="Cancel" Width="Auto" Click="BtnCancel_Click" Visibility="{Binding RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=BtnCancelVisibility}"></Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
public static readonly DependencyProperty BtnEditVisibilityProperty = DependencyProperty.Register("BtnEditVisibility", typeof(Visibility), typeof(OrderExecution));
public Visibility BtnEditVisibility
{
get { return (Visibility)GetValue(BtnEditVisibilityProperty); }
set { SetValue(BtnEditVisibilityProperty, value); }
}
public static readonly DependencyProperty BtnUpdateVisibilityProperty = DependencyProperty.Register("BtnUpdateVisibility", typeof(Visibility), typeof(OrderExecution));
public Visibility BtnUpdateVisibility
{
get { return (Visibility)GetValue(BtnUpdateVisibilityProperty); }
set { SetValue(BtnUpdateVisibilityProperty, value); }
}
public static readonly DependencyProperty BtnCancelVisibilityProperty = DependencyProperty.Register("BtnCancelVisibility", typeof(Visibility), typeof(OrderExecution));
public Visibility BtnCancelVisibility
{
get { return (Visibility)GetValue(BtnCancelVisibilityProperty); }
set { SetValue(BtnCancelVisibilityProperty, value); }
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// By default display editButton
BtnUpdateVisibility = Visibility.Collapsed;
BtnCancelVisibility = Visibility.Collapsed;
}
private void BtnUpdate_Click(object sender, RoutedEventArgs e)
{
BtnEditVisibility = Visibility.Visible;
BtnUpdateVisibility = Visibility.Collapsed;
BtnCancelVisibility = Visibility.Collapsed;
}
private void BtnEdit_Click(object sender, RoutedEventArgs e)
{
BtnEditVisibility = Visibility.Collapsed;
BtnUpdateVisibility = Visibility.Visible;
BtnCancelVisibility = Visibility.Visible;
}
Before enabling your buttons go to the parent of the clicked Edit button and get only his childs buttons (Update - Cancel) and change the visibility for only those two buttons.

ItemsControl modify Items at runtime

in my Silverlight project I have the following ItemsControl :
<ItemsControl x:Name="ItemsList">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border x:Name="brdItem" Opacity="1" MouseLeftButtonDown="brdItem_MouseLeftButtonDown">
<TextBlock x:Name="txtUsername" Text="{Binding Username}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
What I want is :
When my user clicks on an item. I want all the other items Opacity set to "0.3".
When the mouse is released I want all the items to come back to their original state (Opacity="1").
It's very simple if to use the MVVM pattern. Add the Opacity property to the item class and bind it to the Border.Opacity property:
<Border x:Name="brdItem" Opacity="{Binding Opacity}" MouseLeftButtonDown="brdItem_MouseLeftButtonDown">
<TextBlock x:Name="txtUsername" Text="{Binding Username}" />
</Border>
The item class:
public class ItemViewModel : INotifyPropertyChanged
{
public string Username { get; set; }
private double _opacity;
public double Opacity
{
get { return _opacity; }
set
{
_opacity = value;
RaisePropertyChanged("Opacity");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
After that your mouse event will look so:
public void brdItem_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var vm = ((FrameworkElement)sender).DataContext as ItemViewModel;
if (vm != null)
{
vm.Opacity = 1;
this.ItemsList.ItemsSource.OfType<ItemViewModel>()
.Where(item => item != vm)
.ToList()
.ForEach(item => item.Opacity = 0.3);
}
}
To return back to the initial state use the following code:
this.ItemsList.ItemsSource.OfType<ItemViewModel>()
.ToList().ForEach(item => item.Opacity = 1);

Change context menu in WPF TreeView for data

Is there a way to specify in a TreeView's HierarchicalDataTemplate to use a different ContextMenu depending on a property on the data an item is bound to?
For instance, display one ContextMenu if Item.IsFile is true, display a different one if Item.IsFolder is true, etc.
This is example for ListBox, I think you can easily modify it to work with TreeView.
XAML:
...
<Window.Resources>
<ContextMenu x:Key="FileContextMenu">
...
</ContextMenu>
<ContextMenu x:Key="DirContextMenu">
...
</ContextMenu>
<local:ItemToContextMenuConverter x:Key="ContextMenuConverter" />
</Window.Resources>
...
<ListBox x:Name="SomeList">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Path=Name}" ContextMenu="{Binding Converter={StaticResource ContextMenuConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code:
class Item
{
public string Name { get; set; }
public bool IsFile { get; set; }
}
[ValueConversion(typeof(Item), typeof(ContextMenu))]
public class ItemToContextMenuConverter : IValueConverter
{
public static ContextMenu FileContextMenu;
public static ContextMenu DirContextMenu;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Item item = value as Item;
if (item == null) return null;
return item.IsFile ? FileContextMenu : DirContextMenu;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ItemToContextMenuConverter.FileContextMenu
= this.Resources["FileContextMenu"] as ContextMenu;
ItemToContextMenuConverter.DirContextMenu
= this.Resources["DirContextMenu"] as ContextMenu;
List<Item> items = new List<Item>();
items.Add(new Item() { Name = "First", IsFile = true });
items.Add(new Item() { Name = "Second", IsFile = false });
SomeList.ItemsSource = items;
}
Hi I am doing similar thing on TreeView and I don't like that ItemToContextMenuConverter is executed on each item even if it is not used. It's maybe ok in a small project but if you add Enable/Disable code for each MenuItem than it can be slow.
This is maybe not the best (I just started with WPF), but I will share it with you.
Menu Resources:
<Window.Resources>
<ContextMenu x:Key="MnuFolderFavorites" StaysOpen="True">
<MenuItem Header="Remove from Favorites" Click="MnuFolder_RemoveFromFavorites_Click"></MenuItem>
</ContextMenu>
<ContextMenu x:Key="MnuFolder" StaysOpen="True">
<MenuItem Header="New Folder"></MenuItem>
<MenuItem Header="Rename" x:Name="MnuFolderRename" Click="MnuFolder_Rename_Click"></MenuItem>
<MenuItem Header="Add to Favorites" Click="MnuFolder_AddToFavorites_Click"></MenuItem>
</ContextMenu>
</Window.Resources>
TreeView:
<TreeView x:Name="TvFolders">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type data:Folder}" ItemsSource="{Binding Items}">
<StackPanel Orientation="Horizontal" PreviewMouseRightButtonDown="TvFoldersStackPanel_PreviewMouseRightButtonDown">
<Image Width="20" Height="20" Source="{Binding ImagePath}" />
<TextBlock Text="{Binding Title}" Margin="5,0,0,0" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Code:
private void TvFoldersStackPanel_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) {
((StackPanel) sender).ContextMenu = null;
Data.Folder item = (Data.Folder) ((StackPanel) sender).DataContext;
if (!item.Accessible) return;
if (item.Parent != null && item.Parent.Title.Equals("Favorites")) {
((StackPanel) sender).ContextMenu = MainWindow.Resources["MnuFolderFavorites"] as ContextMenu;
} else {
((StackPanel) sender).ContextMenu = MainWindow.Resources["MnuFolder"] as ContextMenu;
foreach (MenuItem menuItem in ((StackPanel) sender).ContextMenu.Items) {
switch (menuItem.Name) {
case "MnuFolderRename": {
menuItem.IsEnabled = item.Parent != null;
break;
}
}
}
}
}
private void MnuFolder_RemoveFromFavorites_Click(object sender, RoutedEventArgs e) {
string path = ((Data.Folder)((MenuItem)sender).DataContext).FullPath;
Settings.Default.FolderFavorites.Remove(path);
Settings.Default.Save();
FavoritesFolder?.AddFavorites(true);
}

Resources