Here is the Main.xaml.cs page details,
private void Btn_Ok_Click(object sender, RoutedEventArgs e)
{
String homeTeamId = TeamIdtxt.Text;
this.DataContext = new MainViewModel();
}
and my class1.cs will be like as follows,
public MainViewModel()
{
Players = new ObservableCollection<PlayersViewModel>();
string url = "http://192.168.1.19/projects/t20lite/index.php/api/api/get_playersbyteam";
var task = new HttpGetTask<PlayerList>(url, this.OnPostExecute);
task.OnPreExecute = this.OnPreExecute;
task.OnError = this.OnError;
task.Execute();
}
how i have to pass the hometeam id value to mainviewmodel, In there i have to append it with url.
As sugested in comments you can share data by several options:
Option 1: Using Data Binding
http://msdn.microsoft.com/en-us/library/ms752347(v=vs.110).aspx
Option 2: Define property in your ViewModel class to pass it. Add some method to handle get player request in your view-model. For example:
public class MainViewModel
{
public string TeamID { get; set; }
public MainViewModel()
{
Players = new ObservableCollection<PlayersViewModel>();
}
public void GetPlayer()
{
string url = "http://192.168.1.19/projects/t20lite/index.php/api/api/get_playersbyteam;"
// Do something with url and tour TeamID
var task = new HttpGetTask<PlayerList>(url, this.OnPostExecute);
task.OnPreExecute = this.OnPreExecute;
task.OnError = this.OnError;
task.Execute();
}
}
And you need to create your ViewModel once. So I suggest you to create your ViewModel in constructor of your View instead of button-click handler.
public class MainView
{
public MainView()
{
InitializeComponent();
this.ViewModel = new MainViewModel();
}
public MainViewModel ViewModel
{
get { return this.DataContext as MainViewModel; }
set { this.DataContext = value; }
}
private void TeadIdText_TextChanged(object sender, TextChangedEventArgs e)
{
this.ViewModel.TeamID = TeamIdtxt.Text;
}
private void Btn_Ok_Click(object sender, RoutedEventArgs e)
{
this.ViewModel.GetPlayer();
}
}
Related
I have two windows. In the first window I would like to start the second window with some preference values (e. g. "MaxWords"). The second window holds a class with an interface for INotifyPropertyChanged. This works as expected...
public partial class PreviewPreferences : Window
{
public PreviewPreferences()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel
{
public Preferences preferences { get; private set; }
public ViewModel()
{
preferences = new Preferences();
}
}
public class Preferences : INotifyPropertyChanged
{
private int _maxWords = 10;
/// <summary>
/// Default constructor
/// </summary>
public Preferences() { }
/// <summary>
/// Max words
/// </summary>
public int MaxWords
{
get { return this._maxWords; }
set { this._maxWords = value; this.OnPropertyChanged("MaxWords"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
The second window should updating the first window and adds some user controls to the grid. The question is not how to add the controls... it is more how to raise the event from the preference class that the value MaxWords is changed?
private void button_preview_preferences_Click(object sender, RoutedEventArgs e)
{
PreviewPreferences previewPreferences = new PreviewPreferences();
previewPreferences.Show();
Preferences preferences = new Preferences();
preferences.PropertyChanged += HandleChangedPreferences;
}
private void HandleChangedPreferences(object sender, PropertyChangedEventArgs e)
{
// this will never be raised
for (int i = 0; i < MaxWords; i++)
{
...
}
}
you have two instance of Preferences in button_preview_preferences_Click method. The first and important one (the one that changes) is hidden in PreviewPreferences DataContext:
private void button_preview_preferences_Click(object sender, RoutedEventArgs e)
{
var previewPreferences = new PreviewPreferences();
var preferences = (previewPreferences.DataContext as ViewModel).preferences;
preferences.PropertyChanged += HandleChangedPreferences;
previewPreferences.Show();
}
I suggest to invert the logic - create preferences outside ViewModel, and create ViewModel outside PreviewPreferences view:
public partial class PreviewPreferences : Window
{
public PreviewPreferences()
{
InitializeComponent();
}
}
public class ViewModel
{
public Preferences preferences { get; private set; }
public ViewModel(Preferences p)
{
preferences = p;
}
}
private void button_preview_preferences_Click(object sender, RoutedEventArgs e)
{
var preferences = new Preferences();
preferences.PropertyChanged += HandleChangedPreferences;
var previewPreferences = new PreviewPreferences();
previewPreferences.DataContext = new ViewModel(preferences);
previewPreferences.Show();
}
How can the URL data within a list view item be passed to a web browser to open? My current code isn't working for some reason.
The name 'item' does not exist in the current context
page class
public sealed partial class MainPage : Page
{
public List<ListItem> listItemCompanies;
public MainPage()
{
this.InitializeComponent();
listItemCompanies = ItemManager.GetListItems();
}
private async void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
foreach (var item in e.AddedItems)
{
showWebsite();
}
}
private async void showWebsite()
{
var title = item as ListItem;
var uriWeb = new Uri(title.CompanyURL);
var uriSuccess = await Launcher.LaunchUriAsync(uriWeb);
}
}
}
list item class
namespace MyApp.Models
{
public class ListItem
{
public string CompanyTitle { get; set; }
public string CompanyURL { get; set; }
}
public class ItemManager
{
public static List<ListItem> GetListItems()
{
var items = new List<ListItem>
{
new ListItem { CompanyTitle = "Apple", CompanyURL = "www.apple.com" },
new ListItem { CompanyTitle = "Google", CompanyURL = "www.google.com" },
new ListItem { CompanyTitle = "Microsoft", CompanyURL = "www.microsoft.com" }
};
return items;
}
}
}
Based on the document of Uri, there are essentially three components to a URI, the first part is scheme. Taking the web URL as an example, the scheme part is "http://". So when you try to create a Uri class, you also need to pass the "http://" instead of only "www.apple.com". In addition, when the ListView_SelectionChanged event is triggered, you can call the SelectedItem property of ListView to get the model you current click. For example:
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
object item = (sender as ListView).SelectedItem;
showWebsite(item);
}
private async void showWebsite(object item)
{
var title = item as ListItem;
var uriWeb = new Uri("http://" + title.CompanyURL);
var uriSuccess = await Launcher.LaunchUriAsync(uriWeb);
}
Update:
If you want to use ItemClick event, you need to set the IsItemClickEnabled of ListView as True.
.xaml:
<ListView ... IsItemClickEnabled="True" ItemClick="ListView_ItemClick">
......
</ListView>
.cs:
private void ListView_ItemClick(object sender, ItemClickEventArgs e)
{
object item = (sender as ListView).SelectedItem;
showWebsite(item);
}
I have a WPF User control and here is the code, where I initialize the view model and subscribe for the event.
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
this.DataContext = new MyUserControlViewModel();
((MyUserControlViewModel)this.DataContext).MainModel.MessageDataNew.CollectionChanged += NewMessage_CollectionChanged;
}
This is the collection change event and it's not firing :(
private void NewMessage_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (MessageStatus != null)
{
var border = (Border)VisualTreeHelper.GetChild(MessageStatus, 0);
var scrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(border, 0);
scrollViewer.ScrollToBottom();
}
}
This is my view model constructor. I am using GalaSoft.MvvmLight.Messaging
public class MyUserControlViewModel: INotifyPropertyChanged
{
public MyUserControlViewModel()
{
Messenger.Default.Register<string>(this, "SimulatorLogs", AddtoCollection);
}
public MainModel MainModel
{
get { return _mainModel; }
set
{ _mainModel = value;
RaisePropertyChanged(() => MainModel);
}
}
private void AddtoCollection(string measurementData)
{
MainModel.MessageDataNew.Add(measurementData);
}
}
I've added a DialogService in order to open a ProductView, so far the ShowDetailDialog() is working as expected.
Issue:
I call Close() on the ProductView, the view isn't closed. I debugged this issue by setting a break point on the call to the dialog service close method.
When I stepped through the code, the null check shows that productView is null, which prevents Close() from being called.
Does anyone have idea why productView is null? (although it's showing data on the view)
DialogService:(hosts the Show and Close methods)
namespace MongoDBApp.Services
{
class DialogService : IDialogService
{
Window productView = null;
ProductView _productView;
public DialogService()
{
_productView = new ProductView();
}
public void CloseDetailDialog()
{
if (productView != null)
productView.Close();
}
public void ShowDetailDialog()
{
_productView.ShowDialog();
}
}
}
ProductViewModel: (summary of ProductVM, calls the close method on SaveCommand)
private void SaveProduct(object product)
{
_dialogService.CloseDetailDialog();
Messenger.Default.Send<ProductModel>(SelectedProduct);
}
CustomerOrdersViewmodel: (Where the ShowDetailDialog() is called initially)
private void EditOrder(object obj)
{
Messenger.Default.Send<ProductModel>(SelectedProduct);
_dialogService.ShowDetailDialog();
}
This is how I have always closed my windows.
Here would be my command:
class CancelCommand : ICommand
{
private NewTruckViewModel newTruck;
public CancelCommand(NewTruckViewModel vm)
{
newTruck = vm;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
newTruck.Cancel();
}
}
Here is my view Model and the method that gets called from my command:
private NewTruck myWnd; //View Declaration
//Ctor where I set myView (myWnd) equal to a view that is passed in.
public NewTruckViewModel(ObservableCollection<Truck> Trucks, NewTruck wnd, bool inEditTruck)
{
myEngine.stopHeartBeatTimer();
editTruck = inEditTruck;
myWnd = wnd;
SaveTruckCommand = new SaveTruckCommand(this);
CancelCommand = new CancelCommand(this);
ClearCommand = new ClearCommand(this);
SetLevel1MTCommand = new SetLevel1MTCommand(this);
SetLevel2MTCommand = new SetLevel2MTCommand(this);
SetLevel3MTCommand = new SetLevel3MTCommand(this);
SetLevel1FLCommand = new SetLevel1FLCommand(this);
SetLevel2FLCommand = new SetLevel2FLCommand(this);
SetLevel3FLCommand = new SetLevel3FLCommand(this);
myTrucks = Trucks;
}
public void Cancel()
{
myWnd.Close();
}
This works for me.
I resolved the issue by implementing an IDialogService on the View. Then calling the Show() and Close() methods from the ViewModel.
Solution:
Interface:
public interface IDialogService
{
void CloseDialog();
void ShowDialog(EditProductViewModel prodVM);
}
View:
public partial class ProductView : Window, IDialogService
{
public ProductView()
{
InitializeComponent();
this.DataContext = new EditProductViewModel(this);
}
public void CloseDialog()
{
if (this != null)
this.Visibility = Visibility.Collapsed;
}
public void ShowDialog(EditProductViewModel prodVM)
{
this.DataContext = prodVM;
this.Show();
}
private void Window_Closed(object sender, EventArgs e)
{
this.Visibility = Visibility.Collapsed;
}
}
ViewModel #1:
private IDialogService _dialogService;
public CustomerOrdersViewModel(IDialogService dialogservice)
{
this._dialogService = dialogservice;
}
private void EditOrder(object obj)
{
EditProductViewModel pvm = new EditProductViewModel(_dialogService);
pvm.Present(pvm);
Messenger.Default.Send<ProductModel>(SelectedProduct);
}
ViewModel #2:
private IDialogService _dialogService;
public EditProductViewModel(IDialogService dialogService)
{
this._dialogService = dialogService;
}
private void SaveProduct(object product)
{
SelectedProduct = SelectedProductTemp;
_dialogService.CloseDialog();
}
public void Present(EditProductViewModel prodVM)
{
_dialogService.ShowDialog(prodVM);
}
I've been trying to get recomposition to work but no luck... I tried many times and many approches - with no luck... can anyone point out my mistake? I expect that after I drop a new .dll into plugins directory the Senders collection will be automatically repopulated with new stuff...
//exported classes
[Export(typeof(ISender))]
public class SMTP : ISender
{
public string Name
{
get { return "SMTP plugin"; }
}
public void Send(string msg)
{
}
}
[Export(typeof(ISender))]
public class Exchange : ISender
{
public string Name
{
get { return "Exchange plugin"; }
}
public void Send(string msg)
{
// .. blah
}
}
/---------------------------------------------------------------------
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private const string STR_Pugins = ".\\plugins";
[ImportMany(typeof(ISender), AllowRecomposition = true)]
private List<ISender> Senders;
private DirectoryCatalog d;
CompositionContainer c;
public MainWindow()
{
InitializeComponent();
listBox1.DisplayMemberPath = "Name";
ConfigPlugins();
bindSenders();
}
private void ConfigPlugins()
{
DirectoryInfo dir = new DirectoryInfo(STR_Pugins);
if (!dir.Exists)
dir.Create();
d = new DirectoryCatalog(STR_Pugins);
d.Changed += new EventHandler<ComposablePartCatalogChangeEventArgs>(d_Changed);
c = new CompositionContainer(d);
c.ExportsChanged += new EventHandler<ExportsChangeEventArgs>(c_ExportsChanged);
c.ComposeParts(this);
}
void d_Changed(object sender, ComposablePartCatalogChangeEventArgs e)
{
bindSenders();
MessageBox.Show("d_Changed " + (Senders == null ? 0 : Senders.Count));
}
private void bindSenders()
{
listBox1.ItemsSource = Senders;
}
void c_ExportsChanged(object sender, ExportsChangeEventArgs e)
{
bindSenders();
MessageBox.Show("c_ExportsChanged "+ (Senders == null ? 0 : Senders.Count));
}
}
AFTER RESPONSE
ok, I've added the refresh, but still I don't get why the listbox won't populate with the new data...
public partial class MainWindow : Window
{
private const string STR_Pugins = ".\\plugins";
[ImportMany(typeof(ISender), AllowRecomposition = true)]
private List<ISender> Senders;
DirectoryCatalog d;
CompositionContainer c;
public MainWindow()
{
InitializeComponent();
listBox1.DisplayMemberPath = "Name";
ConfigPlugins();
bindSenders();
}
private void ConfigPlugins()
{
DirectoryInfo dir = new DirectoryInfo(STR_Pugins);
if (!dir.Exists)
dir.Create();
d = new DirectoryCatalog(STR_Pugins);
c = new CompositionContainer(d);
c.ComposeParts(this);
}
private void bindSenders()
{
label1.DataContext = Senders;
listBox1.ItemsSource = Senders;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
d.Refresh();
bindSenders();
}
}
You have to call Refresh yourself. If you want you can use a FileSystemWatcher object to get notified when the directory contents have changed.
It won't repopulate because when the field is updated, a brand new List is set to the field. The existing collection is not modified. You have to set it up as a property instead of a field (you can still make it protected or private), then when the "set" is called, you update the listBox1.ItemsSource and the label1.DataContext.