I'm very new to this, especially WinUI, so please bear with me.
I'm writing an UI app with Visual Studio which communicates with a console program through a JSON file with properties. The UI has two main sections and a setting page. The pages share parts of the properties which will have to be written to the JSON file. I think the NavigationView is perfect for my purpose. In any case, I want to avoid having everything in one window.
This is a new version of a Windows Forms app, which had very few controls and only a main window with menu elements.
Examples:
1. (static properties require a lot of manual assignment)
Page1 (xaml)
<ToggleSwitch x:Name="test" Header="test switch" OffContent="Off" OnContent="On" Toggled="test_Toggled"/>
Page1 code-behind (C#)
[...]
public static MyClass Test { get; set; }
[...]
private void test_Toggled(object sender, RoutedEventArgs e)
{
Test.TestSwitch = test.IsOn;
}
[...]
Page2 code-behind (C#)
using static Namespace.Page1;
[...]
TextBox.Text = Test.TestSwitch.ToString();
[...]
2. (couldn't figure out proper static binding and using non-static properties doesn't work for me)
Page1 (xaml)
<ToggleSwitch x:Name="test" Header="test switch" IsOn="{x:Bind Test.TestSwitch, Mode=TwoWay}" OffContent="Off" OnContent="On"/>
<TextBox x:Name="test2" Text="{x:Bind Test.TestSwitch, Mode=OneWay}"/> <!--works-->
Page1 code-behind (C#)
[...]
public MyClass Test { get; }
[...]
Page2 code-behind (C#)
[...]
Page1 P1 = new();
TextBox.Text = P1.Test.TestSwitch.ToString();
[...]
4. Find more examples including MVVM in this test app.
This is a general question about how to do this the right way. Did anyone share data in this context before?
*** Please excuse my amateur language.
IMHO your MVVM
approach seems wrong, at least if I fully understood your requirements.
In your provided demo application you have 2 classes TestVM
and TestVM2
, but you have 3 independent working properties of TestSwitch
.
TestVM
has a member TestSwitch
, so each instance of TestVM
will have its own stateTestVM2
has a member TestSwitch
, so each instance of TestVM2
will have its own stateTestVM2
has a static instance, with its own stateI would suggest offloading all "shared" members into a seperate class eg. TestVMShared
and use a static instance of this class.
So instead of this (code is from the github repository)
public class TestVM : INotifyPropertyChanged
{
private bool testSwitch;
public bool TestSwitch
{
get => testSwitch;
set
{
if (testSwitch != value)
{
testSwitch = value;
OnPropertyChanged(nameof(TestSwitch));
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class TestVM2 : INotifyPropertyChanged
{
//{Binding Source={x:Static local:TestVM.Instance}, Path=TestSwitch}
private bool testSwitch;
public TestVM2() {}
public bool TestSwitch
{
get => testSwitch;
set
{
if (testSwitch != value)
{
testSwitch = value;
OnPropertyChanged(nameof(TestSwitch));
}
}
}
private static readonly TestVM2? _instance;
public static TestVM2 Instance => _instance ?? new TestVM2();
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I would do this:
// note:
// I added this class, but it is irrelevant to the answer it just reduces code
// you should consider looking into using a library offering MVVM goodies
// eg. https://github.com/CommunityToolkit/WindowsCommunityToolkit
public class VMBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class TestVM : VMBase
{
public TestVMShared Shared { get; } = TestVMShared.Instance;
}
public class TestVM2 : VMBase
{
public TestVMShared Shared { get; } = TestVMShared.Instance;
}
public class TestVMShared : VMBase
{
public static TestVMShared Instance { get; } = new();
private bool testSwitch;
public bool TestSwitch
{
get => testSwitch;
set
{
if (testSwitch != value)
{
testSwitch = value;
OnPropertyChanged(nameof(TestSwitch));
}
}
}
}
With this every instance either of TestVM
or TestVM2
will always use the same instance of TestVMShared
, as I am using the static instance.
Edit:
Didn't quite understand, why you only specified an DesignInstance
in Tab_One.xaml
, so I did the following additions