2

I have a MainWindow which contains 2 user controls: Ready and Welcome. I want to show either one of them, depending on an enum value in my view model.

When the application starts, only the Welcome should be visible, but both sections are shown. In debug, I see that the ShowWelcome property value is being called, but never the ShowReady, it's like it's not bound.

I don't understand why the Ready user control is still shown, even if the ShowReady property of the viewmodel is set to false.

MainWindow.xaml:

<Window x:Class="xyz.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:xyz.Views"
        mc:Ignorable="d"
        Title="app" Icon="/Assets/images/wcC.png"
        Height="800" Width="240" ResizeMode="NoResize"
        Loaded="Window_Loaded">
<StackPanel Orientation="Vertical">
    <StackPanel.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
    </StackPanel.Resources>

    <local:Ready x:Name="ucReady" Visibility="{Binding ShowReady, Converter={StaticResource BoolToVisConverter}}" />
    <local:Welcome x:Name="ucWelcome" Visibility="{Binding ShowWelcome, Converter={StaticResource BoolToVisConverter}}" />
</StackPanel>
</Window>

MainWindow.xaml.cs

namespace xyz.Views
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //ServerApiCaller api;
        ConfigModelApp configApp;
        MainWindowVM vm;

        public MainWindow(IOptionsMonitor<ConfigModelApp> configApp, ServerApiCaller api)
        {
            this.configApp = configApp.CurrentValue;

            vm = new MainWindowVM();
            DataContext = vm;

            InitializeComponent();

        }

        void Window_Loaded(object sender, RoutedEventArgs e)
        {
            vm.UpdateWindowContext(this.configApp.UserId);
        }

        internal void UpdateWindowContext(ConfigModelApp newConfig)
        {
            configApp = newConfig;
            vm.UpdateWindowContext(newConfig.UserId);
        }
    }
}

MainWindowVM.cs

namespace xyz.ViewModels
{
    public enum MainWindowContextEnum
    {
        Unknown,
        Welcome,
        Ready,
        Drafting,
        Playing,
    }

    public class MainWindowVM : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public MainWindowContextEnum MainWindowContext { get; set; } = MainWindowContextEnum.Welcome;
        public bool ShowWelcome => MainWindowContext == MainWindowContextEnum.Welcome;
        public bool ShowReady => MainWindowContext == MainWindowContextEnum.Ready;

        public void UpdateWindowContext(string userId)
        {
            MainWindowContext = Guid.TryParse(userId, out Guid g) ? MainWindowContextEnum.Ready : MainWindowContextEnum.Welcome;

            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShowReady)));
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShowWelcome)));
        }
    }
}
Bruno
  • 4,685
  • 7
  • 54
  • 105
  • 1
    Are you setting the `DataContext` somewhere in `Ready`? – mm8 Jul 12 '19 at 14:55
  • You should then see some binding error messages in the Output Window in Visual Studio. – Clemens Jul 12 '19 at 14:56
  • Does `Visibility="{Binding DataContext.ShowReady, RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolToVisConverter}}"` work? – mm8 Jul 12 '19 at 14:56
  • @mm8 yes the Ready UC has a viewmodel and I set it to its DataContext...if I remove the vm assignation from the Ready UC code-behind, everything works...Can you explain because I don't understand :O is setting a datacontext in the user control disrupts its visibility in the main window? – Bruno Jul 12 '19 at 14:59
  • Setting the DataContext of the UserControl explictly means that it no longer will inherit its DataContext from the window where the ShowReady property is defined. – mm8 Jul 12 '19 at 15:00

1 Answers1

2

If Visibility="{Binding DataContext.ShowReady, RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolToVisConverter}}" works, you are explicitly setting the DataContext of Ready.

You shouldn't do this as it means that the UserControl will no longer inherit its DataContext from the window where the ShowReady property is defined. That's why the binding fails.

A UserControl is generally supposed to inherit its DataContext.

mm8
  • 163,881
  • 10
  • 57
  • 88