Cenarius
Cenarius

Reputation: 225

Binding User Control from second lib project not work - wpf mvvm

My task: I want to bind textbox and button.

Although I found many topics about it I cannot manage my problem. I have project: Client with WPF application WITH DEFAULT XAML no BINDING, which takes context from MenuWindow project, which is library. Inside MenuWindow project I have User Control WPF called: MenuProgram.

<UserControl x:Class="MenuWindow.MenuProgram"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:MenuWindow"
         mc:Ignorable="d" 
         d:DesignHeight="550" d:DesignWidth="780">
<UserControl.DataContext>
    <local:MenuViewModel/>
</UserControl.DataContext>
<Grid Background="#FF6F6FA4">
    <Label x:Name="lblTitle" Content="GUI Export Revit Data" HorizontalAlignment="Left" Margin="277,31,0,0" VerticalAlignment="Top" Height="50" Width="258" FontSize="24" FontWeight="Bold"/>
    <Label x:Name="lblPrtdPath" Content="File prtd path" HorizontalAlignment="Left" Margin="200,176,0,0" VerticalAlignment="Top"/>
    <Label x:Name="lblXmlPath1" Content="File xml path1" HorizontalAlignment="Left" Margin="200,222,0,0" VerticalAlignment="Top"/>
    <Label x:Name="lblXmlPath2" Content="File xml path2" HorizontalAlignment="Left" Margin="200,266,0,0" VerticalAlignment="Top"/>
    <TextBox x:Name="tbxPrtd" HorizontalAlignment="Left" Height="23" Margin="302,176,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="268" Text="{Binding PrtdFilePath}"/>
    <TextBox x:Name="tbxXml1" HorizontalAlignment="Left" Height="23" Margin="302,222,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="268" Text="{Binding XmlFilePath1}"/>
    <TextBox x:Name="tbxXml2" HorizontalAlignment="Left" Height="23" Margin="302,266,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="268" Text="{Binding XmlFilePath2}"/>
    <Button x:Name="SayHi" Content="Start" HorizontalAlignment="Left" Margin="302,450,0,0" VerticalAlignment="Top" Width="174" Height="84" FontSize="22" Command="{Binding SayHi}" />
    <Button x:Name="btnAbout" Content="About" HorizontalAlignment="Left" Margin="705,496,0,0" VerticalAlignment="Top" Width="55" Height="38" Command="{Binding SayHi}"/>
</Grid>

so I have

<UserControl.DataContext>
<mv:MenuViewModel/>
</UserControl.DataContext>

and with textBoxs or button I want to use binding.

in codeBehind this User Control there is nothing but default initialization. In Project Menu there are: MenuArguments.cs with mapping:

public string PrtdFilePath { get; set; }
public string XmlFilePath1 { get; set; }
public string XmlFilePath2 { get; set; }

RelayCommand:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace MenuWindow
{
public class RelayCommand : ICommand
{
    private readonly Func<Boolean> _canExecute;
    private readonly Action _execute;

    public RelayCommand(Action execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action execute, Func<Boolean> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute;
        _canExecute = canExecute;
    }

    public event EventHandler CanExecuteChanged
    {
        add
        {
            if (_canExecute != null)
                CommandManager.RequerySuggested += value;
        }
        remove
        {
            if (_canExecute != null)
                CommandManager.RequerySuggested -= value;
        }
    }

    public Boolean CanExecute(Object parameter)
    {
        return _canExecute == null ? true : _canExecute();
    }

    public void Execute(Object parameter)
    {
        _execute();
    }
}
}

and MenuViewModel.cs

namespace MenuWindow
{
public class MenuViewModel : INotifyPropertyChanged
{
    public string gowno;
    public MenuArguments _menuArgumenty;
    public string PrtdFilePath
    {
        get { return _menuArgumenty.PrtdFilePath; }
        set
        {
            _menuArgumenty.PrtdFilePath = value;
            OnPropertyChanged("PrtdFilePath");
        }
    }
    public string XmlFilePath1
    {
        get { return _menuArgumenty.XmlFilePath1; }
        set
        {
            _menuArgumenty.XmlFilePath1 = value;
            OnPropertyChanged("XmlFilePath1");
        }
    }
    public string XmlFilePath2
    {
        get { return _menuArgumenty.XmlFilePath2; }
        set
        {
            _menuArgumenty.XmlFilePath2 = value;
            OnPropertyChanged("XmlFilePath2");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public MenuViewModel()
    {
        _menuArgumenty = new MenuArguments();
    }
    public ICommand SayHi
    {
        get
        {
            return new RelayCommand(SayHiExcute, CanSayHiExcute);
        }
    }

    private void SayHiExcute()
    {
        if (!MenuArgumentsExists(_menuArgumenty))
        {
            MessageBox.Show(string.Format("Hi {0} {1}!", _menuArgumenty.PrtdFilePath, _menuArgumenty.XmlFilePath1));
            SavePerosn(_menuArgumenty);
        }
        else
        {
            MessageBox.Show(string.Format("Hey {0} {1}, you exists in our database!", _menuArgumenty.PrtdFilePath, _menuArgumenty.XmlFilePath1));
        }
    }

    private void SavePerosn(MenuArguments _menuArgumenty)
    {
        //Some Database Logic
    }

    private bool CanSayHiExcute()
    {
        return !MenuArgumentsExists(_menuArgumenty);
    }

    private bool MenuArgumentsExists(MenuArguments _menuArgumenty)
    {
        //Some logic
        return false;
    }

}
}

When I start program debuger goes through binding properties. After window appears there is no reaction from binding. What do I do wrong? Please help me.

BR, student Cenarius

Thanks for comments, answers to your comments:

@tabby - I want to bind textBoxes: PrtdFilePath, XmlFilePath1, XmlFilePath1 and button SayHi

@maulik kansara - You are right, I was trying some another methods and I didnt remove code. It should be only version with local.

@grek40 - My example works for one-project in solution for Window not for UserControl which is set in another project. Here is picture: enter image description here

@mm8 - I expected by puting data ino textBoxes or clicking button to see breakpoint in:

        public string PrtdFilePath
    {
        get { return _menuArgumenty.PrtdFilePath; }
        set
        {
            _menuArgumenty.PrtdFilePath = value;
            OnPropertyChanged("PrtdFilePath");
        }
    }

Finally, I think that code in XAML is problem. I was reading about parent-child relations with finding binding/viewmodel/path but I am confused and I dont know how to solve it. Please help me thanks You for all comments.

@grek40 here is Code in Main APP WPF, I add context from my MenuWindow. This MainWindow WPF APP has default XAML.

public MainWindow()
    {
        InitializeComponent();
        menuProgram = new MenuProgram();//User Control
        sw = new SharedWindow();//WPF window
        this.Close();
        sw.Content = menuProgram.Content;// here I set context
        sw.ShowDialog();
    }

and XAML:

<Window x:Class="Client.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:Client"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>

</Grid>
</Window>

Whole code with Your change:

    public partial class MainWindow : Window
{
    private SharedWindow sw;
    private MenuProgram menuProgram;

    public MainWindow()
    {
        InitializeComponent();
        menuProgram = new MenuProgram();
        SetForContext();
    }
    private void SetForContext()
    {
        sw = new SharedWindow();
        this.Close();
        sw.Content = menuProgram;
        sw.ShowDialog();
    }

Upvotes: 0

Views: 649

Answers (1)

grek40
grek40

Reputation: 13438

You need to set the UserControl as window Content, not the Content of UserControl:

sw.Content = menuProgram;// here I set context
/* Bad: sw.Content = menuProgram.Content; */

Your DataContext is assigned to the UserControl itself, so if you move the Content tree to a different Parent, it will no longer have its old DataContext.

Upvotes: 1

Related Questions