I have a command which sends text when the send button is clicked. The binding is set to two way and the updatesource trigger to propertychanged. but the value of the textbox doesnt change to string.empty which is included in the sendCommand, even though the command was able to take the updated textbox value for a new message.
public class BuddyChatViewModel : BaseViewModel
{
private string chat;
public string Chat
{
get { return chat; }
set
{
chat = value;
RaisePropertyChanged();
}
}
public RelayCommand sendChatCommand { get; private set; }
string username = "";
string buddy = "";
UriStrings url = new UriStrings();
BuddiesHomeModel buddiesList = new BuddiesHomeModel();
HttpService http = new HttpService();
StorageService store = new StorageService();
string response = "";
BuddyChatModel buddyChat = new BuddyChatModel();
List<BuddyChat2Datum> buddychatList = new List<BuddyChat2Datum>();
BuddyChat2Datum tempDatum = new BuddyChat2Datum();
private ObservableCollection<BuddyChat2Datum> buddyChatOC = new ObservableCollection<BuddyChat2Datum>();
public ObservableCollection<BuddyChat2Datum> BuddyChatOC
{
get { return buddyChatOC; }
set
{
buddyChatOC = value;
RaisePropertyChanged();
}
}
private async void sendChatExecute()
{
int i = 0;
string s = url.buddychatText(username, buddy, chat);
chat = "";
response = await http.GetAsync(s);
buddyChat = JsonConvert.DeserializeObject<BuddyChatModel>(response);
buddychatList.Clear();
for (i = 0; i < buddyChat.data.Count; i++)
{
tempDatum.conversation = buddyChat.data[i].conversation;
tempDatum.datetime = buddyChat.data[i].datetime;
tempDatum.from = buddyChat.data[i].from;
tempDatum.to = buddyChat.data[i].to;
if (tempDatum.from == username)
tempDatum.isLeft = false;
else
tempDatum.isLeft = true;
buddychatList.Add(tempDatum);
tempDatum = new BuddyChat2Datum();
}
BuddyChatOC.Clear();
for (i = 0; i < buddychatList.Count; i++)
{
BuddyChatOC.Add(buddychatList[i]);
}
Navigate<BuddyChatViewModel>(buddychatList);
}
#region State Management
public override void LoadState(object navParameter, Dictionary<string, object> state)
{
sendChatCommand = new RelayCommand(sendChatExecute);
int i = 0;
base.LoadState(navParameter, state);
BuddyChatOC.Clear();
// load test items again; in production this would retrieve the live item by id or get it from a local data cache
List<BuddyChat2Datum> buddychatList = (List<BuddyChat2Datum>)navParameter;
//var mes = new MessageDialog(buddychatList.Count.ToString());
//await mes.ShowAsync();
for(i=0;i<buddychatList.Count;i++)
{
BuddyChatOC.Add(buddychatList[i]);
}
username = buddychatList[i-1].username;
buddy = buddychatList[i-1].buddy;
}
public override void SaveState(Dictionary<string, object> state)
{
base.SaveState(state);
}
#endregion
}
}
xaml code:
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ListView x:Name="chatList" HorizontalAlignment="Stretch" ItemsSource="{Binding BuddyChatOC}" ItemTemplateSelector="{StaticResource ChatSelector}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
<RelativePanel Grid.Row="1" Margin="5,10,5,10">
<TextBox x:Name="sendtext" Margin="0,0,2,0" Text="{Binding Chat, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" RelativePanel.AlignLeftWithPanel="True" RelativePanel.LeftOf="sendtextbutton"/>
<Button x:Name="sendtextbutton" Content="Send" Command="{Binding sendChatCommand}" RelativePanel.AlignRightWithPanel="True" >
</Button>
</RelativePanel>
</Grid>
Implement INotifyPropertyChanged in BuddyChatViewModel.
public class BuddyChatViewModel : INotifyPropertyChanged, BaseViewModel
{
private string chat;
public string Chat
{
get { return chat; }
set
{
chat = value;
NotifyPropertyChanged("Chat");
}
}
//INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
If you're using MVVMLight (and from how this question is tagged I assume you do), you need to specify changed property name in RaisePropertyChanged call.
That should work in your case:
public string Chat
{
get { return chat; }
set
{
chat = value;
RaisePropertyChanged(() => Chat);
}
}
Related
I want to change my single language project into multiple language, so I use ResourceDictionary to do it like this:
XAML
<Button Content="{DynamicResource LanguageSetting}" Click="btn_LanguageSetting_Click"/>
Code Behind
public static string windowCurrentLanguageFile = "Language/en.xaml";
private void btn_LanguageSetting_Click(object sender, RoutedEventArgs e)
{
windowCurrentLanguageFile = windowCurrentLanguageFile == "Language/en.xaml"
? "Language/ch.xaml"
: "Language/en.xaml";
var rd = new ResourceDictionary() { Source = new Uri(windowCurrentLanguageFile, UriKind.RelativeOrAbsolute) };
if (this.Resources.MergedDictionaries.Count == 0)
this.Resources.MergedDictionaries.Add(rd);
else
this.Resources.MergedDictionaries[0] = rd;
}
This works fine for me. But I have an ItemsControl
<ItemsControl ItemsSource="{Binding ItemOperate}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type viewmodel:SelectableViewModel}">
<Border x:Name="Border" Padding="0,8,0,8" BorderThickness="0 0 0 1" BorderBrush="{DynamicResource MaterialDesignDivider}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Checkerz" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ToggleButton VerticalAlignment="Center" IsChecked="{Binding IsSelected}"
Style="{StaticResource MaterialDesignActionLightToggleButton}"
Content="{Binding Code}" />
<StackPanel Margin="8 0 0 0" Grid.Column="7">
<TextBlock FontWeight="Bold" Text="{Binding Name}" />
<TextBlock Text="{Binding Description}" />
</StackPanel>
</Grid>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource MaterialDesignSelection}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Which Binding to the ViewModel like this:
public class SelectableViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected == value) return;
_isSelected = value;
OnPropertyChanged();
}
}
private char _code;
public char Code
{
get { return _code; }
set
{
if (_code == value) return;
_code = value;
OnPropertyChanged();
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value) return;
_name = value;
OnPropertyChanged();
}
}
private string _description;
public string Description
{
get { return _description; }
set
{
if (_description == value) return;
_description = value;
OnPropertyChanged();
}
}
}
And
public MainViewModel()
{
_itemOperate = CreateData();
}
private static ObservableCollection<SelectableViewModel> CreateData()
{
return new ObservableCollection<SelectableViewModel>
{
new SelectableViewModel
{
Code = 'E',
Name = "Erase",
Description = "Erase The MCU Chip By Page"
},
new SelectableViewModel
{
Code = 'D',
Name = "Detect",
Description = "Detect The MCU Flash",
},
new SelectableViewModel
{
Code = 'P',
Name = "Programming",
Description = "Programming The MCU Chip By Hex File",
},
new SelectableViewModel
{
Code = 'V',
Name = "Verify",
Description = "Verify The Downing Code",
},
new SelectableViewModel
{
Code ='L',
Name = "Lock",
Description = "Lock The Code To Protect The MCU",
}
};
}
So how should I change this into multiple language?
First of all, I would recommend you to change your localization engine.
There are a lot of different ways.
There is the simplest variant:
https://www.codeproject.com/Articles/299436/WPF-Localization-for-Dummies
Also, this tool will help you to manage your resources files:
https://marketplace.visualstudio.com/items?itemName=TomEnglert.ResXManager
And the answer to your question:
If you want to localize your model, you should create it using resources dictionary but not hard coded strings.
It's quite easy if you implement your localization engine like in mentioned
article.
{
return new ObservableCollection<SelectableViewModel>
{
new SelectableViewModel
{
Code = 'E',
Name = YourResourcesProject.Resources.Erase,
Description = YourResourcesProject.Resources.EraseTheMCUChipByPage
},
new SelectableViewModel
{
Code = 'D',
Name = YourResourcesProject.Resources.Detect,
Description = YourResourcesProject.Resources.DetectTheMCUFlash
},
new SelectableViewModel
{
Code = 'P',
Name = YourResourcesProject.Resources.Programming,
Description = YourResourcesProject.Resources.ProgrammingTheMCUChipByHexFile
},
new SelectableViewModel
{
Code = 'V',
Name = YourResourcesProject.Resources.Verify,
Description = YourResourcesProject.Resources.VerifyTheDowningCode
},
new SelectableViewModel
{
Code ='L',
Name = YourResourcesProject.Resources.Lock,
Description = YourResourcesProject.Resources.LockTheCodeToProtectTheMCU
}
};
}
Don't change anything...make your collection of SelectableViewModel into a XML and change the CreateData to load it into the localized version - you can either have a file for each language or mix all together
20 lines of code....as you want - cannot more explicit than that :-(
public class Selectable(View)Model
{
[XmlAttribute]
public string Code { get; set; }
[XmlAttribute]
public string Name { get; set; }
[XmlAttribute]
public string Description { get; set; }
}
///you can deserialize your view model directly
private ObservableCollection<SelectableViewModel> CreateData()
{
return new ObservableCollection<SelectableViewModel>( Deserialize( file_name_code_lang.xml, SelectableViewModel) );
}
// or going through a model class
private ObservableCollection<SelectableViewModel> CreateData()
{
return new ObservableCollection<SelectableViewModel>( Deserialize( file_name_code_lang.xml, SelectableModel ).Foreach(p=> new SelectableViewModel(p) );
}
static public object Deserialize(string filePath, Type objType)
{
object objToDeserialize = null;
XmlTextReader xmlReader = null;
XmlSerializer xmls = null;
try
{
xmlReader = new XmlTextReader(filePath);
xmls = new XmlSerializer(objType);
objToDeserialize = xmls.Deserialize(xmlReader);
}
catch (Exception err)
{
BusinessLogger.Manage(err);
return null;
}
finally
{
xmls = null;
xmlReader.Close();
}
return objToDeserialize;
}
I am using Listview having datasource as observablecollection<empclass>
My overall class structure is like
Class empclass
{
command = new RelayCommand(myfunction, true);
private int _abc;
public int abc
{
get { return _abc;}
set { _abc = value;
onpropertychanged("abc")
}
private int _pqr;
public int pqr
{
get { return _pqr;}
set { _pqr = value;
onpropertychanged("pqr")
}
public void myfunction()
{
messagebox.show((abc+pqr).Tostring());
}
}
i have a separate button, where on click i want to invoke command of selected item to show addition of abc and pqr on respected values present in that object.
It would be great If you could help me with small code example.
Thanks
Ashpak
I'm assuming you have a ListView named lv:
<ListView Name="lv" ... </ListView>
Then you can bind to the SelectedItem of that ListView and use the item's command property.
<Button Command="{Binding ElementName=lv, Path=SelectedItem.command}">Button Text</Button>
Note that for this to work you have to have a public property command, e.g.:
Class empclass
{
public RelayCommand command {get;set;}
...
}
Try this:
1. XAML code:
<Window x:Class="SoButtonBindingHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:soButtonBindingHelpAttempt="clr-namespace:SoButtonBindingHelpAttempt"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<soButtonBindingHelpAttempt:MainViewModel/>
</Window.DataContext>
<Grid>
<ListBox ItemsSource="{Binding ObservableCollection}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type soButtonBindingHelpAttempt:Empclass}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="120"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding abc, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></TextBlock>
<TextBlock Grid.Column="1" Text="{Binding pqr, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></TextBlock>
<Button Grid.Column="2" Command="{Binding Command}" Content="Press me!"></Button>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid></Window>
2. ViewModel code Model code:
public class MainViewModel:BaseObservableObject
{
public MainViewModel()
{
ObservableCollection = new ObservableCollection<Empclass>(new List<Empclass>
{
new Empclass{abc=2, pqr = 3},
new Empclass{abc=5, pqr = 7},
new Empclass{abc=11, pqr = 13},
new Empclass{abc=17, pqr = 19}
});
}
public ObservableCollection<Empclass> ObservableCollection { get; set; }
}
public class Empclass : BaseObservableObject
{
private ICommand _command;
private int _abc;
private int _pqr;
public ICommand Command
{
get { return _command ?? (_command = new RelayCommand(myfunction)); }
}
public int abc
{
get { return _abc; }
set
{
_abc = value;
OnPropertyChanged("abc");
}
}
public int pqr
{
get { return _pqr; }
set
{
_pqr = value;
OnPropertyChanged("pqr");
}
}
private void myfunction()
{
//add you command logic here
var temp = pqr;
pqr = abc;
abc = temp;
}
}
3. MVVM parts implementation:
public class BaseObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
}
public class RelayCommand<T> : ICommand
{
readonly Action<T> _execute;
readonly Func<T, bool> _canExecute;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public void RefreshCommand()
{
var cec = CanExecuteChanged;
if (cec != null)
cec(this, EventArgs.Empty);
}
public bool CanExecute(object parameter)
{
if (_canExecute == null) return true;
return _canExecute((T)parameter);
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
}
public class RelayCommand : RelayCommand<object>
{
public RelayCommand(Action execute, Func<bool> canExecute = null)
: base(_ => execute(),
_ => canExecute == null || canExecute())
{
}
}
4. Look like this:
Regards
I started a new small project, using ModernUI for WPF.
I've to display a Dialog with only two textbox and two button(ok/cancel).
The two textbox have some validation(one is a name that should be >0, the other should be an email).
Currently I've the following:
var userEditionForm = new UserEditionForm(oneUserConfigurationViewModel);
var dlg = new ModernDialog
{
Title = "User edition",
Content = userEditionForm,
Width = 300
};
dlg.Buttons = new[] {dlg.OkButton, dlg.CancelButton};
dlg.ShowDialog();
return dlg.DialogResult.HasValue && dlg.DialogResult.Value;
The content user control is:
<UserControl x:Class="Test.UserControls.UserEditionForm"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Vertical">
<StackPanel.Resources>
<Style TargetType="StackPanel">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="Margin" Value="0,0,0,4" />
</Style>
<Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
<Setter Property="Width" Value="100" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</StackPanel.Resources>
<StackPanel>
<Label Content="Name" Target="{Binding ElementName=TextFirstName}" />
<TextBox x:Name="TextFirstName" Width="150"
Text="{Binding User.Name, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, ValidatesOnDataErrors=True}" />
</StackPanel>
<StackPanel>
<Label Content="Email" Target="{Binding ElementName=TextEmail}" />
<TextBox x:Name="TextEmail" Width="150"
Text="{Binding User.Email, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, ValidatesOnDataErrors=True}" />
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
The validation is made, but I would like to prevent the user to click "OK" until the validation is good. Is it possible? If yes, how?
This was actually pretty tricky but it worked for me:
ViewModel
public class UserInfo : INotifyPropertyChanged, IDataErrorInfo
{
private static Regex emailRegex = new Regex(#"^\w+(?:\.\w+)*?#[a-zA-Z_]+?\.[a-zA-Z]{2,3}$");
private string firstname;
private string email;
public string FirstName
{
get { return firstname; }
set { firstname = value; OnPropertyChanged(); }
}
public string EMail
{
get { return email; }
set { email = value; OnPropertyChanged(); }
}
public string Error
{
get { return null; }
}
public string this[string columnName]
{
get
{
switch (columnName)
{
case "FirstName":
return string.IsNullOrWhiteSpace(FirstName) ? "Firstname is required!" : null;
case "EMail":
return EMail == null || !emailRegex.IsMatch(EMail) ? "The Email Address is not valid!" : null;
default:
return null;
}
}
}
public LoginCommand LoginCommand { get; private set; }
public UserInfo()
{
LoginCommand = new LoginCommand(this);
}
private void OnPropertyChanged([CallerMemberName]string propertyName = "")
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
Command (No clue what you want to call it...)
public class LoginCommand : ICommand
{
private UserInfo info;
private ICommand attachedCommand;
public bool CanExecute(object parameter)
{
return parameter != null && info["FirstName"] == null && info["EMail"] == null;
}
public event EventHandler CanExecuteChanged = delegate { };
public void Execute(object parameter)
{
Debug.WriteLine("This Works!");
//Add execution logic here
if (attachedCommand != null)
{
attachedCommand.Execute(parameter); //should close the window
}
}
private void Info_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
CanExecuteChanged(this, new EventArgs());
}
public LoginCommand(UserInfo info)
{
this.info = info;
info.PropertyChanged += Info_PropertyChanged;
}
public void AttachCommand(ICommand command) //attach the original command here
{
attachedCommand = command;
}
}
Usage with ModernUI
UserInfo info = new UserInfo();
UserInfoForm form = new UserInfoForm(info);
ModernDialog dialog = new ModernDialog
{
Title = "User edition",
Content = form,
Width = 300
};
Button btnOk = dialog.OkButton;
ICommand originalCommand = btnOk.Command; //the original command should close the window so i keep it
btnOk.Command = info.LoginCommand;
info.LoginCommand.AttachCommand(originalCommand); //and attach it to my command
dialog.Buttons = new[] { btnOk, dialog.CancelButton };
dialog.ShowDialog();
I've been told that this code by Christian Moser (http://wpftutorial.net/ValidationErrorByCode.html) is working for validation when only the source is changing, but I don't know where to put it. I have tried to put in a
'PreviewLostKeyboardFocus' class, but it's not working. I already have a validation class that is only working when there is direct user input in the textbox, but I also want validation to occur from a calculation from other textboxes.
I also have properties in ViewModel : INotifyPropertyChanged, but I'm new to MVVM. So I'm not familiar with IDataErrorInfo and would rather use INotifyPropertyChanged if possible.
ValidationError validationError =
new ValidationError(regexValidationRule,
textBox.GetBindingExpression(TextBox.TextProperty));
validationError.ErrorContent = "This is not a valid e-mail address";
Validation.MarkInvalid(
textBox.GetBindingExpression(TextBox.TextProperty),
validationError);
My property
private int _FIMSamlet_score;
public int FIMSamlet_score
{
get { return this._FIMSamlet_score; }
set
{
if (Int32.Parse(value.ToString()) < 18 || Int32.Parse(value.ToString()) > 126)
{ throw new ArgumentException("The value must be between 18 and 126"); }
this._FIMSamlet_score = value;
this.OnPropertyChanged("FIMSamlet_score");
}
}
IDataErrorInfo is part and parcel of a validation scheme using INotifyPropertyChanged. When you set ValidateOnDataErrors=true on a Binding, during the get of an INotifyPropertyChanged enabled property, the value is validated and the value is set.
The method you have linked to would require you to put extensive business logic in the code-behind which is against the MVVM principle of segregation of responsibilities (dumb View, smart ViewModel).
I strongly recommend you learn about IDataErrorInfo and more importantly about the ValidationAttributes defined by System.ComponentModel.DataAnnotations as they are actually the easiest way to perform validation in a pure MVVM environment.
Have a look at this code sample from Microsoft which shows you how to integrate those annotations with IDataErrorInfo into a base ViewModel class which you could inherit from and use as a universal base validating ViewModel class: Validation in MVVM using Data Annotations
ViewModel -> VMStudent.cs
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using WpfDesktopCrud.Model;
namespace WpfDesktopCrud.ViewModel
{
class VMStudent : ViewModelBase, IDataErrorInfo
{
public VMStudent()
{
try
{
Students = new ObservableCollection<Student>();
Students.Add(new Student { id = 1, name = "Dhru", mobno = "0000000000", address = "Shahibaug", email = "dhrusoni84#gmail.com" });
Students.Add(new Student { id = 2, name = "Soni", mobno = "9033259059", address = "Vastrapur", email = "dhru_soni#yahoo.com" });
SaveCommand = new RelayCommand(Save);
NewCommand = new RelayCommand(New);
DeleteCommand = new RelayCommand(Delete);
PropertyChanged += VMStudent_PropertyChanged;
}
catch (Exception ex)
{
throw;
}
}
void VMStudent_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "Selected":
if (Selected != null)
{
ID = Selected.id;
Name = Selected.name;
MobileNo = Selected.mobno;
Address = Selected.address;
Email = Selected.email;
}
break;
}
}
#region Properties
private ObservableCollection<Student> _Students;
public ObservableCollection<Student> Students
{
get { return _Students; }
set
{
_Students = value;
RaisePropertyChanged("Students");
}
}
private Student _Selected;
public Student Selected
{
get { return _Selected; }
set
{
_Selected = value;
RaisePropertyChanged("Selected");
}
}
private int _ID;
public int ID
{
get { return _ID; }
set
{
_ID = value;
RaisePropertyChanged("ID");
}
}
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
RaisePropertyChanged("Name");
}
}
private string _MobileNo;
public string MobileNo
{
get { return _MobileNo; }
set
{
_MobileNo = value;
RaisePropertyChanged("MobileNo");
}
}
private string _Address;
public string Address
{
get { return _Address; }
set
{
_Address = value;
RaisePropertyChanged("Address");
}
}
private string _Email;
public string Email
{
get { return _Email; }
set
{
_Email = value;
RaisePropertyChanged("Email");
}
}
#endregion
#region Commands
public RelayCommand SaveCommand { get; set; }
public RelayCommand NewCommand { get; set; }
public RelayCommand DeleteCommand { get; set; }
#endregion
#region Methods
public void Save()
{
if (Selected != null)
{
if (Selected.id != 0)
{
Selected.name = this.Name;
Selected.mobno = this.MobileNo;
Selected.address = this.Address;
Selected.email = this.Email;
MessageBox.Show("Record Updated.", "WPF MVVM", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
this.ID = 0;
this.Name = string.Empty;
this.Address = string.Empty;
this.MobileNo = string.Empty;
this.Email = string.Empty;
}
}
else
{
try
{
Students.Add(new Student { id = Students.Count + 1, name = this.Name, mobno = this.MobileNo, address = this.Address, email = this.Email });
MessageBox.Show("Record Saved.", "WPF MVVM", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
this.ID = 0;
this.Name = string.Empty;
this.MobileNo = string.Empty;
this.Address = string.Empty;
this.Email = string.Empty;
}
catch (Exception ex)
{
throw;
}
}
}
public void New()
{
if (Selected != null)
{
this.ID = 0;
this.Name = string.Empty;
this.MobileNo = string.Empty;
this.Address = string.Empty;
this.Email = string.Empty;
Selected.id = 0;
}
Selected = null;
}
public void Delete()
{
try
{
Students.Remove(Selected);
this.Name = string.Empty;
this.MobileNo = string.Empty;
this.Address = string.Empty;
this.Email = string.Empty;
MessageBox.Show("Record Deleted.", "WPF MVVM", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
}
catch (Exception ex)
{
throw;
}
}
#endregion
public string Error
{
get { throw new NotImplementedException(); }
}
public string this[string columnName]
{
get
{
string result = null;
if (columnName == "Name")
{
if (string.IsNullOrEmpty(Name))
{
result = "Name Cannot Be Empty";
return result;
}
string st = #"!|#|#|\$|%|\?|\>|\<|\*";
if (Regex.IsMatch(Name, st))
{
result = "special chatachter are not allowed";
return result;
}
}
if (columnName == "MobileNo")
{
if (string.IsNullOrEmpty(MobileNo))
{
result = "Mobile Can not be empty";
return result;
}
if (MobileNo.Length > 10 || MobileNo.Length < 10)
{
result = "number should be 10 charachters";
return result;
}
string s1 = #"^[0-9]*$";
if (!Regex.IsMatch(MobileNo, s1))
{
result = "Mobile number contain numeric value ";
return result;
}
else
{
return null;
}
}
if (columnName == "Address")
{
if (string.IsNullOrEmpty(Address))
{
result = "fill your address";
return result;
}
}
if (columnName == "Email")
{
string s1 = #"^[a-zA-Z][\w\.-]{2,28}[a-zA-Z0-9]#[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$";
if (string.IsNullOrEmpty(Email))
{
result = "Email can not be empty";
return result;
}
if (Regex.IsMatch(Email, s1)) //|| Regex.IsMatch(Email, s2))
{
return null;
}
else
{
result = "Not valid email(format: dhru#gmail.com)";
return result;
}
}
return null;
}
}
}
}
View - > Student.xaml
<Window x:Class="WpfDesktopCrud.View.Students"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:WpfDesktopCrud.ViewModel"
Title="Students" Height="400" Width="500">
<Window.DataContext>
<VM:VMStudent/>
</Window.DataContext>
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="dTemplate">
<StackPanel Orientation="Horizontal">
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right" Text="{Binding AdornedElement.(Validation.Errors).[0].ErrorContent, ElementName=ErrorAdorner}" Background="#FA5858" Foreground="White" FontWeight="Light" VerticalAlignment="Center"/>
<AdornedElementPlaceholder VerticalAlignment="Top" x:Name="ErrorAdorner">
<Border BorderBrush="Red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</StackPanel>
</ControlTemplate>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Students}" SelectedItem="{Binding Selected}" DisplayMemberPath="name" SelectedValuePath="id" Margin="0,0,0,26">
</ListBox>
<Grid Grid.Row="1" HorizontalAlignment="Center">
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="5 2 5 0"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="5 5 5 5"/>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name"/>
<TextBlock Text="Mobile No" Grid.Row="1"/>
<TextBlock Text="Address" Grid.Row="2"/>
<TextBlock Text="Email" Grid.Row="3"/>
<TextBox x:Name="txtName" Text="{Binding Name,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,ValidatesOnDataErrors=True}" Validation.ErrorTemplate="{StaticResource dTemplate}"
Grid.Column="1"/>
<TextBox x:Name="txtNo" Text="{Binding MobileNo,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,ValidatesOnDataErrors=True}" Validation.ErrorTemplate="{StaticResource dTemplate}"
Grid.Row="1" Grid.Column="1"/>
<TextBox x:Name="txtAdd" Text ="{Binding Address,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,ValidatesOnDataErrors=True}" Validation.ErrorTemplate="{StaticResource dTemplate}"
Grid.Row="2" Grid.Column="1" TextWrapping="WrapWithOverflow" AcceptsReturn="True" ScrollViewer.CanContentScroll="True" VerticalScrollBarVisibility="Auto" Height="90"/>
<TextBox x:Name="txtEmail" Text ="{Binding Email,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,ValidatesOnDataErrors=True}" Validation.ErrorTemplate="{StaticResource dTemplate}"
Grid.Row="3" Grid.Column="1"/>
</Grid>
<WrapPanel Grid.Row="3" HorizontalAlignment="Center" >
<Button Command="{Binding NewCommand}" Content="New" Width="75" Height="31">
<Button.Style>
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="MoveFocusOnClick"/>
</Style>
</Button.Style>
</Button>
<Button Command="{Binding SaveCommand}" Content="Save" Width="75" Height="31">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding ="{Binding Path=(Validation.HasError),ElementName=txtName}" Value="false"/>
<Condition Binding ="{Binding Path=(Validation.HasError),ElementName=txtNo}" Value="false"/>
<Condition Binding ="{Binding Path=(Validation.HasError),ElementName=txtAdd}" Value="false"/>
<Condition Binding ="{Binding Path=(Validation.HasError),ElementName=txtEmail}" Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button Command="{Binding DeleteCommand}" Content="Delete" Width="75" Height="31"/>
</WrapPanel>
</Grid>
</Window>
Model -> Student.cs
using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfDesktopCrud.Model
{
class Student : ViewModelBase
{
private int _id;
public int id
{
get { return _id; }
set
{
_id = value;
RaisePropertyChanged("id");
}
}
private string _name;
public string name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged("name");
}
}
private string _mobno;
public string mobno
{
get { return _mobno; }
set
{
_mobno = value;
RaisePropertyChanged("mobno");
}
}
private string _address;
public string address
{
get { return _address; }
set
{
_address = value;
RaisePropertyChanged("address");
}
}
private string _email;
public string email
{
get { return _email; }
set
{
_email = value;
RaisePropertyChanged("email");
}
}
private DateTime _timer;
public DateTime Timer
{
get { return _timer; }
set
{
_timer = value;
RaisePropertyChanged("timer");
}
}
}
}
I have problem that i don't know how to bind data in windows phone 8 and the scenario is :-
I request data from server and after I got response I display them in grid and list boxes (like a table).
Until here every thing is okay after I finish the display function there is a new function that retrieves the update to last request.
Here is my problem:
When I receive the new data I don't know how bind this new data to same old table.
For example: the first request is return the gold price 1500$---> I display in table--->then new request--> the update function return the new price of gold is 1502$.
How to update desired row that have gold price textblock with the new price while the application running.
This the first request:-
public ObservableCollection<Data> DataReceivedCollection { get; set; }
private void FireRequest2()
{
var request = HttpWebRequest.Create(new Uri("http://74.54.46.178/vertexweb10/webservice.svc/getallsymbols?AccountID=1122336675")) as HttpWebRequest;
request.Method = "GET";
request.CookieContainer = cookieJar;
request.BeginGetResponse(ar =>
{
HttpWebRequest req2 = (HttpWebRequest)ar.AsyncState;
using (var response = (HttpWebResponse)req2.EndGetResponse(ar))
{
using (Stream stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
var outerRoot1 = JsonConvert.DeserializeObject<OuterRootObject1>(reader.ReadToEnd());
JArray jsonArray = JArray.Parse(outerRoot1.d);
JToken jsonArray_Item = jsonArray.First;
while (jsonArray_Item != null)
{
string Name = jsonArray_Item.Value<string>("Name");
string Bid = jsonArray_Item.Value<string>("Bid");
string Ask = jsonArray_Item.Value<string>("Ask");
string ID = jsonArray_Item.Value<string>("ID");
DataReceivedCollection = new ObservableCollection<Data>();
DispatchInvoke(() =>
{
myList.ItemsSource = DataReceivedCollection;
// and to add data you do it like this:
DataReceivedCollection.Add(new Data() { symid = ID, textFirst = Name, textSecond = Bid, textThird = Ask });
}
);
//Be careful, you take the next from the current item, not from the JArray object.
jsonArray_Item = jsonArray_Item.Next;
}
}
}
}
}, request);
}
And here is my XAML that i want to dsiaply the requested data from firerequest2();
<Grid Background="#FFC9DC97" x:Name="ContentPanel" Grid.Row="1" Margin="12,140,12,0">
<ListBox Name="myList" Background="#FFC9DC97">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="ide" Text="{Binding symid}" Grid.Column="3" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding textFirst}" Grid.Column="0" HorizontalAlignment="Left" Foreground="#FF1C69D8"/>
<TextBlock Text="{Binding textSecond}" Grid.Column="1" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding textThird}" Grid.Column="2" HorizontalAlignment="Right"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
To here every thing is working fine i don't know to update the grid with the new data from the next function
public class Data : INotifyPropertyChanged
{
private string _textFirst;
public string textFirst
{
[DebuggerStepThrough]
get { return _textFirst; }
[DebuggerStepThrough]
set
{
if (value != _textFirst)
{
_textFirst = value;
OnPropertyChanged("textFirst");
}
}
}
private string _textSecond;
public string textSecond
{
[DebuggerStepThrough]
get { return _textSecond; }
[DebuggerStepThrough]
set
{
if (value != _textSecond)
{
_textSecond = value;
OnPropertyChanged("textSecond");
}
}
}
private string _textThird;
public string textThird
{
[DebuggerStepThrough]
get { return _textThird; }
[DebuggerStepThrough]
set
{
if (value != _textThird)
{
_textThird = value;
OnPropertyChanged("textThird");
}
}
}
private string _symid;
public string symid
{
[DebuggerStepThrough]
get { return _symid; }
[DebuggerStepThrough]
set
{
if (value != _symid)
{
_symid = value;
OnPropertyChanged("symid");
}
}
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
Your dataReceived collection needs to be declared like this because it is the subject of a binding...
public ObservableCollection<Data> DataReceivedCollection { get; set; }
And in the initialization code, it needs to be instantiated like this...
DataReceivedCollection = new ObservableCollection<Data>();
And your data class should be declared something like this (not all properties declared)
public class Data : INotifyPropertyChanged
{
private string _textFirst;
public string TextFirst
{
[DebuggerStepThrough]
get { return _textFirst; }
[DebuggerStepThrough]
set
{
if (value != _textFirst)
{
_textFirst = value;
OnPropertyChanged("TextFirst");
}
}
}
private string _textSecond;
public string TextSecond
{
[DebuggerStepThrough]
get { return _textSecond; }
[DebuggerStepThrough]
set
{
if (value != _textSecond)
{
_textSecond = value;
OnPropertyChanged("TextSecond");
}
}
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
Doing these things will ensure that the binding engine gets the information it needs to populate your List Box.
This is only a start that will give you some better results. As mentioned in the commentary, your next port of call is to take up a study of INotifyPropertyChanged.