Search code examples
c#mvvmdatacontext

Setting a binding for a second window


I have two WPF windows and i want to set the context to a ViewModel but if I write:

this.DataContext = new myViewModel() 

in my second windows cs it doesn't work here is my code. i have tried to place a binding in the XAML and to connect the context but when i try to debug it all i get the error code this breakpoint will not get run.

BrowseDialog.xaml

 <Window x:Class="TextalkApi.BrowseDialog"
        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:TextalkApi"
        mc:Ignorable="d"
        Title="BrowseDialog" Height="248.361" Width="427.459">
    <Grid>
        <Button Content="Browse" HorizontalAlignment="Left" Margin="267,11,0,0" VerticalAlignment="Top" Width="75"/>
        <TextBox x:Name="FileDialog" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="{Binding webUrl}" VerticalAlignment="Top" Width="244"/>
        <Button Content="Save" HorizontalAlignment="Left" Margin="267,166,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SaveCommand}" />
        <TextBox HorizontalAlignment="Left" Height="23" Margin="10,38,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
        <Label Content="{Binding errorMessage}" HorizontalAlignment="Left" Margin="10,167,0,0" VerticalAlignment="Top" RenderTransformOrigin="-5.611,10.822" Width="207" Height="19"/> 
    </Grid>
</Window>

BrowseViewModel

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
using System.Threading;
using System.Threading.Tasks;
using System.Configuration;
using System.Collections.Specialized;
using System.IO;

namespace Data
{
    public class BrowseViewModel : BaseViewModel
    {
        #region public variables
        public string webUrl { get; set; }
        public string errorMessage { get; set; }
        #endregion

        #region Public Commands
        public ICommand SaveCommand { get; set; }
        #endregion

        #region Constructor
        public BrowseViewModel()
        {
            this.SaveCommand = new RelayCommand(SaveFilePath);
        }
        #endregion

        #region Private methods
        private void SaveFilePath()
        {
            if (File.Exists(webUrl))
            {
                ConfigurationManager.AppSettings.Add("WebUrl", webUrl);
            }
            else
            {
                errorMessage = "Filen existerar ej"; 
            }
        }
        #endregion
    }
}

BrowseDialog.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;
using Data;

namespace TextalkApi
{
    /// <summary>
    /// Interaction logic for BrowseDialog.xaml
    /// </summary>
    public partial class BrowseDialog : Window
    {
        public BrowseDialog()
        {
            InitializeComponent();
            this.DataContext = new BrowseViewModel();
        }
    }
}

BaseViewModel

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using PropertyChanged;

namespace Data
{
    [AddINotifyPropertyChangedInterface]

    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

Solution

  • Your XAML looks correct and I highly suspect it is the ViewModel causing it not to work. Something like this should work.

    Please note that this will depend a lot on how the BaseViewModel has been implemented. If possible can you share this so I can update my answer to be correct? The below is how you should implement the properties in your ViewModel which is the DataContext of the View.

    #region Properties
        private string _webUrl;
        public string WebUrl 
        { 
            get => _webUrl;     
            set 
            {
                //This will change based on how you have implemented your BaseViewModel!
                //The method name might be different, or have different parameters!
                this.SetProperty(ref _webUrl, value, nameof(WebUrl));
                //Call the save file path validation method...
                SaveFilePath();
            }
        }
    
        private string _errorMessage;
        public string ErrorMessage 
        { 
            get => _errorMessage;           
            private set 
            {
                //This will change based on how you have implemented your BaseViewModel!
                //This method should call NotifyPropertyChange to notify the UI to update...
                this.SetProperty(ref _errorMessage, value, nameof(ErrorMessage));
            }
        }
    #endregion
    

    In your ViewModelBase you can add a generic SetProperty method that can then handle raising the property changed event for you. Something like this:

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        public void SetProperty<T>(ref T storage, T value, string propertyName)
        {
            storage = value;
            RaisePropertyChangedEvent(propertyName);
        }
    
        protected void RaisePropertyChangedEvent(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    and because of the changes in the ViewModel you will also need to update the bindings in your XAML.

    <Grid>
        <Button Content="Browse" HorizontalAlignment="Left" Margin="267,11,0,0" VerticalAlignment="Top" Width="75"/>
        <TextBox x:Name="FileDialog" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" Text="{Binding WebUrl}" VerticalAlignment="Top" Width="244"/>
        <Button Content="Save" HorizontalAlignment="Left" Margin="267,166,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SaveCommand}" />
        <TextBox HorizontalAlignment="Left" Height="23" Margin="10,38,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
        <Label Content="{Binding ErrorMessage}" HorizontalAlignment="Left" Margin="10,155,0,0" VerticalAlignment="Top" RenderTransformOrigin="-5.611,10.822" Width="207" Height="46"/>
    </Grid>