Defining eventhandlers outside MainWindow? - wpf

I am trying to define some event handlers inside auser class but im not sure how. The MainWindow needs the handler definitions.
public abstract partial class MainWindow: Window {
public User user = new User();
}
public class User {
internal void ExampleMouseEventDown(object sender, MouseEventArgs e) {
// Does stuff;
}
}
Isnt there a way to somehow make this work? Such as:
mainWindow.AddHandleDefinition += ExampleMouseEventDown();
Also tried this:
public partial class MainWindow : Window {
public MainWindow() {
User user = new User(this);
}
}
public class User
{
internal User(MainWindow w)
{
w.AddObserverButton.MouseUp += ExampleMouseEventDown;
}
internal void ExampleMouseEventDown(object sender, MouseEventArgs e)
{
// Does stuff;
}
}

Related

User control and event for Padding changed

Im working on gauge control.
I need to redraw everything inside when Size or Padding property is changed.
This is how I deal with Size property changes:
public RoundGauge()
{
this.SizeChanged += delegate
{
ReDrawEverything();
};
InitializeComponent();
}
But there is no PaddingChanged event. What can I do with this?
There is no indeed no "PaddingChanged" event but you could use a DependencyPropertyDescriptor to subscribe to changes to a dependency property:
public partial class RoundGauge : UserControl
{
public RoundGauge()
{
InitializeComponent();
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(PaddingProperty, typeof(UserControl));
if (dpd != null)
dpd.AddValueChanged(this, OnPaddingChanged);
}
private void OnPaddingChanged(object sender, EventArgs e)
{
MessageBox.Show("Padding changed!");
}
}
Please refer to the following blog post for more information.
Handling changes to dependency properties in the view: https://blog.magnusmontin.net/2014/03/31/handling-changes-to-dependency-properties/
You can override OnPropertyChanged event:
public partial class RoundGauge : Control
{
public RoundGauge()
{
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (e.Property == PaddingProperty)
{
Thickness oldPadding = (Thickness)e.OldValue;
Thickness newPadding = (Thickness)e.NewValue;
// ...
}
}
}

Update viewmodel based on MainWindow event

I have a UdpClient, firing off a DataRecevied event on my MainWindow:
public partial class MainWindow : Window
{
public static YakUdpClient ClientConnection = new YakUdpClient();
public ClientData;
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
ClientData = new ClientData();
ClientConnection.OnDataReceived += ClientConnectionOnDataReceived;
}
private void ClientConnectionOnDataReceived(object sender, MessageEventArgs messageEventArgs)
{
ClientData.Users = messageEvenArgs.ConnectedUsers;
}
}
My ClientData and User classes look as follow:
public class ClientData
{
public List<User> Users {get;set;)
}
public class User
{
public string Name {get;set;}
}
On my MainWindow, I have a UserControl called UserListView which has a ViewModel called UserListViewModel
The ViewModel looks as follow:
public class UserListViewModel: BindableBase
{
public UserListViewModel()
{
//I am sure there are better ways of doing this :(
Users = new ObservableCollection<User>((MainWindow)Application.Current.MainWindow).ClientData.Users
});
private ObservableCollection<User> _users;
public ObservableCollection<User> Users
{
get{ return _users;}
set { this.SetProperty(ref this._users, value); }
}
}
The difficulty I have here, is when the ClientConnectionOnDataReceived event on the MainWindow gets fired, I would like to update my ClientData class, My Viewmodel should then somehow be notified that the list changed, and subsequently update my UI.
Can anyone give me a solid example of how to achieve this using MVVM (Prism) in WPF?
I am new to MVVM, so i am still trying to figure this out.
First of all, there's no obvious reason why the main window should do the subscription.
I'd go for something like this:
create a service that encapsulates the subscription (and subscribes in its constructor)
register that as a singleton
have it implement INotifyPropertyChanged (to notify consumers of a change to Users)
inject the service into UserListViewModel and observe the Users property (see PropertyObserver)
when Users in the service changes, update Users in the user list view model
and best of all, no need for ObservableCollection here :-)
EDIT: example:
interface IUserService : INotifyPropertyChanged
{
IReadOnlyCollection<User> Users
{
get;
}
}
class YakUdpService : BindableBase, IUserService
{
private readonly YakUdpClient _yakUdpClient;
private IReadOnlyCollection<User> _users;
public YakUdpService()
{
_yakUdpClient = new YakUdpClient();
_yakUdpClient.OnDataReceived += ( s, e ) => Users = e.ConnectedUsers;
}
public IReadOnlyCollection<User> Users
{
get
{
return _users;
}
private set
{
SetProperty( ref _users, value );
}
}
}
class UserListViewModel : BindableBase
{
private IReadOnlyCollection<UserViewModel> _users;
private readonly IUserService _userService;
private readonly PropertyObserver<IUserService> _userServiceObserver;
public UserListViewModel( IUserService userService )
{
_userService = userService;
_userServiceObserver = new PropertyObserver<IUserService>( userService );
_userServiceObserver.RegisterHandler( x => x.Users, () => Users = _userService.Users.Select( x => new UserViewModel( x ) ).ToList() );
// ^^^ should use factory in real code
}
public IReadOnlyCollection<UserViewModel> Users
{
get
{
return _users;
}
private set
{
SetProperty( ref _users, value );
}
}
}
and then register the service
Container.RegisterType<IUserService, YakUdpService>( new ContainerControlledLifetimeManager() );
in your bootstrapper or your module's initialization.

Interaction between forms

I am using visual studio 2012 (windows form application) and I have two forms, one with a label and the other with a button. I want it so that when you click the button the label on the other form goes up by one. I already have:
Label1 = Label1 + 1
I just need to know how to make the connection with the two forms. Maybe call a function?
Btw I am new to the program and script so in simple terms plz.
Here is a sample I create for you. Add Fomr2 Like this:
public partial class Form2 : Form
{
private void button1_Click(object sender, EventArgs e)
{
Form1.Instance.Controls.Find("label1", true).First().Text = "Some thing";
}
}
And Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
_Instance = this;
}
private static Form1 _Instance;
public static Form1 Instance
{
get { return _Instance; }
set { Instance = value; }
}
private void button1_Click(object sender, EventArgs e)
{
new Form2().Show();
}

Cannot implicitly convert type 'MouseEventHandler' to 'RoutedEventHandler

I tried to inherit method button1_click and I got the message above, how to fix that ?
namespace visualinheritance
{
public partial class usercontrolcommon : UserControl
{
public usercontrolcommon()
{
InitializeComponent();
}
public void button1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("usercontrolcommon");
}
}
}
namespace visualinheritance
{
public partial class usercontrol1 : usercontrolcommon
{
public usercontrol1()
{
InitializeComponent();
this.button1.Click += new MouseEventHandler(button1_Click);
}
}
}
The button click event is not a mouse event. Just change the handler to button1.Click += button1_Click; and it will work

Silverlight child windows in MVVM pattern

I am trying to find the right way to get the data from a ChildWindow/popup using a MVVM pattern in Silverlight (3). For example: I have a main page with a data entry form and I want to open a popup with a list of customers. When user selects a customer I want to transfer selected customer into the main page. This is what the (example) code which I am using at the moment:
Main page
public partial class MainPage : UserControl
{
public MainPageViewModel ViewModel { get; private set; }
public MainPage()
{
InitializeComponent();
ViewModel = new MainPageViewModel();
DataContext = ViewModel;
}
private void SearchCustomer_Click(object sender, RoutedEventArgs e)
{
ViewModel.SearchCustomer();
}
}
public class MainPageViewModel: ViewModel
{
private string customer;
public string Customer
{
get { return customer; }
set { customer = value; RaisePropertyChanged("Customer"); }
}
public void SearchCustomer()
{
// Called from a view
SearchWindow searchWindow = new SearchWindow();
searchWindow.Closed += (sender, e) =>
{
if ((bool)searchWindow.DialogResult)
{
Customer = searchWindow.ViewModel.SelectedCustomer.ToString();
}
};
searchWindow.Show();
}
}
Child window
public partial class SearchWindow : ChildWindow
{
public SearchWindowViewModel ViewModel { get; private set; }
public SearchWindow()
{
InitializeComponent();
ViewModel = new SearchWindowViewModel();
DataContext = ViewModel;
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = ViewModel.OkButtonClick();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = ViewModel.CancelButtonClick();
}
}
public class SearchWindowViewModel: ViewModel
{
private Customer selectedCustomer;
private ObservableCollection<Customer> customers;
public ObservableCollection<Customer> Customers
{
get { return customers; }
set {customers = value; RaisePropertyChanged("Customers"); }
}
public Customer SelectedCustomer
{
get { return selectedCustomer; }
set { selectedCustomer = value; RaisePropertyChanged("SelectedCustomer"); }
}
public SearchWindowViewModel()
{
Customers = new ObservableCollection<Customer>();
ISearchService searchService = new FakeSearchService();
foreach (Customer customer in searchService.FindCustomers("dummy"))
Customers.Add(customer);
}
public bool? OkButtonClick()
{
if (SelectedCustomer != null)
return true;
else
return null; // show some error message before that
}
public bool? CancelButtonClick()
{
return false;
}
}
Is this the right way or is there anything more "simple"?
Cheers,
Rok
More problematic here is the use of View specific terms and types in your VMs. Click events, DialogResults should not be anywhere near your ViewModels.
With regards to the question, I had a similiar question about this here:
Handling Dialogs in WPF with MVVM
The answer I accepted was the use of the Mediator pattern to get around this. Have a look. :)
A good MVVM library which supports opening child window is Chinch mvvm helper library. You can look at a sample at http://www.codeproject.com/KB/silverlight/SL4FileUploadAnd_SL4_MVVM.aspx.

Resources