|
Tish - that's the sound of a light bulb switching on in my head. You certainly know your stuff! Many thanks.
Live for today. Plan for tomorrow. Party tonight!
|
|
|
|
|
No problem. Glad to help.
|
|
|
|
|
Pete O'Hanlon wrote: We use a custom localisable MarkupExtension to handle this
And here I was going to ask for an example of the binding syntax!
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
This is how I would do it (only if my requirements stated I had to use your language files - otherwise I would use Resource Files as Abhinav suggestes)
Your LanguageItem class:
class LanguageItem
{
public int ID { get; set; }
public string Word { get; set; }
}
A separate class which I will call LanguageViewModel:
class LanguageViewModel : INotifyPropertyChanged
{
enum LanguageChoice
{
UK,
US
}
private LanguageChoice selectedLanguage = LanguageChoice.UK;
private string languageText = "Switch to US English";
public string LanguageText
{
get
{
return languageText;
}
set
{
if (languageText != value)
{
languageText = value;
NotifyPropertyChanged("LanguageText");
}
}
}
ObservableCollection<LanguageItem> words = new ObservableCollection<LanguageItem>();
public ObservableCollection<LanguageItem> Words
{
get
{
return words;
}
set
{
if (words != value)
{
words = value;
NotifyPropertyChanged("Words");
}
}
}
public LanguageViewModel()
{
LoadLanguage(selectedLanguage);
}
private RelayCommand switchCommand;
public ICommand SwitchCommand
{
get
{
return switchCommand ?? (switchCommand = new RelayCommand(() => ObeySwitchCommand()));
}
}
private void ObeySwitchCommand()
{
selectedLanguage = selectedLanguage == LanguageChoice.UK ? LanguageChoice.US : LanguageChoice.UK;
LanguageText = selectedLanguage == LanguageChoice.UK ? "Switch to US English" : "Switch to UK English";
LoadLanguage(selectedLanguage);
}
void LoadLanguage(LanguageChoice languageToLoad)
{
string path;
if (languageToLoad == LanguageChoice.UK)
{
path = @"C:\Users\SwitchLanguage\UK.txt";
}
else
{
path = @"C:\Users\SwitchLanguage\US.txt";
}
StreamReader sr = new StreamReader(path);
ObservableCollection<LanguageItem> newWords = new ObservableCollection<LanguageItem>();
while (!sr.EndOfStream)
{
string[] parts = sr.ReadLine().Split(new char[] { ',' });
int index;
int.TryParse(parts[0], out index);
LanguageItem li = new LanguageItem() { ID = index, Word = parts[1] };
newWords.Add(li);
}
Words = newWords;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
My XAML File (Note no code in code behind):
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="{Binding Path=Words[0].Word}"/>
<Label Content="{Binding Path=Words[1].Word}" Grid.Column="1"/>
<Button Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Command="{Binding Path=SwitchCommand}" Content="{Binding Path=LanguageText}"
Width="100" Height="23"/>
Then I would override the OnStartUp method in the App.xaml.cs file like this:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
LanguageViewModel vm = new LanguageViewModel();
LanguageTest lt = new LanguageTest();
lt.DataContext = vm;
lt.ShowDialog();
}
And here is a bog standard RelayCommand class that is used for binding the Button's click command to the SwitchCommand on the ViewModel:
public class RelayCommand : ICommand
{
readonly Action execute;
readonly Func<bool> canExecute;
public RelayCommand(Action execute)
: this(execute, null)
{
}
public RelayCommand(Action execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute == null ? true : canExecute();
}
public event EventHandler CanExecuteChanged
{
add
{
if (canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
execute();
}
}
Live for today. Plan for tomorrow. Party tonight!
|
|
|
|
|
I would look at using a resource file for maintaining different languages.
See WPF Localization Using RESX Files[^] for an example.
Too much of heaven can bring you underground
Heaven can always turn around
Too much of heaven, our life is all hell bound
Heaven, the kill that makes no sound
modified on Thursday, September 1, 2011 7:23 AM
|
|
|
|
|
With WCF you can retrieve data, etc into silverlight UI using asyncronous calls...
Then is there any reason for backgrooundworker process to be used in silverlight?
Thanks
modified on Thursday, September 1, 2011 1:28 AM
|
|
|
|
|
Define required! I am yet to use a BGW process in SL.
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
Hello,
I updated the question.
Thanks
|
|
|
|
|
I'm sure you've asked this question before. Yes, you can use a background worker to do something in Silverlight, but in most cases it's not necessary because of the asynchronous nature of the client/server roundtrip. Saying that, you could be attempting to do something entirely on the client side, e.g. performing a long running calculation, and you should use some form of threading for this.
The answer you are looking for:
Roundtrip = asynchronous = no need for additional threading
Client side only = synchronous = you might want to use threading here.
|
|
|
|
|
In that case, on the client side, to use threading, I can use background worker? and not manually creating threads like thread t = new thread(...)?
Thanks
|
|
|
|
|
arkiboys wrote: on the client side, to use threading, I can use background worker
Yes.
|
|
|
|
|
I see.
So in silverlight, I do not need to learn how to do manual threading as long as I know backgroundworker process?
Thanks
|
|
|
|
|
That's correct. Learning manual threading is good knowledge to have, it will make you a better coder, but it isn't absolutely necessary.
|
|
|
|
|
I see.
This is now clear.
Thanks
|
|
|
|
|
To be able to develop in windows phone, as well as having the visual studio express 2010, should I also install the VS.NET 2010 Express for Windows Phone
Thanks
|
|
|
|
|
Hi!
Please help me to solve the problem:
I got DataSet, which contains 2 DataTables:
Categories (CategoryID, CategoryName)
Products(ProductID, CategoryID, Name)
These tables are linked using DataRelation by CategoryID key.
So, each product has category.
I got TreeView bound to DataSet.Tables["Categories"] - no problem here. Category names are displayed correctly as tree view items(having DisplayMemberPath=CategoryName)
And I got ListView.
So, I need to show Products in this ListView, that contains only the products of category selected in TreeView.
I don't know how to bind. Could you please help me?
Thanks!
|
|
|
|
|
Personally, I think you are going about things the wrong way. When it comes to WPF, as I told you before, using datasets and trying to bind to them is seriously a PITA. For a start, I would create 2 classes, one for Products and one for Categories. These can be really basic. The Category class should have a property that returns a List of Products. Then I would have another class (call it a viewmodel if you will) that would implement the INotifyPropertyChanged[^] Interface. This viewmodel need only have 2 properties, one which returns an ObservableCollection of Categories, call it Categories(to be original), and another that returns a specific Category (call it SelectedCategory). These properties should call your NotifyPropertyChanged event handler whenever they are changed. The viewmodel should also be able to populate the collection of categories, either from a database or some other source, or it could be populated in the constructor. Then in your Window/UserControl constructor, all you need to do is create an instance of the viewmodel class, and set the Window/UserControl's datacontext to the instance (this can be done in the constructor). In your XAML, you set up 2 ListViews. The first ListView should have it's ItemsSource property set to bind to the Categories property of the view model. The second ListView, the one with 2 columns for each property of the product, should have it's ItemsSource bound to the SelectedCategory's Products Property, with the first column bound to the product Id, and the second Column bound to the Name. And that's it, Simples.
Doing things this way, will make your life so easier. If you have any problems with implementing this, I will try and help if I can.
Live for today. Plan for tomorrow. Party tonight!
|
|
|
|
|
Wayne, firstly thank you so much for your efforts.
Seriously, I would never thought that using DataSets in WPF projects is not the best solution.
So, by now a got such code:
public DataSet GetDataSet()
{
string queryCatStr = @"SELECT * FROM [Category]";
string queryProdStr = @"SELECT * FROM [Products]";
DataSet ds = new DataSet();
SQLConnection dbConn = new SQLConnection("conn_str"))
dbConn.Open();
SQLCommand cmd = new SQLCommand(dbConn);
cmd.CommandText = queryCatStr;
SQLDataAdapter da = new SQLDataAdapter(cmd);
da.Fill(ds, "Categories");
cmd.CommandText = queryProdStr;
da.Fill(ds, "Products");
DataRelation drCat2Prod = new DataRelation("Cat2Prod", ds.Tables["categories"].Columns["CategoryID"], ds.Tables["Products"].Columns["CategoryID"]);
ds.Relations.Add(drCat2Prod);
return ds;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ds = GetDataSet();
this.DataContext = ds.Tables["Category"];
this.treeCategories.DisplayMemberPath = "CategoryName";
}
<TreeView x:Name="treeCategories" ItemsSource="{Binding}" />
...
<ListView x:Name="lstProducts" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Cat2Prod}" />
And now I just can't understand why this binding doesn't work as I expected - ListView contains products only for the first category and doesn't update contents when user selects another item in TreeView.
If I used ObservableCollection as a data source for the application, I would take care about initialization and synchronizing objects in the collection with data base. But ADO cand do it behind the scene as I think.
Even If I tried to init ObservableCollection of CategoryObjects with ProductsList contained in each one, I would make as many SQL queries to DB as many Categories I got in CategoriesTable.
Moreover, I should keep Data Base up-to-date, updating it manually. It seems to me this is not a good solution for me. But may be I'm wrong.
|
|
|
|
|
This is exactly the type of scenario that you should be looking into the Entity Framework for. Using a DataSet to bind to complex items such as a TreeView is an overly complicated task, doesn't play well with the binding notification mechanism, and actually has a poor runtime performance.
|
|
|
|
|
Thanks, Pete.
I haven't heard about it before.
I would be glad If you know some code examples similar for my task.
The main task for me is just make the code of classic ADO.NET work as expected. Possibke overhead is not a problem by now.
|
|
|
|
|
Hi,
How can i navigate to another page in a frame from code behind.
ex: I have a navigate frame, when i click on a link button from outside navigate frame i need to navigate it to another page by writing code behind.
i try ..
ContentFrame.UriMapper.MapUri(new Uri(@"/EmployeeList.xaml"));
ContentFrame.Source = new Uri("/EmployeeList.xaml");
in the click event. error i get is
Microsoft JScript runtime error: Unhandled Error in Silverlight Application Invalid URI: The format of the URI could not be determined. at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
at System.Uri..ctor(String uriString)
at HRMS.MainPage.Menu_MenuItemClicked(Object sender, EventArgs e)
at SilverlightMenu.Library.Menu.gridLevel2_MouseLeftButtonUp(Object sender, MouseButtonEventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
Thankyou,
YPKI
|
|
|
|
|
I have a static method that I call from any forms code behind. The default frame is the main navigation frame but I can pass in a frame if required
public static void NavigateTo(string sViewName)
{
Frame oFR = (Application.Current.RootVisual as FrameworkElement).FindName("MainContent") as Frame;
NavigateTo(oFR,sViewName);
}
public static void NavigateTo(Frame oFR, string sViewName)
{
if(!sViewName.StartsWith("/"))
{sViewName = string.Format("/{0}",sViewName);}
oFR.Navigate(new Uri(sViewName, UriKind.Relative));
}
And call it passing in the name of the view. The view is in the app.xaml of course. Do some research into Silverlight navigation projects.
gUI.NavigateTo(sURL);
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
Hi!
Please help me to solve the problem:
I got DataSet, which contains 2 DataTables:
Categories (CategoryID, CategoryName)
Products(ProductID, CategoryID, Name)
These tables are linked using DataRelation by CategoryID key.
So, each product has category.
I got TreeView bound to DataSet.Tables["Categories"] - no problem here. Category names are displayed correctly as tree view items(having DisplayMemberPath=CategoryName)
And I got DataGridView (imported from Windows Forms using WindowsFormsHost control).
So, I need to show Products table in this DataGridView, that contains only the products of category selected in TreeView.
I don't know how to bind DataGridView in this case. Could you please help me?
Thanks!
|
|
|
|
|
Is there any particular reason that you are using the WinForms DataGridView? WPF has got a DataGrid, which is fully compatible with data binding. You could have a property(call it SelectedCategory) in your viewmodel/codebehind which holds the selected category(bound to the SelectedItem property of the TreeView), and bind the DataGrid to SelectedCategory.Products . You then create a DataTemplate for the DataGrid which will show the particular properties of each product such as name, retail price etc.
Live for today. Plan for tomorrow. Party tonight!
|
|
|
|
|
Is there any particular reason that you are using the WinForms DataGridView? WPF has got a DataGrid, which is fully compatible with data binding.
See, I have strong restriction for my project to run under .NET version 3.5
It has no DataGrid control included. That's why I have to use DataGridView.
|
|
|
|
|