I'm new to WPF and have currently set up a 1 window WPF.
Now however I need a new window to share a Dictionary clientData;
When I click the entry in a ListBox in the main window I need to pass the entryId to the new window that can acces the clientData[entryId].
I've always made single window apps in the past so again I'm new to this.
How is this done?
Generally there are two easy possibilities to communicate between two windows.
Possibility 1:
You create public and static variables in both windows like this:
public static int Property1 { get; set; }
Possibility 2:
You create a parameterized method to show your subwindow and return your variables as public like this:
public int Property2 { get; set; }
public void ShowThis(int parameter)//Gets called by your MainWindow
{
this.Property2 = parameter;
this.Show();
}
EDIT
Based to your problem:
Your subwindow:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
public void ShowThis<T>(IEnumerable<T> data)
{
listBox.Items.Clear();
foreach(var item in data)
{
listBox.Items.Add(item);
}
this.Show();
}
}
And your MainWindow would look like this:
public partial class MainWindow : Window
{
Window1 window1;//your subwindow
public MainWindow()
{
InitializeComponent();
window1 = new Window1();
}
private void buttonShow_Click(object sender, RoutedEventArgs e)//button to show subwindow
{
int[] testData = new int[5] { 1, 3, 5, 7, 9 };
window1.ShowThis(testData);
}
}
Related
Im new at OOP and im wondering how i can say in my edit Class, get this textbox from the mainwindow and clear it. I tried this:
public partial class MainWindow : Window
{
Edit edit = new Edit();
public MainWindow()
{
InitializeComponent();
}
private void ClearBtn_Click(object sender, RoutedEventArgs e)
{
//TxtBox.Clear();
edit.Clear();
}
}
Edit class
public class Edit
{
MainWindow main = new MainWindow();
public void Clear()
{
main.TxtBox.Clear();
}
public Edit()
{
}
}
It's unclear to me why you would need to clear the MainWindow's text box from another class, as it's not practical in a real-world situation, but here you go:
public class Edit
{
public void Clear(MainWindow window)
{
window.TxtBox.Clear();
}
}
Another way to do it would be to pass the MainWindow into the Edit class's constructor, because I can see that you are instantiating Edit from the MainWindow class anyways.
public class Edit
{
private MainWindow _window;
public Edit(MainWindow window)
{
_window = window;
}
public void Clear()
{
_window.TxtBox.Clear();
}
}
if you wish to access controls of MainWindow from different classes you could use a similiar code:
MainWindow MWin = (MainWindow)Application.Current.MainWindow;
MWin.TxtBox.Clear();
I have a WPF application and here is the application structure:
Views
MainWindow.xaml, ABC.xaml (all with .cs files)
ViewModels
MainWindowVM.cs, ABCVM.cs
I have a Button in MainWindow.xaml (bound to MainWindowVM.cs) that calls a function, SampleFunction() in MainWindowVM.cs when being clicked and the SampleFunction() then creates a new instance of ABC.xaml (bound to ABCVM.cs) and open a new window of ABC.xaml using Show() function.
How can I make sure that clicking the Button in MainWindow would not open another new window of ABC.xaml when the old window is still there, or not create another new instance of ABC.xaml?
MainWindow.xaml.cs
public partial class MainWindow : Window
{
/*...Some other codes...*/
private MainWindowVM _VM = new MainWindowVM();
public MainWindowVM MainWindowVM
{
get { return _VM; }
set { _VM= value; }
}
public MainWindow()
{
InitializeComponent();
this.DataContext = MainWindowVM;
}
private void SomeControl_MouseLeftButtonUp(object sender,MouseButtonEventArgs e)
{
MainWindowVM.SampleFunction();
}
}
MainWindowVM.cs
public class MainWindowVM
{
/*...Some other codes...*/
public void SampleFunction()
{
ABC abc= new ABC();
abc.Show();
}
}
ABC.xaml.cs
public partial class ABC: Window
{
/*...Some other codes...*/
private static ABCVM _abcVM= new ABCVM();
public ABCVM ABCVM { get { return _abcVM; } set { _abcVM = value; } }
public ABC()
{
InitializeComponent();
this.DataContext = ABCVM;
}
}
Use ShowDialog() instead of Show().
Then you have to close the ABC.xaml first, before you can make something on the MainWindow. So you can't open a second ABC.xaml Window.
You can write code to check whether a window type object exists or not.
for each(Window win in Application.Current.Windows)
{
string windowType = win.GetType().ToString();
if (!windowType.Equals(nameSpace + "." + ABC))
{
ABC abc= new ABC();
abc.Show();
}
}
So this sounds strange but I always get a stackoverflow exception when I execute 'this.Content' 3 times.
So I have a main window which stores all userControls so I dont have to create them always:
public partial class MainWindow : Window
{
CreateSessionWindow csw;
RateSessionWindow rsw;
CloseSessionWindow closesw;
MainMenuWindow mmw;
public MainWindow()
{
InitializeComponent();
csw = new CreateSessionWindow();
rsw = new RateSessionWindow();
closesw = new CloseSessionWindow();
mmw = new MainMenuWindow();
AllSessionWindows.csw = csw;
AllSessionWindows.rsw = rsw;
AllSessionWindows.closesw = closesw;
AllSessionWindows.mmw = mmw;
}
private void bttnStartProgram_Click(object sender, RoutedEventArgs e)
{
this.Content = AllSessionWindows.mmw;
}
}
public static class AllSessionWindows
{
public static RateSessionWindow rsw;
public static CloseSessionWindow closesw;
public static CreateSessionWindow csw;
public static MainMenuWindow mmw;
}
In my MainMenuWindow class I have a button and when I click on the button it changes the content:
public partial class MainMenuWindow : UserControl
{
public MainMenuWindow()
{
InitializeComponent();
}
private void bttnCreateSession_Click(object sender, RoutedEventArgs e)
{
this.Content = AllSessionWindows.csw; //here
}
}
And here is where I get usually the stackoverflowexception:
public partial class CreateSessionWindow : UserControl
{
public CreateSessionWindow()
{
InitializeComponent();
}
private void bttnGoBack_Click(object sender, RoutedEventArgs e)
{
this.Content = AllSessionWindows.mmw; //here I always get the exception
}
}
So no matter in which order I call this.Content (for eg. first mmw and than csw or csw and than mmw) I always get a stackoverflow Exception when I call it 3 times which you can see above. What could be the problem be?
The problem in your code is this.Content=... in UserControls (in this case this.Content is UserControl content not Window content). If you want to change content in the main window you should add property with MainWindow to class AllSessionWindows:
public static class AllSessionWindows
{
public static MainWindow MainWindow;
public static RateSessionWindow rsw;
public static CloseSessionWindow closesw;
public static CreateSessionWindow csw;
public static MainMenuWindow mmw;
}
In the MainWidnow constructor you must assign this property:
public MainWindow()
{
InitializeComponent();
...
AllSessionWindows.MainWindow = this;
}
And in UserControl you should use following code:
private void bttnCreateSession_Click(object sender, RoutedEventArgs e)
{
AllSessionWindows.MainWindow.Content = AllSessionWindows.csw;
}
Presented solution to this kind of problem by you is not the best solution. For this kind of problem, you can use Caliburn.Micro framework.
In the following link you can find a good tutorial:
http://www.mindscapehq.com/blog/index.php/2012/1/12/caliburn-micro-part-1-getting-started/
Your problem is described in part 5 and 6 of this tutorial.
Hello I have a simple WPF window and I want to load and display a logo image on specific "Image" item. The following code works perfectly and I can display the logo.
namespace WPFexample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var uri = new Uri("pack://application:,,,/Assets/Logo.png");
LogoImage.Source = new BitmapImage(uri);
}
}
}
Now I want to create another class which can access the GUI and display from there the logo:
namespace WPFexample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
class MyClass
{
private void myCustomDisplay()
{
var uri = new Uri("pack://application:,,,/Assets/Logo.png");
// How can I call the LogoImage.Source from this place??
}
}
}
Initially I thought that I could do this but nothing happened:
class MyClass
{
private void myCustomDisplay()
{
MainWindow MainWindowClassRef = new MainWindow();
var uri = new Uri("pack://application:,,,/Assets/Logo.png");
MainWindowClassRef.LogoImage.Source = new BitmapImage(uri);
}
}
Any suggestion why I cannot display it?
This does not work either:
namespace WPFexample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void DisplayInGUI()
{
var uri = new Uri("pack://application:,,,/Assets/ITLLogo.png");
LogoImage.Source = new BitmapImage(uri);
}
}
class MyClass:MainWindow
{
public void myCustomDisplay()
{
DisplayInGUI()
}
}
}
To access a member (e.g. property or method) of the MainWindow instance, you can cast the MainWindow property of the current Application instance to your MainWindow class.
So e.g. call the MainWindow's DisplayInGUI() method by
((MainWindow)Application.Current.MainWindow).DisplayInGUI();
You probably want to pass the actual logo image as parameter to a method like
public partial class MainWindow : Window
{
...
public void SetLogoImage(ImageSource image)
{
LogoImage.Source = image;
}
}
and call it like this:
((MainWindow)Application.Current.MainWindow).SetLogoImage(
new BitmapImage(new Uri("pack://application:,,,/Assets/ITLLogo.png")));
EDIT: Call the method from another thread like this:
var mainWindow = (MainWindow)Application.Current.MainWindow;
mainWindow.Dispatcher.Invoke(() => mainWindow.DisplayInGUI());
MyClass needs to have a property or field called LogoImage. The "partial" keyword indicates that MainWindow has part of its class definition somewhere else - probably in a class called MainWindow.xaml. I would try looking at that file and moving the relevant portions of it to MyClass.
It might also help for MyClass to derive indirectly from UIElement. If you ask your IDE to create it as a UserControl in a new file, it will probably generate some placeholder xaml for you as well.
I'm writing an application which will be storing film that i watched and I going to watch in future in XML file ( simple app only for training )
The main object which i use to store data in my app look like :
public class FilmDto : IFilmDto
{
public int FilmId { get; set; }
public string Name { get; set; }
public DateTime? WatchedDate { get; set; }
public int ParentId { get; set; }
public string ParentName { get; set; }
public FilmStatus FilmStatus { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
}
All the operation is perform in Service class. There are list of film as main data file.
The service class look this :
public class FilmService
{
private List<FilmDto> _films = new List<FilmDto>();
private FilmDao _filmDao = new FilmDao();
private FilmService()
{
_films = _filmDao.Load();
}
public static FilmService Inicialize()
{
return new FilmService();
}
public void Save()
{
_filmDao.Save(_films);
}
public List<FilmDto> GetFilmsByCriteria(FilmCriteriaDto criteria, bool withStatus)
{
if (withStatus)
{
return _films.Where(x => x.Category.Contains(criteria.Category)
&& x.SubCategory.Contains(criteria.SubCategory)
&& x.ParentName.Contains(criteria.ParentName)
&& x.Name.Contains(criteria.Name)
&& x.FilmStatus.Equals(criteria.FilmStatus)).ToList();
}
else
{
return _films.Where(x => x.Category.Contains(criteria.Category)
&& x.SubCategory.Contains(criteria.SubCategory)
&& x.ParentName.Contains(criteria.ParentName)
&& x.Name.Contains(criteria.Name)).ToList();
}
}
public StatisticDto GetFilmStatistic()
{
return new StatisticDto
{
TotalCount = _films.Count,
TotalToWatch = _films.Where(x => x.FilmStatus == FilmStatus.DoObejzenia).Count(),
TotalWatched = _films.Where(x => x.FilmStatus == FilmStatus.Obejzany).Count()
};
}
public List<string> GetAllParentName()
{
return _films.Select(x => x.ParentName).ToList();
}
public void Add(FilmDto film)
{
_films.add(film);
}
// Private Methods
private int GetNexID()
{
return _films.OrderByDescending(x => x.FilmId).FirstOrDefault().FilmId + 1;
}
}
Now its time to form which i use to resent data. The form use service instance and call method form service to get those data ( form have only display data and do not have any logic to transform it )
public partial class Form1 : Form
{
private FilmService _filmService
public Form1()
{
_filmService = FilmService.Inicialize();
InitializeComponent();
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
FillTable(new FilmCriteriaDto(), false);
}
private void FillTable(FilmCriteriaDto criteria,bool witchStatus)
{
List<FilmDto> films = _filmService.GetFilmsByCriteria(criteria,witchStatus);
foreach (FilmDto film in films)
{
dataGridView1.Rows.Add(film.Name,film.WatchedDate,film.ParentName,film.Category,film.SubCategory,film.FilmStatus);
}
}
private void statisticToolStripMenuItem_Click(object sender, EventArgs e)
{
StatisticDto stats = _filmService.GetFilmStatistic();
MessageBox.Show(string.Format("Total :{0}\nWatched {1}\nTo watch {2}"
, stats.TotalCount, stats.TotalWatched, stats.TotalToWatch), "Stats INFO",MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void addToolStripMenuItem_Click(object sender, EventArgs e)
{
...Call new form to add new film
}
}
To this moment everything is quite nice. But now i need to create new form ( Form2) which will have TexBox to insert new film data to my list in service. No i don't know ho to do this.
First i thought that i change private FilmService _filmService to public FilmService FilmService {get;set;}
And in form2 create constructor where I give Form1 object like public Form2(Form1 form) and make call it form Form1 like : Form2 form = new Form2(this) . In that case i have access to that service method but it will look like form.FilmService.Add which is not nice. In other way i can pass FilmService object as parameter but in that way Form1 will don't know change which Form2 make. I want to create method in Form2 which will be returning FilmDto object to Form1 when e.g i click buton in Form2 is there any way to do that ?
You can use different ways to do this.
The simplest is to use Dialogs. You can open your Form2 as fialog by call ShowDialog and then just read the property if result is OK. It's a general way to implement your behavior in WinForms.
private void addToolStripMenuItem_Click(object sender, EventArgs e)
{
// Show testDialog as a modal dialog and determine if DialogResult = OK.
if (form2.ShowDialog(this) == DialogResult.OK)
{
// Read the contents of testDialog's TextBox.
this.txtResult.Text = form2.TextBox1.Text;
}
}
Note that you must set DialogResult property in Form2 to DialogResult.OK if user click the button and DialogResult.Cancel in other way. It helps you to handle scenario when user has decided not to add new movie.
The other way is to use events. Declare new event in Form2 and subscribe Form1 to this event. Raise new event on button click and pass your data as a parameter of your event.
First of all you can make FilmService static or singleton.
Also you can find some examplex for your particular task here - Communicate between two windows forms in C#
In my Point of View, you should use MVP pattern - https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter
But probably it is overkill.