Edit ListBox on MainWindow from a class
I have a WPF application, i created a new class named Agent
. On my WPF application window i have ListBox
. I call Agent
from the MainWIndow.xaml.cs .
Agent class runs a FileSystemWatcher
and now when OnChanged
event is raised i want to add the message to the ListBox
that the event was raised.
MainWindow.xaml
<Window x:Class="MachineLogAgentGUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="411" Width="515">
<Grid Background="#0A000000">
<Button Content="Run Agent" Height="26" HorizontalAlignment="Left" Margin="397,12,0,0" Name="runAgent" VerticalAlignment="Top" Width="86" Click="runAgent_Click" />
<ListBox Margin="12,66,12,12" Name="messageBox" />
<TextBox Height="26" HorizontalAlignment="Left" Margin="12,12,0,0" Name="observedDirectory" VerticalAlignment="Top" Width="261" />
<Button Content="Browse" Height="26" HorizontalAlignment="Left" Margin="271,12,0,0" Name="browse" VerticalAlignment="Top" Width="75" Click="browse_Click" />
<CheckBox Content="Include Subfolders" Height="16" HorizontalAlignment="Left" Margin="12,44,0,0" Name="includeSubfolders" VerticalAlignment="Top" />
</Grid>
In MainWindow.xaml.cs i have:
Agent agent = null;
private void runAgent_Click(object sender, RoutedEventArgs e)
{
if (agent == null || !agent._running)
{
agent = new Agent(@"W:\MindWare.SVN\CardMax2\trunk\ProcessEngine\TSPHelper.Producer\bin\Debug\GeneratedLogs");
runAgent.Content = "Stop Agent";
}
else if (agent._running)
{
agent.StopAgent();
runAgent.Content = "Run Agent";
}
}
And Agent class:
public class Agent
{
private string Path { get; set; }
public bool _running { get; set; }
FileSystemWatcher watcher = new FileSystemWatcher();
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public Agent(string path)
{
Path = path;
watcher.Path = path;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.txt";
watcher.IncludeSubdirectories = true;
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
_running = true;
}
// Stop Agent
public void StopAgent()
{
watcher.EnableRaisingEvents = false;
_running = false;
}
// Define the event handlers.
private void OnChanged(object source, FileSystemEventArgs e)
{
try
{
watcher.EnableRaisingEvents = false;
_running = false;
// DO SOMETHING HERE
// Add item to ListBox on MainWindow somehow
}
finally
开发者_运维问答 {
watcher.EnableRaisingEvents = true;
_running = true;
}
}
How i could do that?
I think I understand what you mean.
You could create a static MainWindow object in the Agent class:
public class Agent
{
public static MainWindow mainWindow;
....
}
Then inside the MainWindow.cs you can add your window to the variable
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Agent.mainWindow = this;
....
}
Now when ever you need to access this you can reference mainWindow:
public class Agent
{
public static MainWindow mainWindow;
public void AddToList(string value)
{
mainWindow.listBox1.items.add(value);
}
Edit: Update for Threading error
Sounds like the FileSystemWatcher runs on a seperate thread to the UI. you can manage this by getting passing the work to the UI thread
// DO SOMETHING HERE
// Add item to ListBox on MainWindow somehow
if (!mainWindow.Dispatcher.CheckAccess())
{
mainWindow.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
//Code to make changes to the mainWindow if the thread does not have access:
mainWindow.listBox1.Items.Add("hello");
}));
}
else
{
//Access allowed make changes normally.
mainWindow.listBox1.Items.Add("hello");
}
Martyn
You probably should not do that since model-classes should be independent from the view.
Other than that why not pass a reference to the constructor of the class or exposing the ListView field as a public or internal property?
To expose your ListBox create a property like this:
public ListBox MessageBox { get { return messageBox; } }
This should be in your MainWindow code behind, then you can access the ListBox on any instance of the window via mainWindow.MessageBox
.
精彩评论