One issue that can rear it's ugly head is memory leaks. When you tightly couple objects together, it is easy to forget to release unused objects.
A method to overcome this is to use a proxy class to share data. Typically, this is done with DI (Dependency Injection). When not using DI, an alternative is to use a shared class.
public static class SharedDataProxy
{
public static void PostMessage(string message)
{
ReceiveMessage?.Invoke(message);
}
public static Action<string> ReceiveMessage { private get; set; } = null;
}
In this example, I am going to pass a message string from the main window to a side window. I have purposely started each window separately sp neither are linked / tightly coupled.
1. Main Window Xaml (sender):
<Window x:Class="WpfSharingDataAcrossWindows.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Message:" Padding="0 0 10 0"/>
<TextBox x:Name="TextMessage" Width="200"/>
</StackPanel>
<Button Grid.Row="1"
Content="SEND"
HorizontalAlignment="Left"
Margin="0 10"
Padding="20 10"
Click="ButtonBase_OnClick"/>
</Grid>
</Window>
And the code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
SharedDataProxy.PostMessage(TextMessage.Text);
}
}
So when the SEND button is clicked, the
PostMessage
on the
SharedDataProxy
is used to pass the data. The MainWindow is totally oblicious to who will get the data.
2. Side Window Xaml:
<Window x:Class="WpfSharingDataAcrossWindows.SideWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SideWindow" Height="450" Width="800">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Message:" Padding="0 0 10 0"/>
<TextBlock x:Name="TextMessage"/>
</StackPanel>
</Grid>
</Window>
and the code-behind:
public partial class SideWindow : Window
{
public SideWindow()
{
InitializeComponent();
SharedDataProxy.ReceiveMessage = ShowMessage;
}
public void ShowMessage(string message)
{
TextMessage.Text = message;
}
}
Here we register the method to be used to show the message in the constructor to the
ReceiveMessage
of the
SharedDataProxy
class. So this is the listener.
3. Now, for this demo, to launch each window separately when the app starts, we need to modify the App Startup in the
App.xaml
and
App.xaml.cs
files:
App.xaml:
<Application
x:Class="WpfSharingDataAcrossWindows.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" />
We removed the default startup.
App.xaml.cs:
public partial class App : Application
{
private Window _sideWindow;
protected override void OnStartup(StartupEventArgs e)
{
_sideWindow = new SideWindow();
_sideWindow.Show();
App.Current.MainWindow = new MainWindow();
App.Current.MainWindow .Show();
base.OnStartup(e);
}
}
So the
MainWindow
button calls
SharedDataProxy.PostMessage
method, and that method invokes the
ReceiveMessage
delegate method that points to the
SideWindow.ShowMessage
method and the message is displayed.
Where this is useful is for testing code and also, if you need to change what window receives the message, the
MainWindow
is totally unaware.
This technique is not isolated to WPF, it can be used with all application types, like Winforms. Also, will work for both .Net Framework and Dot Net.