WPF pass ListView selected items to another ListView - c#

I have a list view with some items in the main window. Then I add checked boxes so that when an item is selected it also get checked.
Now I tried to pass the selected items from that list view to another list view but here is what I get:
Here is my XAML:
<Window x:Class="WpfApp1.MainWindow"
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:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Canvas HorizontalAlignment="Left" Height="299" Margin="10,10,0,0" VerticalAlignment="Top" Width="497">
<TabControl Height="279" Canvas.Left="10" Canvas.Top="10" Width="477">
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5">
<ListView Name="lv1" Margin="0,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Height="110" Width="471">
<ListViewItem>
<CheckBox >
<StackPanel Orientation="Horizontal">
<TextBlock Text="Apple"/>
</StackPanel>
</CheckBox>
</ListViewItem>
<ListViewItem>
<CheckBox >
<StackPanel Orientation="Horizontal">
<TextBlock Text="Orange"/>
</StackPanel>
</CheckBox>
</ListViewItem>
</ListView>
<Button Content="Copy" Width="100" Height="25" Click="Button_Click"/>
<ListView Name="lv2" HorizontalAlignment="Left" VerticalAlignment="Bottom" Height="110" Width="471"/>
</Grid>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</TabItem>
</TabControl>
</Canvas>
</Grid>
Here is code behind in c#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
List<string> lv1list = new List<string>();
foreach (var i in lv1.SelectedItems)
{
lv1list.Add(i.ToString());
}
lv2.Items.Add(lv1.SelectedItems);
}
}
}
What went wrong here?

The problem is you're adding a complete list as an item which is why you're getting the (Collection) value.
What you can do is get all the selected item in a list them loop and add them one by one
private void Button_Click(object sender, RoutedEventArgs e)
{
var selectedItems = lv1.SelectedItems;
for(int i = 0; i < selectedItems.Count; i++)
{
lv2.Items.Add(selectedItems[i]);
}
}
You might also want to clear your lv2 before adding the new values
lv2.Items.Clear();
Another option which wouldn't require you to press a button so that the values appear in the second listview would be to bind the ItemsSource of your lv2 to the SelectedItems of your lv1
lv2.ItemsSource = lv1.SelectedItems;
You can do that once at the beginning and lv2 will always contain the selected items of lv1 and will update as soon as the selected items changes.

I made some more modifications and then I realized it is not working as it should. I have a "foreach statement" looping through all the checked/selected items in listBox1, then inside the "foreach statement" there is an "If statement" to check if the checked/selected items from listBox1 are not in listBox2, if they aren't then they are copied to listBox2. Each condition of the "If statement" should display relevant MessageBox. The problem now is that the "If statement" doesn't work properly. I know this, because I cannot see the correct relevant MessageBox to the correct condition of the "If statement". However the items are not duplicated, meaning they are not being copied over and over only they appear duplicated in the MessageBox. Here is my code and hope someone can spot my mistake
using System.Windows;
using System.Windows.Controls;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System;
namespace MYNAMESPACE
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
// To initialise the List and use it outside the class
//MyListItem instanceOfClass = new MyListItem();
//List<CheckBoxListItem> listOfItems = instanceOfClass.MyMethod();
//listBox1.ItemsSource = listOfItems;
}
public class CheckBoxListItem : INotifyPropertyChanged
{
public bool CheckStatus { get; set; }
public string Text { get; set; }
public CheckBoxListItem(bool _CheckStatus, string _Text)
{
CheckStatus = _CheckStatus;
Text = _Text;
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class MyListItem
{
public List<CheckBoxListItem> MyMethod()
{
List<CheckBoxListItem> items = new List<CheckBoxListItem>();
items.Add(new CheckBoxListItem(false, "Item 1"));
items.Add(new CheckBoxListItem(false, "Item 2"));
items.Add(new CheckBoxListItem(false, "Item 3"));
return items;
}
}
public List<string> selectedNames = new List<string>();
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
var checkBox = sender as CheckBox;
var item = checkBox.Content;
bool isChecked = checkBox.IsChecked.HasValue ? checkBox.IsChecked.Value : false;
if (isChecked)
selectedNames.Add(item.ToString());
else
selectedNames.Remove(item.ToString());
}
public string selections;
bool updatedItems;
public void Button_Click(object sender, RoutedEventArgs e)
{
foreach (string selection in selectedNames)
{
selections += selection + Environment.NewLine;
if (!listBox2.Items.Contains(selection))
{
listBox2.Items.Add(selection);
updatedItems = true;
}
else if (listBox2.Items.Contains(selection))
{
updatedItems = false;
}
}
if (updatedItems == true)
MessageBox.Show("Add items are: " + selections);
else if (updatedItems == false)
MessageBox.Show("No update to selection was made.");
}
private void CheckStatus(string propName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
}

Related

How to edit an observableCollection while WPF app is running

I am making a To-do List application for one of my classes. Now I have tried in a console app to update objects (of TaskModels a type I defined) inside an observable collection and it has seemed to work. But now I am trying to update the entries inside the observable collection. I have wrote some code that I thought was going to change the value but it did not change the value in the ListBox I will include the code below for TaskModel.
Originally I was wanting to have the edit button open a new window that allowed the user to input what the wanted the task to be and then they press a button maybe called change task and it sends it back to the original window. But for simpleness at the moment I would like to change with the textbox in the user control in the main window.
I am also pretty new to making apps in WPF so this is all pretty new to me and I am trying to learn it all.
Below is my TaskModel and the only thing it does is get and set the TaskName.
namespace ToDoList.Model
{
public class TaskModel
{
private string taskName;
public string TaskName {
get { return taskName; }
set { taskName = value; }
}
}
}
I wrote the following code hoping that it would allow me to change the value of the TaskName but it does not seem to be working. Is there anyhting else that I should add to the code for it change the TaskName properly? Any tips or anything that could help me with this problem.
Below is the XAML code for my main window. It is a really simple UI, it features a ListBox which uses an ObservableCollection as its itemsource and when the listbox has a new item put into it has a checkbox to the left of it.
Below I will include the main window XAML and the C# code.
<Window x:Class="ToDoList.DemoMainWindow"
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:local="clr-namespace:ToDoList"
mc:Ignorable="d"
Title="The To-Do List" Height="500" Width="500" FontSize="22"
Background="White">
<Grid Margin="10" Background="BlueViolet">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2">
<TextBlock>Tasks to do:</TextBlock>
<!-- <TextBlock>Blah blah</TextBlock> -->
<!-- <local:UCLabelTextBxInput x:Name="TxtUCSaveToFileLocation" Title="Save to File Location" MaxLength="50"></local:UCLabelTextBxInput> -->
<ListBox x:Name="LstBoxTasks" MinHeight="200" MaxHeight="200" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Mode=OneWay}" Content="{Binding TaskName, Mode=TwoWay}" FontSize="14"></CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<local:UCLabelTextBxInput x:Name="TxtUCEnteredTask" Title="Enter Task Here:" MaxLength="50"></local:UCLabelTextBxInput>
<Button x:Name="BtnAddTask" Click="BtnAddTask_Click" Background="Chocolate">Add Task to List</Button>
</StackPanel>
<Button Grid.Column="0" Grid.Row="1" Margin="0,10,20,0" x:Name="btnDeleteTask" Click="BtnDeleteTask_Click" Background="Chocolate">Delete Task</Button>
<Button Grid.Column="1" Grid.Row="1" Margin="20,10,0,0" Background="Chocolate" Click="BtnEditTask_Click">Edit Task</Button>
<Button Grid.Column="0" Grid.Row="2" Margin="0,10,0,10" Grid.ColumnSpan="2" Background="Chocolate" Click="BtnHelp_Click">Help</Button>
</Grid>
</Window>
Then finally here is the C# code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using ToDoList.Model;
namespace ToDoList
{
/// <summary>
/// Interaction logic for DemoMainWindow.xaml
/// </summary>
public partial class DemoMainWindow : Window
{
SaveDataModel saveDataModel = new SaveDataModel();
ObservableCollection<TaskModel> tasksModels = new ObservableCollection<TaskModel>();
public DemoMainWindow()
{
InitializeComponent();
TxtUCEnteredTask.txtLimitedInput.Text = "Do the dishes";
LstBoxTasks.ItemsSource = tasksModels;
}
private void BtnAddTask_Click(object sender, RoutedEventArgs e)
{
tasksModels.Add(new TaskModel() { TaskName = TxtUCEnteredTask.txtLimitedInput.Text });
}
private void BtnDeleteTask_Click(object sender, RoutedEventArgs e)
{
if(LstBoxTasks.SelectedItem != null)
{
tasksModels.Remove(LstBoxTasks.SelectedItem as TaskModel);
}
}
private void BtnHelp_Click(object sender, RoutedEventArgs e)
{
HelpWindow helpWindow = new HelpWindow();
helpWindow.Show();
}
private void BtnEditTask_Click(object sender, RoutedEventArgs e)
{
if (LstBoxTasks.SelectedItem != null)
{
tasksModels[LstBoxTasks.SelectedIndex].TaskName = TxtUCEnteredTask.txtLimitedInput.Text;
}
}
}
}
Your property TaskName is not calling the OnPropertyChanged() method that notifies your view that the name changed.
You can do something like that:
private string taskName;
public string TaskName {
get { return taskName; }
set {
if( value != taskName) {
taskName = value;
OnPropertyChanged("TaskName");
}
}
}
protected void OnPropertyChanged(string name) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
Remarks:
The best way to do WPF is to do MVVM.
You should check out this link : https://www.codeproject.com/Tips/806587/Basic-MVVM-Listbox-Binding-in-WPF

How to assign property (get; set;) to a WPF User Control?

I'm trying to learn property (get and set) in C#. I'm still new to the language and currently making a simple program using WPF with some textboxes, as you can see in the pictures.
So, here are the description :
Input : it's where user can type the input, located at MainWindow
Output 1 : it's where to see the typed string in input, located at MainWindow
Output 2 : same like Output 1, located inside tab one, at MainWindow.
Output 3 : same like Output 1, located inside tab two, still at MainWindow.
Output 4 : same like Output 1, located inside tab two, referred to local UserControl Page1.
Button : a button to "save" the input
Here are the codes :
Main Window : solution --> I added x:Name="Page1" after local:page1
<!-- MainWindow.xaml -->
<Window x:Class="TestGetSet.MainWindow"
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:local="clr-namespace:TestGetSet"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl x:Name="tabControl" HorizontalAlignment="Left" Height="212" Margin="37,20,0,0" VerticalAlignment="Top" Width="447">
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5">
<TextBox x:Name="output2" HorizontalAlignment="Left" Height="23" Margin="156,76,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
<Label x:Name="label2" Content="Output 2" HorizontalAlignment="Left" Margin="156,46,0,0" VerticalAlignment="Top"/>
</Grid>
</TabItem>
<TabItem Header="TabItem">
<Grid Background="#FFE5E5E5">
<TextBox x:Name="output3" HorizontalAlignment="Left" Height="23" Margin="321,26,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
<local:Page1 x:Name="Page1"/>
<Label x:Name="label3" Content="Output 3" HorizontalAlignment="Left" Margin="321,0,0,0" VerticalAlignment="Top"/>
</Grid>
</TabItem>
</TabControl>
<TextBox x:Name="input" Text=""/>
<TextBox x:Name="output1" Text=""/>
<Button x:Name="button" Content="Button" Click="button_Click"/>
<Label x:Name="label" Content="Input" HorizontalAlignment="Left" Margin="37,239,0,0" VerticalAlignment="Top"/>
<Label x:Name="label1" Content="Output 1" HorizontalAlignment="Left" Margin="364,239,0,0" VerticalAlignment="Top"/>
</Grid>
MainWindow code behind : solution --> added one line Page1.passingvalue(..)
// MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
public partial class MainWindow : Window
{
public myProperty myProp = new myProperty();
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
myProp.myData = input.Text;
output1.Text = myProp.myData;
output2.Text = myProp.myData;
output3.Text = myProp.myData;
Page1.passingvalue(myProp.myData);
}
}
Next is Page1.xaml (No changes made here for the solution)
<!-- Page1.xaml-->
<UserControl x:Class="TestGetSet.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestGetSet"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBox x:Name="output4" Text=""/>
<Label x:Name="label" Content="Output 4" HorizontalAlignment="Left" Margin="92,110,0,0" VerticalAlignment="Top"/>
</Grid>
</UserControl>
Page1 code behind : solution--> deleted timer and added passingvalue
// Page1.xaml.cs
using System;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Threading;
using System.ComponentModel;
namespace TestGetSet
{
public partial class Page1 : UserControl
{
private Thread _receiveThread;
myProperty myProp = new myProperty();
public Page1()
{
InitializeComponent();
/*DispatcherTimer MyTimer = new DispatcherTimer();
MyTimer.Interval = new TimeSpan(0, 0, 0, 0, 100);
MyTimer.Tick += MyTimer_Tick;
MyTimer.Start();*/
}
public void passingvalue(string m)
{
output4.Text = m;
}
/*private void MyTimer_Tick(object sender, EventArgs e)
{
output4.Text = myProp.myData;
}*/
}
}
Last one, the property, simple version :
// myProperty.cs
namespace TestGetSet
{
public class myProperty
{
public string myData { get; set }
}
}
Property with INotifyPropertyChanged :
// myProperty.cs
using System.ComponentModel;
namespace TestGetSet
{
public class myProperty : INotifyPropertyChanged
{
private string _textdata;
public string myData {
get
{
return _textdata;
}
set
{
_textdata = value;
NotifyPropertyChanged("myData");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Here are the screenshots of the program window :
one
and
two
As you can see, only Output4 is empty and the other outputs still give me results even though I don't use INotifyPropertyChanged. My question is why, and how can I fix this? I wonder if it's because I'm using UserControl for Page1, which the Output4 is in. I've been looking for the answer but came up with nothing. Any help is much appreciated. Thank you.
Okay so I updated the code. It's working now. I got the reference for passingvalue from : How to Pass a Value From a Window to a UserControl in WPF
Thank you.
Your issue here is that you misstakes the MainWindow's myProperty and Page1's myProperty.
In Page1, you set the output4.Text using myProp.myData which is wrong because myProp is the Page1's myProp which is never updated.
If you pass the MainWindow's reference to Page1 and instead write something like output4.Text = myMainWindowReferenc.myProp.myData; it will work as intended.
You could also add setting to output4 in your button_Click function by naming the Page1 in the XAML:
private void button_Click(object sender, RoutedEventArgs e)
{
myProp.myData = input.Text;
output1.Text = myProp.myData;
output2.Text = myProp.myData;
output3.Text = myProp.myData;
Page1.output4.Text = myProp.myData;
}

How to uncheck all CheckBox in side datatemplate of gridcontrol on button click in WPF using C#?

I have a CheckBox in GridControl Column. After performing some operation the selected checkboxes inside GridControl must be UNCHECKED on button click in WPF. Any idea?
<dxg:GridControl Name="grdInfill" Height="700" VerticalAlignment="Center">
<dxg:GridControl.Columns>
<dxg:GridColumn AllowEditing="True">
<dxg:GridColumn.CellTemplate>
<DataTemplate>
CheckBox Name="chkSelect" HorizontalAlignment="Center" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected,Mode=TwoWay}" Checked="CheckEdit_Checked" Unchecked="CheckEdit_Unchecked"/>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
</dxg:GridColumn>
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<dxg:TableView Name="grdInfillInner" ShowTotalSummary="True" AutoWidth="True"
DetailHeaderContent="True" ShowIndicator="False" ShowGroupPanel="False"
CellValueChanging="grdInfillInner_CellValueChanging">
<!--GroupRowTemplate="{StaticResource descriptionHeader}"-->
</dxg:TableView>
</dxg:GridControl.View>
</dxg:GridControl>
<Button Name="BtnClearAllCheckbox" Content="Clear All Checkbox" Height="20" Width="80" />
Help Appreciated!
In my opinion, one of the solutions can pass by this:
Have a property on the datacontext that is binded to the isselected property on the checkbox;
On button click, pass the gridview itemsource in the CommandParameter, or if you bind the itemssource to a list in the datacontext use that list. Do a foreach and put the property IsSelected (that i said in 1) to false...The bind in the checkbox must be two way and implement the InotifyPropertyChanged.
If I was not clear in any point, please just tell me :)
Regards,
EDIT ----------------------------
This is my example working with the default controls (I don't have devexpress).
On the XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="checkBoxTemplate">
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked"></CheckBox>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<ListView ItemsSource="{Binding listExample}">
<ListView.View>
<GridView>
<GridViewColumn CellTemplate="{StaticResource checkBoxTemplate}"></GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Test1}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<Button Content="Uncheck all" Click="Button_Click"></Button>
</StackPanel>
</Grid>
</Window>
On the CodeBehind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public List<Example> listExample { get; set; }
public MainWindow()
{
InitializeComponent();
this.listExample = new List<Example>();
listExample.Add(new Example { IsChecked = false, Test1 = "teste" });
listExample.Add(new Example {IsChecked = false, Test1 = "TTTTT!" });
DataContext = this;
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.listExample.ForEach(x => x.IsChecked = false);
}
}
}
And I have this class with the implementation of INotifyPropertyChanged:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApplication1
{
public class Example : INotifyPropertyChanged
{
private bool isChecked;
public bool IsChecked { get { return isChecked; } set { SetField(ref isChecked, value, "IsChecked"); } }
public string Test1 { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, string propertyName)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
}
Just analyse this and try to understand and adapt to your code.
Regards,

WPF Populating list, assigning on-click event handler with custom variables to pass

I'm populating a listBox, Each list item has a button.
I've got it populating text in to the list, but I'd like each button to have the correct event handler and the house number to be passed to it.
Here's the XAML code:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" Background="#FFCBCBCB">
<Grid>
<Label Content="Welcome to the house manager" Height="28" HorizontalAlignment="Left" Margin="20,12,0,0" Name="label1" VerticalAlignment="Top" />
<ListBox Height="253" HorizontalAlignment="Left" Margin="10,46,0,0" VerticalAlignment="Top" Width="481" x:Name="houseList">
<ListBox.ItemTemplate>
<DataTemplate DataType="house">
<Button Click="choose_house(HOUSE NUMBER HERE)" Background="#FFBEBEBE" BorderThickness="0" Focusable="True" Width="459" BorderBrush="White" Padding="0">
<StackPanel Orientation="Vertical" Width="400" VerticalAlignment="Stretch">
<TextBlock Margin="0,5,0,0" Text="{Binding street}" HorizontalAlignment="Left" />
<TextBlock Margin="0,5,0,0" Text="{Binding postCode}" HorizontalAlignment="Left" />
</StackPanel>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Here's the code which populates the list at the moment:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
List<house> houseAddresses = new List<house>();
// Create a new house
for (var i = 1; i <= 10; i++)
{
house newHouse = new house();
newHouse.street = i + " Scale Hall Lane";
newHouse.postCode = "PR4 3TL";
newHouse.houseNumber = i;
houseAddresses.Add(newHouse);
}
// Go through each house and add them to the list
foreach (house houses in houseAddresses)
{
houseList.Items.Add(houses);
}
}
private void choose_house(object sender, RoutedEventArgs e)
{
MessageBox.Show("Clicked");
}
}
}
Here's my house class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApplication1
{
class house
{
public string street { get; set; }
public string postCode { get; set; }
public int houseNumber { get; set; }
}
}
I've put Click="choose_house(HOUSE NUMBER HERE)" in the code on the button where the code would have the correct event handler.
Either cast your sender as a Button and get it's DataContext, or use a Command and bind the CommandParameter to the HouseNumber
private void choose_house(object sender, RoutedEventArgs e)
{
var ctrl = sender as Button;
var h = ctrl.DataContext as house; // Please capitalize your classes! :)
MessageBox.Show(h.houseNumber);
}
or
<Button Command="{Binding Path=DataContext.ChooseHouseCommand,
RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}"
CommandParameter="{Binding houseNumber}" ... />
What you can do on the click handler is:
private void choose_house(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button != null)
{
var yourObject = button.DataContext as house;
if (yourObject != null)
{
//do stuff with your button
}
}
}

Dynamically set TextBlock's text binding

I am attempting to write a multilingual application in Silverlight 4.0 and I at the point where I can start replacing my static text with dynamic text from a SampleData xaml file. Here is what I have:
My Database
<SampleData:something xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.MyDatabase" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<SampleData:something.mysystemCollection>
<SampleData:mysystem ID="1" English="Menu" German="Menü" French="Menu" Spanish="Menú" Swedish="Meny" Italian="Menu" Dutch="Menu" />
</SampleData:something.mysystemCollection>
</SampleData:something>
My UserControl
<UserControl
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" mc:Ignorable="d"
x:Class="Something.MyUC" d:DesignWidth="1000" d:DesignHeight="600">
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource MyDatabase}}">
<Grid Height="50" Margin="8,20,8,0" VerticalAlignment="Top" d:DataContext="{Binding mysystemCollection[1]}" x:Name="gTitle">
<TextBlock x:Name="Title" Text="{Binding English}" TextWrapping="Wrap" Foreground="#FF00A33D" TextAlignment="Center" FontSize="22"/>
</Grid>
</Grid>
</UserControl>
As you can see, I have 7 languages that I want to deal with. Right now this loads the English version of my text just fine. I have spent the better part of today trying to figure out how to change the binding in my code to swap this out when I needed (lets say when I change the language via drop down).
It sounds like you're looking for code like this:
Title.SetBinding(TextProperty, new Binding { Path = new PropertyPath(language) });
All it does is create a new Binding for the language you requested and use it to replace the old binding for the Title's Text property.
You are going about this the wrong way. Best practice for localization in Silverlight is to use resource files holding the translated keywords. Here is some more info about this:
http://msdn.microsoft.com/en-us/library/cc838238%28VS.95%29.aspx
EDIT:
Here is an example where I use a helper class to hold the translated strings. These translations could then be loaded from just about anywhere. Static resource files, xml, database or whatever. I made this in a hurry, so it is not very stable. And it only switches between english and swedish.
XAML:
<UserControl x:Class="SilverlightApplication13.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:local="clr-namespace:SilverlightApplication13"
mc:Ignorable="d"
d:DesignWidth="640"
d:DesignHeight="480">
<UserControl.Resources>
<local:TranslationHelper x:Key="TranslationHelper"></local:TranslationHelper>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<StackPanel>
<TextBlock Margin="10"
Text="{Binding Home, Source={StaticResource TranslationHelper}}"></TextBlock>
<TextBlock Margin="10"
Text="{Binding Contact, Source={StaticResource TranslationHelper}}"></TextBlock>
<TextBlock Margin="10"
Text="{Binding Links, Source={StaticResource TranslationHelper}}"></TextBlock>
<Button Content="English"
HorizontalAlignment="Left"
Click="BtnEnglish_Click"
Margin="10"></Button>
<Button Content="Swedish"
HorizontalAlignment="Left"
Click="BtnSwedish_Click"
Margin="10"></Button>
</StackPanel>
</Grid>
</UserControl>
Code-behind + TranslationHelper class:
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.Windows.Threading;
using System.ComponentModel;
namespace SilverlightApplication13
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
//Default
(this.Resources["TranslationHelper"] as TranslationHelper).SetLanguage("en-US");
}
private void BtnEnglish_Click(object sender, RoutedEventArgs e)
{
(this.Resources["TranslationHelper"] as TranslationHelper).SetLanguage("en-US");
}
private void BtnSwedish_Click(object sender, RoutedEventArgs e)
{
(this.Resources["TranslationHelper"] as TranslationHelper).SetLanguage("sv-SE");
}
}
public class TranslationHelper : INotifyPropertyChanged
{
private string _Contact;
/// <summary>
/// Contact Property
/// </summary>
public string Contact
{
get { return _Contact; }
set
{
_Contact = value;
OnPropertyChanged("Contact");
}
}
private string _Links;
/// <summary>
/// Links Property
/// </summary>
public string Links
{
get { return _Links; }
set
{
_Links = value;
OnPropertyChanged("Links");
}
}
private string _Home;
/// <summary>
/// Home Property
/// </summary>
public string Home
{
get { return _Home; }
set
{
_Home = value;
OnPropertyChanged("Home");
}
}
public TranslationHelper()
{
//Default
SetLanguage("en-US");
}
public void SetLanguage(string cultureName)
{
//Hard coded values, need to be loaded from db or elsewhere
switch (cultureName)
{
case "sv-SE":
Contact = "Kontakt";
Links = "Länkar";
Home = "Hem";
break;
case "en-US":
Contact = "Contact";
Links = "Links";
Home = "Home";
break;
default:
break;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

Categories